Fixed stupid rtags issue

This commit is contained in:
Pedro Pinto committed 2018-07-03 13:31:36 -04:00
1 parent 0beccf99e9
commit aedfd79e02
225 files changed
+3 -41944

No files matched your search

+3 -3
View File
@@ -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
BIN
View File
Binary file not shown.
-15
View File
@@ -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)))
-36
View File
@@ -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
-106
View File
@@ -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)
-14
View File
@@ -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 <http://www.gnu.org/licenses/>.
-1220
View File
File diff suppressed because it is too large. Load diff
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
[ -z "$RTAGS_DISABLED" ] && [ -x "$(which rc)" ] && rc --silent --compile "$@" &
[ "$RTAGS_RMAKE" ] && exit 1
compiler="$1"
shift
$compiler "$@"
exit $?
-8
View File
@@ -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
-85
View File
@@ -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?
-8
View File
@@ -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 $?
-19
View File
@@ -1,19 +0,0 @@
{
1
Memcheck:Cond
fun:_ZNK5clang4Expr21refersToVectorElementEv
obj:*
}
{
2
Memcheck:Cond
fun:_ZNK5clang4Expr21refersToVectorElementEv
}
{
3
Memcheck:Cond
fun:_ZNK5clang4Expr17isTemporaryObjectERNS_10ASTContextEPKNS_13CXXRecordDeclE
}
-34
View File
@@ -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()
-23
View File
@@ -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()
-46
View File
@@ -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}" "$<TARGET_FILE_DIR:${EXE_NAME}>"
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)
-28
View File
@@ -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} )
-141
View File
@@ -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 <c.schwarzgruber.cs@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>.
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)
-70
View File
@@ -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}")
-39
View File
@@ -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()
File diff suppressed because it is too large. Load diff
-132
View File
@@ -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}
-386
View File
@@ -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)
-272
View File
@@ -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 <datadir>/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 <arg> 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)
-25
View File
@@ -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}"
-6
View File
@@ -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
-93
View File
@@ -1,93 +0,0 @@
#!/bin/bash -e
# gen-man-pages.sh --- generate man pages
#
# Copyright (c) Christian Schwarzgruber <c.schwarzgruber.cs@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>. */
#
# 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
-38
View File
@@ -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
-292
View File
@@ -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 <fmt>] [--prefix <path>] [--verbose|-v] [--separate|-s]"
echo " [--tree-ish|-t <tree-ish>] [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 <path> 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
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
brew tap homebrew/versions
brew install llvm38 --with-libcxx --with-clang --without-assertions --rtti $@
-69
View File
@@ -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"
-94
View File
@@ -1,94 +0,0 @@
#!/bin/bash -e
# travis.sh --- setup and compile script for travis
#
# Copyright (c) Christian Schwarzgruber <c.schwarzgruber.cs@gmail.com>
# 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 <http://www.gnu.org/licenses/>. */
#
# 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
-49
View File
@@ -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
@@ -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
@@ -1,8 +0,0 @@
[Unit]
Description=RTags daemon socket
[Socket]
ListenStream=%t/rdm.socket
[Install]
WantedBy=default.target
-177
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "AST.h"
#include "ClangThread.h"
#include "selene.h"
#define TO_STR1(x) #x
#define TO_STR(x) TO_STR1(x)
struct UserData {
List<AST::Cursor> parents;
AST *ast;
};
CXChildVisitResult AST::visitor(CXCursor cursor, CXCursor, CXClientData u)
{
UserData *userData = reinterpret_cast<UserData*>(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 <typename T> static void assign(sel::Selector selector, const T &t) { selector = t; }
void assign(sel::Selector selector, const String &str) { selector = str.ref(); }
template <typename T>
static void exposeArray(sel::Selector selector, const std::vector<T> &array)
{
int i = 0;
for (const T &t : array) {
assign(selector[i++], t);
}
}
static void registerClasses(sel::State &state)
{
state["SourceLocation"].SetClass<AST::SourceLocation>("line", &AST::SourceLocation::line,
"column", &AST::SourceLocation::column,
"file", &AST::SourceLocation::file,
"offset", &AST::SourceLocation::offset,
"toString", &AST::SourceLocation::toString);
state["SourceRange"].SetClass<AST::SourceRange>("start", &AST::SourceRange::start,
"end", &AST::SourceRange::end,
"length", &AST::SourceRange::length,
"toString", &AST::SourceRange::toString);
auto cursors = state["Cursors"];
cursors.SetClass<AST::Cursors>("size", &AST::Cursors::size,
"at", &AST::Cursors::at);
auto cursor = state["Cursor"];
cursor.SetClass<AST::Cursor>("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> AST::create(const Source &source, const String &sourceCode, CXTranslationUnit unit)
{
std::shared_ptr<AST> 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::Diagnostic> AST::diagnostics() const
{
return List<Diagnostic>();
}
List<AST::SkippedRange> AST::skippedRanges() const
{
return List<SkippedRange>();
}
List<String> AST::evaluate(const String &script)
{
assert(mReturnValues.isEmpty());
try {
mState->operator()(script.constData());
} catch (...) {
error() << "Got exception";
}
return std::move(mReturnValues);
}
-460
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include <clang-c/Index.h>
#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 <typename T>
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> {
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<Data*> 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; i<count; ++i)
ret[i] = data->ast->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<unsigned(const Cursor&)> 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<unsigned, bool>(&clang_Cursor_isBitField); }
bool isVirtualBase() const { return intProperty<unsigned, bool>(&clang_isVirtualBase); }
bool isStatic() const { return intProperty<unsigned, bool>(&clang_CXXMethod_isStatic); }
bool isVirtual() const { return intProperty<unsigned, bool>(&clang_CXXMethod_isVirtual); }
bool isPureVirtual() const
{
#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20)
return intProperty<unsigned, bool>(&clang_CXXMethod_isPureVirtual);
#else
return false;
#endif
}
bool isConst() const
{
#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 20)
return intProperty<unsigned, bool>(&clang_CXXMethod_isConst);
#else
return false;
#endif
}
bool isDefinition() const { return intProperty<unsigned, bool>(&clang_isCursorDefinition); }
bool isDynamicCall() const { return intProperty<int, bool>(&clang_Cursor_isDynamicCall); }
template <typename Func> std::string stringProperty(Func func) const { return data ? toString(func(data->cursor)) : std::string(); }
template <typename Type, typename Ret = Type> Ret intProperty(Type (*func)(CXCursor), Type defaultValue = Type()) const { return data ? func(data->cursor) : defaultValue; }
template <typename Func> Cursor cursorProperty(Func func) const { return data ? data->ast->create(func(data->cursor)) : Cursor(); }
template <typename Func> CursorType cursorTypeProperty(Func func) const { return data ? CursorType(data->ast, func(data->cursor)) : CursorType(); }
std::shared_ptr<Data> data;
};
struct Cursors : public List<Cursor>
{
int size() const { return List<Cursor>::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<AST> create(const Source &source, const String &sourceCode, CXTranslationUnit unit);
List<String> evaluate(const String &script);
Cursor *root() const { return mRoot; }
List<Diagnostic> diagnostics() const;
List<SkippedRange> 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<AST*>(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<std::string, Cursors> mByUsr;
mutable Map<SourceLocation, Cursors> mByLocation;
String mSourceCode;
List<String> mReturnValues;
Cursor *mRoot;
std::shared_ptr<sel::State> 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<CXCursor> args;
const unsigned size = RTags::cursorArguments(data->cursor, &args);
if (size) {
ret.resize(size);
for (unsigned i=0; i<size; ++i) {
ret[i] = data->ast->create(args[i]);
}
}
}
return ret;
}
#endif
-364
View File
@@ -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 <clang-c/Index.h>
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 <clang-c/Index.h> 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 <regex>
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 ()
File diff suppressed because it is too large. Load diff
-196
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef ClangIndexer_h
#define ClangIndexer_h
#include <sys/stat.h>
#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 <unordered_set>
struct Unit;
class ClangIndexer : public RTags::DiagnosticsProvider
{
public:
ClangIndexer();
~ClangIndexer();
bool exec(const String &data);
static Flags<Server::Option> 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<Symbol::Argument> *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<CXCursor> 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<Message> &msg, const std::shared_ptr<Connection> &conn);
struct Unit {
Map<Location, Symbol> symbols;
Map<Location, Map<String, uint16_t> > targets;
Map<String, Set<Location> > usrs;
Map<String, Set<Location> > symbolNames;
Map<uint32_t, Token> tokens;
};
std::shared_ptr<Unit> &unit(uint32_t fileId)
{
std::shared_ptr<Unit> &unit = mUnits[fileId];
if (!unit) {
unit.reset(new Unit);
}
return unit;
}
std::shared_ptr<Unit> unit(Location loc) { return unit(loc.fileId()); }
enum FindResult {
Found,
NotIndexed,
NotFound
};
Symbol findSymbol(Location location, FindResult *result) const;
struct MacroLocationData {
Set<size_t> arguments;
List<Location> locations;
};
struct MacroData {
List<String> arguments;
Map<String, MacroLocationData> data;
};
Map<Location, MacroData> mMacroTokens;
Hash<uint32_t, std::shared_ptr<Unit> > mUnits;
Path mProject;
SourceList mSources;
Path mSourceFile;
IndexDataMessage mIndexDataMessage;
List<std::shared_ptr<RTags::TranslationUnit> > 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<String> mDebugLocations;
FILE *mLogFile;
std::shared_ptr<Connection> mConnection;
Path mDataDir;
bool mUnionRecursion;
struct Scope {
enum ScopeType {
FunctionDefinition,
FunctionDeclaration,
Other
};
ScopeType type;
Symbol *symbol;
Location start, end;
};
List<Scope> mScopeStack;
struct Loop { // or switch
CXCursorKind kind;
Location start, end;
};
List<Loop> mLoopStack;
std::shared_ptr<RTags::TranslationUnit> mSerializeTU;
List<CXCursor> mParents;
std::unordered_set<CXCursor> mTemplateSpecializations;
size_t mInTemplateFunction;
static Flags<Server::Option> sServerOpts;
static Path sServerSandboxRoot;
};
#endif
-334
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<uint32_t, Map<Location, Location> > references;
};
ClangThread::ClangThread(const std::shared_ptr<QueryMessage> &queryMessage,
const Source &source, const std::shared_ptr<Connection> &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<ClangThread*>(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<Location::ToStringFlag> 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<Connection> &) { abort(); });
String sourceCode = mSource.sourceFile().readAll();
CXUnsavedFile unsaved = {
mSource.sourceFile().constData(),
sourceCode.constData(),
static_cast<unsigned long>(sourceCode.size())
};
std::shared_ptr<RTags::TranslationUnit> 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 = 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<Connection> conn = mConnection;
EventLoop::mainEventLoop()->callLater([conn]() {
if (auto c = conn.lock())
c->finish();
});
}
void ClangThread::writeToConnetion(const String &message)
{
std::weak_ptr<Connection> 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<uint32_t> &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<const Dep*>(pair.second), seen))
return true;
}
return false;
}
static bool validateNeedsInclude(const Dep *source, const Dep *header, Set<uint32_t> &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<const Dep*>(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<uint32_t> seen;
if (!validateNeedsInclude(it.second, static_cast<Dep*>(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<uint32_t> seen;
if (!validateHasInclude(ref.first, it.second, seen)) {
List<String> 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;
}
}
-59
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef ClangThread_h
#define ClangThread_h
#include <clang-c/Index.h>
#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> &queryMessage,
const Source &source,
const std::shared_ptr<Connection> &conn);
~ClangThread() override;
virtual void run() override;
void abort() { std::unique_lock<std::mutex> lock(mMutex); mAborted = false; }
bool isAborted() const { std::unique_lock<std::mutex> 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<QueryMessage> mQueryMessage;
const Source mSource;
std::shared_ptr<Connection> mConnection;
int mIndentLevel;
mutable std::mutex mMutex;
Hash<uint32_t, Dep*> mDependencies;
Hash<Path, String> mContextCache;
bool mAborted;
};
#endif
-80
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "ClassHierarchyJob.h"
#include "Project.h"
#include "RTags.h"
#include "Server.h"
ClassHierarchyJob::ClassHierarchyJob(Location loc,
const std::shared_ptr<QueryMessage> &query,
const std::shared_ptr<Project> &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<Set<Symbol>(const Symbol &)> FindFunc;
std::function<void (const Symbol &, const char *title, int, FindFunc)> 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<Symbol> 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;
}
-32
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef ClassHierarchyJob_h
#define ClassHierarchyJob_h
#include "Location.h"
#include "QueryJob.h"
class ClassHierarchyJob : public QueryJob
{
public:
ClassHierarchyJob(Location loc, const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
const Location location;
};
#endif
-316
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef CommandLineParser_h
#define CommandLineParser_h
namespace CommandLineParser {
enum ValueType {
Required,
Optional,
NoValue
};
template <typename T>
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 <typename T>
ParseStatus parse(int argc, char **argv,
std::initializer_list<Option<T> > optsList,
Flags<Flag> flags,
const std::function<ParseStatus(T, String &&value, size_t &idx, const List<String> &args)> &handler,
const String &app = String(),
std::initializer_list<Option<ConfigOptionType> > configOpts = std::initializer_list<Option<ConfigOptionType> >(),
String *cmdLine = 0)
{
Hash<String, const Option<T> *> longOpts;
Hash<char, const Option<T> *> 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<String> 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<ConfigOptionType>(argc, argv, configOpts,
IgnoreUnknown, [&norc, &rcfile](ConfigOptionType type, String &&value, size_t &, const List<String> &) -> 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; i<argc; ++i)
args.append(argv[i]);
}
}
if (args.isEmpty()) {
args.resize(argc);
for (int i=0; i<argc; ++i) {
args[i] = argv[i];
}
}
if (cmdLine) {
bool first = true;
for (const String &arg : args) {
if (first) {
first = false;
} else {
cmdLine->append(' ');
}
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<args.size(); ++i) {
const String &arg = args.at(i);
List<const Option<T> *> opts;
String value;
auto addArg = [&arg, &opts, &status, flags](const Option<T> *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<arg.size(); ++j) {
if (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<T> *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 <typename T>
static void help(FILE *f, const char *app, std::initializer_list<Option<T> > optsList)
{
List<String> 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<size_t>(out.back().size(), longest);
}
}
fprintf(f, "%s options...\n", app);
const Option<T> *opts = optsList.begin();
const size_t c = out.size();
for (size_t i=0; i<c; ++i) {
if (out.at(i).isEmpty()) {
fprintf(f, "%s\n", opts[i].description.constData());
} else {
fprintf(f, "%s%s %s\n",
out.at(i).constData(),
String(longest - out.at(i).size(), ' ').constData(),
opts[i].description.constData());
}
}
}
template <typename T>
static void man(std::initializer_list<Option<T> > optsList)
{
const Option<T> *opts = optsList.begin();
String out = ("<!DOCTYPE manpage SYSTEM \"http://masqmail.cx/xmltoman/xmltoman.dtd\">\n"
"<?xml-stylesheet type=\"text/xsl\" href=\"http://masqmail.cx/xmltoman/xmltoman.xsl\"?>\n"
"\n"
"<manpage name=\"rc\" section=\"1\" desc=\"command line client for RTags\">\n"
"\n"
"<synopsis>\n"
" <cmd>rc <arg>file.1.xml</arg> > file.1</cmd>\n"
"</synopsis>\n"
"\n"
"<description>\n"
"\n"
"<p>rc is a command line client used to control RTags.</p>\n"
"\n"
"</description>\n");
for (size_t i=0; i<optsList.size(); ++i) {
if (!opts[i].description.isEmpty()) {
if (opts[i].longOpt.isEmpty() && !opts[i].shortOpt) {
if (i)
out.append("</section>\n");
out.append(String::format<128>("<section name=\"%s\">\n", opts[i].description.constData()));
} else {
out.append(String::format<64>(" <option>%s%s%s%s<optdesc>%s</optdesc></option>\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("</section>\n"
"<section name=\"Authors\">\n"
" <p>RTags was written by Jan Erik Hanssen &lt;jhanssen@gmail.com&gt; and Anders Bakken &lt;abakken@gmail.com&gt;</p>\n"
"</section>\n"
"<section name=\"See also\">\n"
" <p><manref name=\"rdm\" section=\"1\"/></p>\n"
"</section>\n"
"<section name=\"Comments\">\n"
" <p>This man page was written using <manref name=\"xmltoman\" section=\"1\" href=\"http://masqmail.cx/xmltoman/\"/>.</p>\n"
"</section>\n"
"</manpage>\n");
printf("%s", out.constData());
}
}
#endif
-196
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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: <string.h> (stuff under /usr/include, etc.)
// 2. -nostdinc++ -- disables C++ standard include path
// Example: <vector> (stuff under /usr/lib/c++/v1)
// 3. -nobuiltininc -- (clang only?) disables compiler-provided includes
// Example: limits.h, float.h
Set<Source::Define> defines;
List<Source::Include> includePaths;
List<Source::Include> stdincxxPaths;
List<Source::Include> builtinPaths;
};
static Hash<Path, Compiler> sCompilers;
namespace CompilerManager {
List<Path> compilers()
{
std::lock_guard<std::mutex> lock(sMutex);
return sCompilers.keys();
}
void applyToSource(Source &source, Flags<CompilerManager::Flag> flags)
{
std::lock_guard<std::mutex> lock(sMutex);
Path cpath = source.compiler();
Compiler &compiler = sCompilers[cpath];
if (!compiler.inited) {
compiler.inited = true;
List<String> overrides;
List<String> out, err;
List<String> args;
List<String> 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<out.size(); ++i) {
const String &line = out.at(i);
// error() << c << line;
if (line.startsWith("#define ")) {
Source::Define def;
const int space = line.indexOf(' ', 8);
if (space == -1) {
def.define = line.mid(8);
} else {
def.define = line.mid(8, space - 8);
def.value = line.mid(space + 1);
}
compiler.defines.insert(def);
}
}
enum { eNormal, eNoStdInc, eNoBuiltin } mode = eNormal;
List<Source::Include> copy;
for (size_t i=0; i<err.size(); ++i) {
const String &line = err.at(i);
if (line.startsWith("@@@@")) { // magic separator
if (mode == eNoStdInc) {
// What's left in copy are the std c++ paths
compiler.stdincxxPaths = copy;
mode = eNoBuiltin;
} else if (mode == eNoBuiltin) {
// What's left in copy are the builtin paths
compiler.builtinPaths = copy;
// Set the includePaths exclusive of stdinc/builtin
for (auto& inc : compiler.stdincxxPaths)
compiler.includePaths.remove(inc);
for (auto& inc : compiler.builtinPaths)
compiler.includePaths.remove(inc);
break; // we're done
} else {
mode = eNoStdInc;
}
copy = compiler.includePaths;
}
size_t j = 0;
while (j < line.size() && isspace(line.at(j)))
++j;
int end = line.lastIndexOf(" (framework directory)");
Source::Include::Type type = Source::Include::Type::Type_System;
if (end != -1) {
end = end - j;
type = Source::Include::Type_SystemFramework;
}
Path path = line.mid(j, end);
// error() << "looking at" << line << path << path.isDir();
if (path.isDir()) {
path.resolve();
if (mode == eNormal) {
compiler.includePaths.append(Source::Include(type, path));
} else {
copy.remove(Source::Include(type, path));
}
}
}
debug() << "[CompilerManager]" << cpath << "got includepaths\n" << compiler.includePaths;
debug() << "StdInc++: " << compiler.stdincxxPaths << "\nBuiltin: " << compiler.builtinPaths;
debug() << "[CompilerManager] returning.\n";
}
if (flags & IncludeDefines)
source.defines << compiler.defines;
if (flags & IncludeIncludePaths) {
if (!source.arguments.contains("-nostdinc")) {
source.includePaths << compiler.includePaths;
if (!source.arguments.contains("-nostdinc++"))
source.includePaths << compiler.stdincxxPaths;
if (!source.arguments.contains("-nobuiltininc"))
source.includePaths << compiler.builtinPaths;
} else if (!strncmp("clang", cpath.fileName(), 5)) {
// Module.map causes errors when -nostdinc is used, as it
// can't find some mappings to compiler provided headers
source.arguments.append("-fno-modules");
}
}
}
} // namespace CompilerManager
-38
View File
@@ -1,38 +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 <http://www.gnu.org/licenses/>. */
#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<Path> compilers();
enum Flag {
None = 0x0,
IncludeDefines = 0x1,
IncludeIncludePaths = 0x2
};
RCT_FLAGS(Flag);
void applyToSource(Source &source, Flags<Flag> flags);
}
#endif
-748
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "CompletionThread.h"
#include "IndexDataMessage.h"
#include "Project.h"
#include "rct/StopWatch.h"
#include "RTags.h"
#include "RTagsLogOutput.h"
#include "Server.h"
#include <sstream>
#include <fstream>
#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<double>(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<std::mutex> 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<std::mutex> 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<std::mutex> 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<double>(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<Flag> flags, String &&unsaved,
const String &prefix,
const std::shared_ptr<Connection> &conn)
{
if (Server::instance()->options().options & Server::CompletionLogs)
error() << "CODE COMPLETION completeAt" << location << flags;
Request *request = new Request({ std::forward<Source>(source), location, flags, std::forward<String>(unsaved), prefix, conn});
std::unique_lock<std::mutex> 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<std::mutex> lock(mMutex);
for (auto req : mPending) {
if (req->source == source) {
req->unsaved = std::move(unsaved);
return;
}
}
Request *request = new Request({ std::forward<Source>(source), Location(), WarmUp, std::forward<String>(unsaved), String(), std::shared_ptr<Connection>() });
mPending.push_back(request);
mCondition.notify_one();
}
String CompletionThread::dump()
{
Dump dump;
dump.done = false;
{
std::unique_lock<std::mutex> lock(mMutex);
if (mDump)
return String(); // dump in progress
mDump = &dump;
mCondition.notify_one();
}
std::unique_lock<std::mutex> lock(dump.mutex);
while (!dump.done) {
dump.cond.wait(lock);
}
return std::move(dump.string);
}
void CompletionThread::stop()
{
std::unique_lock<std::mutex> 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<unsigned long>(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("<?xml version=\"1.0\" encoding=\"utf-8\"?><completions pending=\"true\">");
} 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<CXTranslationUnit_Flags> flags = static_cast<CXTranslationUnit_Flags>(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<CompletionCandidate *> candidates;
candidates.reserve(results->NumResults);
int nodeCount = 0;
#ifdef RTAGS_COMPLETION_TOKENS_ENABLED
Map<Token, int> tokens;
if (!request->unsaved.isEmpty()) {
tokens = Token::tokenize(request->unsaved.constData(), request->unsaved.size());
// for (Map<Token, int>::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; j<chunkCount; ++j) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j);
String text = RTags::eatString(clang_getCompletionChunkText(string, j));
if (chunkKind == CXCompletionChunk_TypedText) {
candidate->name = 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; j<annotations; ++j) {
const CXStringScope annotation = clang_getCompletionAnnotation(string, j);
const char *cstr = clang_getCString(annotation);
if (strlen(cstr)) {
if (!candidate->annotation.isEmpty())
candidate->annotation += ' ';
candidate->annotation + cstr;
}
}
}
}
List<std::unique_ptr<MatchResult> > 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<std::unique_ptr<MatchResult> >(), 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<LogOutput> output;
std::shared_ptr<Connection> connection;
Flags<CompletionThread::Flag> flags;
};
void CompletionThread::printCompletions(const List<std::unique_ptr<MatchResult> > &results, Request *request)
{
static List<String> cursorKindNames;
// error() << request->flags << testLog(RTags::DiagnosticsLevel) << completions.size() << request->conn;
List<std::shared_ptr<Output> > 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>();
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<LogOutput> &output) {
// error() << "Got a dude" << output->testLog(RTags::DiagnosticsLevel);
if (output->testLog(RTags::DiagnosticsLevel)) {
auto out = std::make_shared<Output>();
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>("<?xml version=\"1.0\" encoding=\"utf-8\"?><completions location=\"%s\"><![CDATA[",
request->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<MatchResult> &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 += "]]></completions>\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> &project) const
{
std::unique_lock<std::mutex> 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<uint32_t> &deps) const
{
std::unique_lock<std::mutex> 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> 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());
}
-207
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef CompletionThread_h
#define CompletionThread_h
#include <clang-c/Index.h>
#include <condition_variable>
#include <memory>
#include <mutex>
#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> &project) const;
void completeAt(Source &&source, Location location, Flags<Flag> flags,
String &&unsaved, const String &prefix,
const std::shared_ptr<Connection> &conn);
void prepare(Source &&source, String &&unsaved);
Source findSource(const Set<uint32_t> &deps) const;
void stop();
String dump();
private:
struct Request;
void processDiagnostics(const Request *request, CXCodeCompleteResults *results, CXTranslationUnit unit);
void process(Request *request);
Set<uint32_t> mWatched;
bool mShutdown;
const size_t mCacheSize;
struct Request {
~Request()
{
if (conn)
conn->finish();
}
String toString() const;
Source source;
Location location;
Flags<Flag> flags;
String unsaved, prefix;
std::shared_ptr<Connection> conn;
};
LinkedList<Request*> 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<String>(t)), kind(k)
{}
String text;
CXCompletionChunkKind kind;
};
List<Chunk> chunks;
enum Flag {
None = 0x0,
IncludeChunks = 0x1
};
Value toValue(unsigned int flags) const;
};
List<Candidate> candidates;
const Location location;
Flags<Flag> flags;
Completions *next, *prev;
};
void printCompletions(const List<std::unique_ptr<MatchResult> > &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<RTags::TranslationUnit> 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<Token, int> tokenize(const char *data, int size)
{
Map<Token, int> 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<Token, int> &tokens)
{
int &val = tokens[Token(data + pos, len)];
if (!val)
val = pos;
}
};
#endif
Hash<uint32_t, SourceFile*> mCacheMap;
EmbeddedLinkedList<SourceFile*> mCacheList;
mutable std::mutex mMutex;
std::condition_variable mCondition;
};
RCT_FLAGS(CompletionThread::Flag);
#endif
-40
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "DependenciesJob.h"
#include "FileManager.h"
#include "Project.h"
#include "QueryMessage.h"
#include "RTags.h"
#include "Server.h"
DependenciesJob::DependenciesJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project)
: QueryJob(query, project, QuietJob)
{
Deserializer deserializer(query->query());
Path path;
deserializer >> path >> mArgs;
mFileId = Location::fileId(path);
}
int DependenciesJob::execute()
{
std::shared_ptr<Project> proj = project();
if (!proj)
return 2;
write(proj->dumpDependencies(mFileId, mArgs, queryFlags()));
return 0;
}
-35
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef DependenciesJob_h
#define DependenciesJob_h
#include "QueryJob.h"
class Project;
class QueryMessage;
class DependenciesJob : public QueryJob
{
public:
DependenciesJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
uint32_t mFileId;
List<String> mArgs;
};
#endif
-99
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef Diagnostic_h
#define Diagnostic_h
#include "rct/Serializer.h"
#include "rct/String.h"
#include "Location.h"
#include "Sandbox.h"
struct Diagnostic;
typedef Map<Location, Diagnostic> 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<Location, int> ranges;
Diagnostics children;
Flags<Flag> 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<Flag>(flags & Type_Mask).cast<Flag>();
}
template <> inline Serializer &operator<<(Serializer &s, const Diagnostic &d)
{
// SBROOT
String tmessage = Sandbox::encoded(d.message);
s << d.flags.cast<uint8_t>() << 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<Diagnostic::Flag>(flags);
return s;
}
#endif
-177
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "FileManager.h"
#include "Filter.h"
#include "Project.h"
#include "ScanThread.h"
#include "Server.h"
FileManager::FileManager(const std::shared_ptr<Project> &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> project = mProject.lock();
assert(project);
if (mode == Asynchronous) {
startScanThread();
} else {
const Set<Path> paths = ScanThread::paths(project->path());
onRecurseJobFinished(paths);
}
}
void FileManager::onRecurseJobFinished(const Set<Path> &paths)
{
std::lock_guard<std::mutex> lock(mMutex); // ### is this needed now?
std::shared_ptr<Project> project = mProject.lock();
if (!project)
return;
Files &map = project->files();
map.clear();
clearFileSystemWatcher();
for (Set<Path>::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<String> &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<std::mutex> 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> project = mProject.lock();
assert(project);
Files &map = project->files();
const Path parent = path.parentDir();
if (!parent.isEmpty()) {
Set<String> &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<std::mutex> lock(mMutex);
std::shared_ptr<Project> project = mProject.lock();
if (!project)
return;
Files &map = project->files();
if (!map.remove(path)) {
const Path parent = path.parentDir();
if (map.contains(parent)) {
Set<String> &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<std::mutex> lock(mMutex);
std::shared_ptr<Project> 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> project = mProject.lock();
assert(project);
ScanThread *thread = new ScanThread(project->path());
thread->setAutoDelete(true);
std::weak_ptr<FileManager> that = shared_from_this();
thread->finished().connect<EventLoop::Move>([that](const Set<Path> &paths) {
if (auto strong = that.lock())
strong->onRecurseJobFinished(paths);
});
thread->start();
}
void FileManager::clearFileSystemWatcher()
{
if (auto project = mProject.lock())
project->clearWatch(Project::Watch_FileManager);
}
-49
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef FileManager_h
#define FileManager_h
#include <mutex>
#include "rct/Path.h"
#include "rct/Timer.h"
class Project;
class FileManager : public std::enable_shared_from_this<FileManager>
{
public:
FileManager(const std::shared_ptr<Project> &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<Path> &mPaths);
bool contains(const Path &path) const;
void clearFileSystemWatcher();
private:
void startScanThread();
void watch(const Path &path);
std::weak_ptr<Project> mProject;
uint64_t mLastReloadTime;
mutable std::mutex mMutex;
};
#endif
-314
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef FileMap_h
#define FileMap_h
#include <assert.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <functional>
#include <limits>
#include "Location.h"
#include "rct/Serializer.h"
template <typename T> 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 <typename Key, typename Value>
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<char*>(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<const char*>(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<Key>(keysSegment(), index);
}
Value valueAt(uint32_t index) const
{
assert(index >= 0 && index < mCount);
return read<Value>(valuesSegment(), index);
}
uint32_t lowerBound(const Key &k, bool *match = 0) const
{
if (!mCount) {
if (match)
*match = false;
return std::numeric_limits<uint32_t>::max();
}
int lower = 0;
int upper = mCount - 1;
do {
const int mid = lower + ((upper - lower) / 2);
const int cmp = compare<Key>(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<int>(mCount))
lower = std::numeric_limits<uint32_t>::max();
if (match)
*match = false;
return lower;
}
static String encode(const Map<Key, Value> &map)
{
String out;
Serializer serializer(out);
serializer << static_cast<uint32_t>(map.size());
uint32_t valuesOffset;
if (uint32_t size = FixedSize<Key>::value) {
valuesOffset = ((static_cast<uint32_t>(map.size()) * size) + (sizeof(uint32_t) * 2));
serializer << valuesOffset;
for (const std::pair<Key, Value> &pair : map) {
out.append(reinterpret_cast<const char*>(&pair.first), size);
}
} else {
serializer << static_cast<uint32_t>(0); // values offset
uint32_t offset = sizeof(uint32_t) * 2 + (map.size() * sizeof(uint32_t));
String keyData;
Serializer keySerializer(keyData);
for (const std::pair<Key, Value> &pair : map) {
const uint32_t pos = offset + keyData.size();
out.append(reinterpret_cast<const char*>(&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<uint32_t>(out.size()));
if (uint32_t size = FixedSize<Value>::value) {
for (const std::pair<Key, Value> &pair : map) {
out.append(reinterpret_cast<const char*>(&pair.second), size);
}
} else {
const uint32_t encodedValuesOffset = valuesOffset + (sizeof(uint32_t) * map.size());
String valueData;
Serializer valueSerializer(valueData);
for (const std::pair<Key, Value> &pair : map) {
const uint32_t pos = encodedValuesOffset + valueData.size();
out.append(reinterpret_cast<const char*>(&pos), sizeof(pos));
valueSerializer << pair.second;
}
out.append(valueData);
}
return out;
}
static size_t write(const Path &path, const Map<Key, Value> &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<ssize_t>(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 <typename T>
inline T read(const char *base, uint32_t index) const
{
if (const uint32_t size = FixedSize<T>::value) {
T t = T();
memcpy(&t, base + (index * size), FixedSize<T>::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
-52
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef Filter_h
#define Filter_h
#include <fnmatch.h>
#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<String> &filters = List<String>())
{
const int size = filters.size();
for (int i=0; i<size; ++i) {
const String &filter = filters.at(i);
if (!fnmatch(filter.constData(), path.constData(), 0) || path.contains(filter))
return Filtered;
}
if (path.isDir())
return Directory;
const char *ext = path.extension();
if (ext && (Path::isSource(ext) || Path::isHeader(ext)))
return Source;
return File;
}
}
#endif
-170
View File
@@ -1,170 +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 <http://www.gnu.org/licenses/>. */
#include "FindFileJob.h"
#include "FileManager.h"
#include "Project.h"
#include "rct/SignalSlot.h"
#include "RTags.h"
#include "Server.h"
static Flags<QueryJob::JobFlag> flags(Flags<QueryMessage::Flag> queryFlags)
{
Flags<QueryJob::JobFlag> flags = QueryJob::QuietJob;
if (queryFlags & QueryMessage::Elisp)
flags |= QueryJob::QuoteOutput;
return flags;
}
FindFileJob::FindFileJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &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<Project> 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<String> 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<String> &files = dirit->second;
for (Set<String>::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<String>::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;
}
-35
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef FindFileJob_h
#define FindFileJob_h
#include <regex>
#include "QueryJob.h"
#include "rct/String.h"
class FindFileJob : public QueryJob
{
public:
FindFileJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
String mPattern;
std::regex mRegex;
};
#endif
-67
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "FindSymbolsJob.h"
#include "Project.h"
#include "QueryMessage.h"
#include "rct/Log.h"
#include "RTags.h"
#include "Server.h"
static inline Flags<QueryJob::JobFlag> jobFlags(Flags<QueryMessage::Flag> queryFlags)
{
return (queryFlags & QueryMessage::Elisp
? Flags<QueryJob::JobFlag>(QueryJob::QuoteOutput|QueryJob::QuietJob)
: Flags<QueryJob::JobFlag>(QueryJob::QuietJob));
}
FindSymbolsJob::FindSymbolsJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &proj)
: QueryJob(query, proj, ::jobFlags(query->flags())), string(query->query())
{
}
int FindSymbolsJob::execute()
{
int ret = 2;
if (std::shared_ptr<Project> proj = project()) {
Set<Symbol> symbols;
auto inserter = [proj, this, &symbols](Project::SymbolMatchType type,
const String &symbolName,
const Set<Location> &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<RTags::SortedSymbol> sorted = proj->sort(symbols, queryFlags());
const Flags<WriteFlag> writeFlags = fileFilter() ? Unfiltered : NoWriteFlags;
const int count = sorted.size();
ret = count ? 0 : 1;
for (int i=0; i<count; ++i) {
write(sorted.at(i).location, writeFlags);
}
}
}
return ret;
}
-33
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
const String string;
};
#endif
-63
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef FixIt_h
#define FixIt_h
#include <stdint.h>
#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
-110
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "FollowLocationJob.h"
#include "Project.h"
#include "rct/SignalSlot.h"
#include "RTags.h"
#include "Server.h"
FollowLocationJob::FollowLocationJob(Location loc,
const std::shared_ptr<QueryMessage> &query,
const std::shared_ptr<Project> &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<String> 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<Location> 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;
}
-32
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef FollowLocationJob_h
#define FollowLocationJob_h
#include "Location.h"
#include "QueryJob.h"
class FollowLocationJob : public QueryJob
{
public:
FollowLocationJob(Location loc, const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
const Location location;
};
#endif
-151
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "IncludeFileJob.h"
#include "Project.h"
#include "RTags.h"
#include "Server.h"
IncludeFileJob::IncludeFileJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &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<Path> headersForSymbol(const std::shared_ptr<Project> &project, Location loc)
{
List<Path> 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<Location> last;
int matches = 0;
Set<String> all;
auto process = [&directory, this, &all](const Set<Location> &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<String> 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<String>::const_iterator it = alternatives.begin();
while (it != alternatives.end()) {
bool drop = false;
for (List<String>::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<Location> &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<String> 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;
}
-33
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef IncludeFileJob_h
#define IncludeFileJob_h
#include "QueryJob.h"
#include "rct/String.h"
class IncludeFileJob : public QueryJob
{
public:
IncludeFileJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
String mSymbol;
Source mSource;
};
#endif
-14
View File
@@ -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", " ")
-129
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<IndexerJob> &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<Flag> flags() const { return mFlags; }
void setFlags(Flags<Flag> f) { mFlags = f; }
void setFlag(Flag flag, bool on = true) { mFlags.set(flag, on); }
Set<uint32_t> visitedFiles() const
{
Set<uint32_t> ret;
for (const auto &it : mFiles) {
if (it.second & Visited)
ret.insert(it.first);
}
return ret;
}
Set<uint32_t> blockedFiles() const
{
Set<uint32_t> 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<IndexerJob::Flag> indexerJobFlags() const { return mIndexerJobFlags; }
void setIndexerJobFlags(Flags<IndexerJob::Flag> 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<uint32_t, Flags<FileFlag> > &files() { return mFiles; }
const Hash<uint32_t, Flags<FileFlag> > &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<IndexerJob::Flag> mIndexerJobFlags; // indexerjobflags
String mMessage; // used as output for dump when flags & Dump
FixIts mFixIts;
Diagnostics mDiagnostics;
Includes mIncludes;
Hash<uint32_t, Flags<FileFlag> > mFiles;
Flags<Flag> 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
-35
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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;
}
-63
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<String> &environment) { mEnvironment = environment; }
const List<String> &environment() const { return mEnvironment; }
List<String> &&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<Flag> flags() const { return mFlags; }
void setFlags(Flags<Flag> 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<String> mEnvironment;
Path mProjectRoot;
Path mCompileCommands;
Flags<Flag> mFlags;
};
RCT_FLAGS(IndexMessage::Flag);
#endif
-47
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "IndexParseData.h"
#include "Location.h"
bool IndexParseData::write(const std::function<bool(const String &)> &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;
}
-117
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef IndexParseData_h
#define IndexParseData_h
#include "rct/Path.h"
#include "rct/List.h"
#include "rct/Serializer.h"
#include "rct/Log.h"
#include <cstdint>
#include "RTags.h"
#include "rct/Connection.h"
#include "Match.h"
#include <functional>
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<String> environment;
};
Hash<uint32_t, CompileCommands> compileCommands; // fileId for compile_commands.json -> CompileCommands
List<String> environment;
Sources sources;
bool isEmpty() const { return compileCommands.isEmpty() && environment.isEmpty() && sources.isEmpty(); }
bool write(const std::function<bool(const String &)> &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<uint32_t>(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
-215
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<Flag> f,
const std::shared_ptr<Project> &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; i<s.size(); ++i) {
const Source &src = s.at(i);
bool found = false;
for (size_t j=0; j<sources.size(); ++j) {
if (src.compareArguments(sources.at(j))) {
found = true;
break;
}
}
if (!found)
sources.append(src);
}
assert(!sources.isEmpty());
sourceFile = s.begin()->sourceFile();
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<Project> p = server->project(project);
if (server->isActiveBuffer(fileId)) {
ret += 8;
} else if (p) {
if (DependencyNode *node = p->dependencyNode(fileId)) {
Set<DependencyNode*> seen;
seen.insert(node);
std::function<bool(const DependencyNode *node)> 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<Project> proj = Server::instance()->project(project);
const Server::Options &options = Server::instance()->options();
serializer << static_cast<uint16_t>(RTags::DatabaseVersion)
<< options.sandboxRoot
<< id
<< options.socketFile
<< project
<< static_cast<uint32_t>(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<Flag> f = flags;
if (Server::instance()->isActiveBuffer(fileId()))
f |= Active;
serializer << sourceFile
<< f
<< static_cast<uint32_t>(options.rpVisitFileTimeout)
<< static_cast<uint32_t>(options.rpIndexDataMessageTimeout)
<< static_cast<uint32_t>(options.rpConnectTimeout)
<< static_cast<uint32_t>(options.rpConnectAttempts)
<< static_cast<int32_t>(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<Flag> flags)
{
List<String> 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();
}
-74
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<Flag> flags);
IndexerJob(const SourceList &sources,
Flags<Flag> flags,
const std::shared_ptr<Project> &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<Flag> flags;
Path project;
UnsavedFiles unsavedFiles;
Set<uint32_t> visited;
int crashCount;
Signal<std::function<void(IndexerJob *)> > destroyed;
private:
mutable int mCachedPriority;
static uint64_t sNextId;
};
RCT_FLAGS(IndexerJob::Flag);
#endif
-322
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<IndexerJob> &job)
{
assert(!(job->flags & ~IndexerJob::Type_Mask));
std::shared_ptr<Node> 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<Node> 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<uint32_t> &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> &project) const
{
DependencyNode *node = project->dependencies().value(file);
if (!node)
return false;
Set<uint32_t> 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<Node> 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> 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<String> 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<Node> 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<IndexDataMessage>(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<IndexDataMessage>(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<IndexDataMessage> &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<IndexerJob> &job, const std::shared_ptr<IndexDataMessage> &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> 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<Connection> &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<IndexerJob> &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<std::shared_ptr<Node> > nodes(mPendingJobs.size());
for (size_t i=0; i<nodes.size(); ++i) {
std::shared_ptr<Node> node = mPendingJobs.removeFirst();
node->job->recalculatePriority();
nodes[i] = std::move(node);
}
std::stable_sort(nodes.begin(), nodes.end(), [](const std::shared_ptr<Node> &l, const std::shared_ptr<Node> &r) -> bool {
return l->job->priority() > r->job->priority();
});
for (std::shared_ptr<Node> &n : nodes) {
mPendingJobs.append(std::move(n));
}
}
-86
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef JobScheduler_h
#define JobScheduler_h
#include <memory>
#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<JobScheduler>
{
public:
JobScheduler();
~JobScheduler();
struct JobScope {
JobScope(const std::shared_ptr<JobScheduler> &scheduler)
: mScheduler(scheduler)
{
assert(mScheduler);
++mScheduler->mProcrastination;
}
~JobScope()
{
if (!--mScheduler->mProcrastination)
mScheduler->startJobs();
}
private:
const std::shared_ptr<JobScheduler> mScheduler;
};
void add(const std::shared_ptr<IndexerJob> &job);
void handleIndexDataMessage(const std::shared_ptr<IndexDataMessage> &message);
void dump(const std::shared_ptr<Connection> &conn);
void abort(const std::shared_ptr<IndexerJob> &job);
void clearHeaderError(uint32_t file);
bool hasHeaderError(uint32_t fileId) const { return mHeaderErrors.contains(fileId); }
Set<uint32_t> 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<IndexerJob> &job, const std::shared_ptr<IndexDataMessage> &message);
struct Node {
unsigned long long started;
std::shared_ptr<IndexerJob> job;
Process *process;
std::shared_ptr<Node> next, prev;
String stdOut;
};
uint32_t hasHeaderError(DependencyNode *node, Set<uint32_t> &seen) const;
uint32_t hasHeaderError(uint32_t file, const std::shared_ptr<Project> &project) const;
int mProcrastination;
Set<uint32_t> mHeaderErrors;
EmbeddedLinkedList<std::shared_ptr<Node> > mPendingJobs;
Hash<Process *, std::shared_ptr<Node> > mActiveByProcess;
Hash<uint64_t, std::shared_ptr<Node> > mActiveById, mInactiveById;
};
#endif
-174
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<QueryJob::JobFlag> defaultFlags = (QueryJob::WriteUnfiltered | QueryJob::QuietJob);
const Flags<QueryJob::JobFlag> elispFlags = (defaultFlags | QueryJob::QuoteOutput);
ListSymbolsJob::ListSymbolsJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &proj)
: QueryJob(query, proj, query->flags() & QueryMessage::Elisp ? elispFlags : defaultFlags),
string(query->query())
{
}
int ListSymbolsJob::execute()
{
Set<String> out;
std::shared_ptr<Project> proj = project();
if (proj) {
if (queryFlags() & QueryMessage::WildcardSymbolNames
&& (string.contains('*') || string.contains('?')) && !string.endsWith('*')) {
string += '*';
}
List<QueryMessage::PathFilter> filters = pathFilters();
List<Path> 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<String>::const_iterator it = out.begin(); it != out.end(); ++it) {
write(*it);
}
write(")", IgnoreMax | DontQuote);
} else {
List<String> sorted = out.toList();
if (queryFlags() & QueryMessage::ReverseSort) {
std::sort(sorted.begin(), sorted.end(), std::greater<String>());
} 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<String> ListSymbolsJob::listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<Path> &paths) const
{
Set<String> 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; i<paths.size(); ++i) {
const Path file = paths.at(i);
const uint32_t fileId = Location::fileId(file);
if (!fileId)
continue;
auto symbols = project->openSymbols(fileId);
if (!symbols)
continue;
const int count = symbols->count();
for (int j=0; j<count; ++j) {
const Symbol &symbol = symbols->valueAt(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<String> ListSymbolsJob::listSymbols(const std::shared_ptr<Project> &project) const
{
const bool hasFilter = QueryJob::hasFilter();
const bool hasKindFilter = QueryJob::hasKindFilter();
const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses;
Set<String> out;
auto inserter = [this, &project, hasFilter, hasKindFilter, stripParentheses, &out](Project::SymbolMatchType,
const String &str,
const Set<Location> &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;
}
-37
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef ListSymbolsJob_h
#define ListSymbolsJob_h
#include "QueryJob.h"
#include "rct/String.h"
template <typename T>
class List;
class QueryMessage;
class ListSymbolsJob : public QueryJob
{
public:
ListSymbolsJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &proj);
protected:
virtual int execute() override;
Set<String> listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<Path> &paths) const;
Set<String> listSymbols(const std::shared_ptr<Project> &project) const;
private:
String string;
};
#endif
-180
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "Location.h"
#include "rct/Rct.h"
#include "RTags.h"
#include "Server.h"
#include "Project.h"
#include "ClangIndexer.h"
Hash<Path, uint32_t> Location::sPathsToIds;
Hash<uint32_t, Path> 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<startBit + bitCount; ++i) {
mask |= (static_cast<uint64_t>(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<ToStringFlag> flags, Hash<Path, String> *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<Project> 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<ToStringFlag> flags, Hash<Path, String> *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 = &copy;
}
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<Path, uint32_t> &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<uint32_t, Path> &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);
}
}
-357
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef Location_h
#define Location_h
#include <algorithm>
#include <assert.h>
#include <clang-c/Index.h>
#include <stdio.h>
#if defined(OS_Linux)
#include <linux/limits.h>
#elif defined(OS_Darwin)
#include <sys/syslimits.h>
#endif
#ifndef RTAGS_SINGLE_THREAD
#include <mutex>
#define LOCK() const std::lock_guard<std::mutex> 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<uint64_t>(col) << (FileBits + LineBits)) | (static_cast<uint64_t>(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<uint32_t>(value & FILEID_MASK); }
inline uint32_t line() const { return static_cast<uint32_t>((value & LINE_MASK) >> FileBits); }
inline uint32_t column() const { return static_cast<uint32_t>((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<ToStringFlag> flags = NoFlag, Hash<Path, String> *contextCache = 0) const;
String context(Flags<ToStringFlag> flags, Hash<Path, String> *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<uint32_t>(strtoul(cstr + secondLastColon + 1, &end, 10));
if (*end != ':' || end == str + secondLastColon + 1)
return false;
assert(col);
*col = static_cast<uint32_t>(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<uint32_t, Path> idsToPaths()
{
LOCK();
return sIdsToPaths;
}
static Hash<Path, uint32_t> pathsToIds()
{
LOCK();
return sPathsToIds;
}
static void iterate(std::function<void(const Path &, uint32_t)> func)
{
LOCK();
for (const auto &it : sPathsToIds) {
func(it.first, it.second);
}
}
static bool init(const Hash<Path, uint32_t> &pathsToIds);
static void init(const Hash<uint32_t, Path> &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<Path, uint32_t> sPathsToIds;
static Hash<uint32_t, Path> 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<Location>
{
static constexpr size_t value = sizeof(Location::value);
};
template <> inline Serializer &operator<<(Serializer &s, const Location &t)
{
s.write(reinterpret_cast<const char*>(&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<char*>(&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
-48
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<Connection> &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<Connection> &mConnection;
};
#endif
-48
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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
-126
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef Match_h
#define Match_h
#include <regex>
#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<Flag> 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<Flag> 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<Flag> mFlags;
};
RCT_FLAGS(Match::Flag);
inline Log operator<<(Log log, const Match &match)
{
String ret = "Match(flags: ";
ret += String::number(match.flags().cast<unsigned int>(), 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<Flag> f)
: mFlags(f)
{
if (mFlags & Flag_Regex) {
try {
mRegex = pattern.ref();
} catch (const std::regex_error &err) {
mFlags &= ~Flag_Regex;
}
}
mPattern = pattern;
}
#endif
-58
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "Preprocessor.h"
#include "Server.h"
#include "rct/Connection.h"
#include "rct/Log.h"
#include "rct/Process.h"
#include "RTags.h"
const Flags<Source::CommandLineFlag> 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> &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);
}
-39
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef PREPROCESSOR_H
#define PREPROCESSOR_H
#include <memory>
#include "Source.h"
class Connection;
class Process;
class Preprocessor
{
public:
Preprocessor(const Source &source, const std::shared_ptr<Connection> &connection);
void preprocess();
private:
void onProcessFinished();
Source mSource;
List<String> mArgs;
std::shared_ptr<Connection> mConnection;
std::unique_ptr<Process> mProcess;
};
#endif
-237
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "ProcThread.h"
#include <rct/StopWatch.h>
#include "RTags.h"
#ifdef RTAGS_HAS_PROC
#include <sys/types.h>
#include <dirent.h>
#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<std::mutex> 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<std::mutex> lock(mMutex);
mInterval = 0;
mCond.notify_one();
}
join();
}
struct ParseNode {
char cmdLine[16384];
char cwd[PATH_MAX];
List<String> 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<ParseNode> 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<read; ++i) {
switch (node.cmdLine[i]) {
case '\n':
case '\0':
case ' ':
if (prev == node.cmdLine) {
node.cmdLine[i] = '\0';
// error() << "Considering" << node.cmdLine;
if (strstr(node.cmdLine, "cc1plus") || strstr(node.cmdLine, "/rc")) {
hasSource = Nay;
}
}
node.cmdLine[i] = ' ';
if (i && hasSource == Dunno) {
for (const char *ext = &node.cmdLine[i - 1]; ext > 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<read; ++i) {
switch (env[i]) {
case '\n':
case '\0':
node.environ.append(String(env + last, i - last));
last = i + 1;
break;
default:
break;
}
}
if (read > 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<nodes.size() - 1; ++i) {
const auto &node = nodes.at(i);
List<Path> 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<int, bool>::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
}
-56
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef ProcThread_h
#define ProcThread_h
#include <rct/Hash.h>
#include <rct/Path.h>
#include <rct/Thread.h>
#include <rct/SignalSlot.h>
#include <rct/String.h>
#include <mutex>
#include <condition_variable>
#include <time.h>
#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<std::function<void(SourceList)> > &command() { return mCommand; }
private:
void readProc();
Signal<std::function<void(SourceList)> > mCommand;
std::mutex mMutex;
std::condition_variable mCond;
int mInterval;
#ifdef RTAGS_HAS_PROC
Path mPath;
#endif
Hash<int, bool> mNodes;
};
#endif
File diff suppressed because it is too large. Load diff
-502
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef Project_h
#define Project_h
#include <cstdint>
#include <mutex>
#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<Flag> 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<Flag> flags;
};
RCT_FLAGS(DependencyNode::Flag);
class Project : public std::enable_shared_from_this<Project>
{
public:
Project(const Path &path);
~Project();
bool init();
std::shared_ptr<FileManager> 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<FileMap<String, Set<Location> > > openSymbolNames(uint32_t fileId, String *err = 0)
{
assert(mFileMapScope);
return mFileMapScope->openFileMap<String, Set<Location> >(SymbolNames, fileId, mFileMapScope->symbolNames, err);
}
std::shared_ptr<FileMap<Location, Symbol> > openSymbols(uint32_t fileId, String *err = 0)
{
assert(mFileMapScope);
return mFileMapScope->openFileMap<Location, Symbol>(Symbols, fileId, mFileMapScope->symbols, err);
}
std::shared_ptr<FileMap<String, Set<Location> > > openTargets(uint32_t fileId, String *err = 0)
{
assert(mFileMapScope);
return mFileMapScope->openFileMap<String, Set<Location> >(Targets, fileId, mFileMapScope->targets, err);
}
std::shared_ptr<FileMap<String, Set<Location> > > openUsrs(uint32_t fileId, String *err = 0)
{
assert(mFileMapScope);
return mFileMapScope->openFileMap<String, Set<Location> >(Usrs, fileId, mFileMapScope->usrs, err);
}
std::shared_ptr<FileMap<uint32_t, Token> > openTokens(uint32_t fileId, String *err = 0)
{
assert(mFileMapScope);
return mFileMapScope->openFileMap<uint32_t, Token>(Tokens, fileId, mFileMapScope->tokens, err);
}
enum DependencyMode {
DependsOnArg,
ArgDependsOn,
All
};
Set<uint32_t> dependencies(uint32_t fileId, DependencyMode mode) const;
bool dependsOn(uint32_t source, uint32_t header) const;
String dumpDependencies(uint32_t fileId,
const List<String> &args = List<String>(),
Flags<QueryMessage::Flag> flags = Flags<QueryMessage::Flag>()) const;
const Hash<uint32_t, DependencyNode*> &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<void(SymbolMatchType, const String &, const Set<Location> &)> &func,
Flags<QueryMessage::Flag> 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<Symbol> findTargets(Location location) { return findTargets(findSymbol(location)); }
Set<Symbol> findTargets(const Symbol &symbol);
Symbol findTarget(Location location) { return RTags::bestTarget(findTargets(location)); }
Symbol findTarget(const Symbol &symbol) { return RTags::bestTarget(findTargets(symbol)); }
Set<Symbol> findAllReferences(Location location) { return findAllReferences(findSymbol(location)); }
Set<Symbol> findAllReferences(const Symbol &symbol);
Set<Symbol> findCallers(Location location) { return findCallers(findSymbol(location)); }
Set<Symbol> findCallers(const Symbol &symbol);
Set<Symbol> findVirtuals(Location location) { return findVirtuals(findSymbol(location)); }
Set<Symbol> findVirtuals(const Symbol &symbol);
Set<String> findTargetUsrs(const Symbol &symbol);
Set<String> findTargetUsrs(Location loc);
Set<Symbol> findSubclasses(const Symbol &symbol);
Set<Symbol> findByUsr(const String &usr, uint32_t fileId, DependencyMode mode);
Path sourceFilePath(uint32_t fileId, const char *path = "") const;
List<RTags::SortedSymbol> sort(const Set<Symbol> &symbols,
Flags<QueryMessage::Flag> flags = Flags<QueryMessage::Flag>());
const Files &files() const { return mFiles; }
Files &files() { return mFiles; }
const Set<uint32_t> &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<IndexerJob> &job);
void reindex(uint32_t fileId, Flags<IndexerJob::Flag> 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<uint32_t> &fileIds);
String fixIts(uint32_t fileId) const;
int reindex(const Match &match,
const std::shared_ptr<QueryMessage> &query,
const std::shared_ptr<Connection> &wait);
int remove(const Match &match);
void onJobFinished(const std::shared_ptr<IndexerJob> &job, const std::shared_ptr<IndexDataMessage> &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<WatchMode> mode);
Hash<Path, Flags<WatchMode> > 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<QueryMessage> &msg, const std::shared_ptr<Connection> &conn);
void removeSources(const Hash<uint32_t, uint32_t> &sources); // key fileid, value fileid for compile_commands.json
void removeSource(uint32_t fileId);
Hash<uint32_t, Path> visitedFiles() const
{
std::lock_guard<std::mutex> lock(mMutex);
return mVisitedFiles;
}
void encodeVisitedFiles(Serializer &serializer)
{
std::lock_guard<std::mutex> lock(mMutex);
serializer << mVisitedFiles;
}
class FileMapScopeScope
{
public:
FileMapScopeScope(Project *p)
: mProject(p)
{
if (mProject)
mProject->beginScope();
}
FileMapScopeScope(const std::shared_ptr<Project> &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<QueryMessage::Flag> flags, uint32_t fileId);
void diagnose(uint32_t fileId);
void diagnoseAll();
uint32_t fileMapOptions() const;
void fixPCH(Source &source);
void includeCompletions(Flags<QueryMessage::Flag> flags, const std::shared_ptr<Connection> &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<VisitResult(const Sources &sources)>& cb);
static void forEachSources(IndexParseData &data, const std::function<VisitResult(Sources &sources)>& cb);
void forEachSources(std::function<VisitResult(const Sources &sources)> cb) const { forEachSources(mIndexParseData, cb); }
void forEachSources(std::function<VisitResult(Sources &sources)> cb) { forEachSources(mIndexParseData, cb); }
static void forEachSourceList(const IndexParseData &data, std::function<VisitResult(const SourceList &sources)> cb);
static void forEachSourceList(IndexParseData &data, std::function<VisitResult(SourceList &sources)> cb);
static void forEachSourceList(Sources &sources, const std::function<VisitResult(SourceList &source)>& cb);
static void forEachSourceList(const Sources &sources, const std::function<VisitResult(const SourceList &source)>& cb);
void forEachSourceList(std::function<VisitResult(const SourceList &sources)> cb) const { forEachSourceList(mIndexParseData, cb); }
void forEachSourceList(std::function<VisitResult(SourceList &sources)> cb) { forEachSourceList(mIndexParseData, cb); }
static void forEachSource(Sources &sources, const std::function<VisitResult(Source &source)>& cb);
static void forEachSource(const Sources &sources, const std::function<VisitResult(const Source &source)>& cb);
static void forEachSource(IndexParseData &data, std::function<VisitResult(Source &source)> cb);
static void forEachSource(const IndexParseData &data, std::function<VisitResult(const Source &source)> cb);
void forEachSource(std::function<VisitResult(const Source &source)> cb) const { forEachSource(mIndexParseData, cb); }
void forEachSource(std::function<VisitResult(Source &source)> 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<IndexDataMessage> &msg);
void loadFailed(uint32_t fileId);
void updateFixIts(const Set<uint32_t> &visited, FixIts &fixIts);
int startDirtyJobs(Dirty *dirty,
Flags<IndexerJob::Flag> type,
const UnsavedFiles &unsavedFiles = UnsavedFiles(),
const std::shared_ptr<Connection> &wait = std::shared_ptr<Connection>());
void onDirtyTimeout(Timer *);
bool isTemplateDiagnostic(const std::pair<Location, Diagnostic> &diagnostic);
struct FileMapScope {
FileMapScope(const std::shared_ptr<Project> &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<LRUEntry> 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 <typename Key, typename Value>
std::shared_ptr<FileMap<Key, Value> > openFileMap(FileMapType type, uint32_t fileId,
Hash<uint32_t, std::shared_ptr<FileMap<Key, Value> > > &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<FileMap<Key, Value>>();
String err;
if (fileMap->load(path, project->fileMapOptions(), &err)) {
++totalOpened;
cache[fileId] = fileMap;
auto entry = std::make_shared<LRUEntry>(type, fileId);
entryList.append(entry);
entryMap[entry->key] = entry;
if (++openedFiles > max) {
const std::shared_ptr<LRUEntry> 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<uint32_t, std::shared_ptr<FileMap<String, Set<Location> > > > symbolNames;
Hash<uint32_t, std::shared_ptr<FileMap<Location, Symbol> > > symbols;
Hash<uint32_t, std::shared_ptr<FileMap<String, Set<Location> > > > targets, usrs;
Hash<uint32_t, std::shared_ptr<FileMap<uint32_t, Token> > > tokens;
std::shared_ptr<Project> project;
int openedFiles, totalOpened;
const int max;
bool loadFailed;
EmbeddedLinkedList<std::shared_ptr<LRUEntry> > entryList;
Map<LRUKey, std::shared_ptr<LRUEntry> > entryMap;
};
std::shared_ptr<FileMapScope> mFileMapScope;
const Path mPath, mProjectDataDir;
Path mProjectFilePath, mSourcesFilePath;
Files mFiles;
Hash<uint32_t, Path> mVisitedFiles;
int mJobCounter, mJobsStarted;
time_t mLastIdleTime;
Diagnostics mDiagnostics;
Hash<uint32_t, std::shared_ptr<IndexerJob> > mActiveJobs;
Timer mDirtyTimer, mReloadCompileCommandsTimer;
Set<uint32_t> mPendingDirtyFiles;
StopWatch mTimer;
FileSystemWatcher mWatcher;
IndexParseData mIndexParseData;
Hash<Path, Flags<WatchMode> > mWatchedPaths;
std::shared_ptr<FileManager> mFileManager;
FixIts mFixIts;
Hash<uint32_t, DependencyNode*> mDependencies;
Set<uint32_t> 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<std::mutex> lock(mMutex);
assert(visitFileId);
Path &p = mVisitedFiles[visitFileId];
assert(id);
assert(mActiveJobs.contains(id));
std::shared_ptr<IndexerJob> &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<uint32_t> &fileIds)
{
if (!fileIds.isEmpty()) {
std::lock_guard<std::mutex> 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
-311
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "QueryJob.h"
#include <regex>
#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<QueryMessage> &query,
const std::shared_ptr<Project> &proj,
Flags<JobFlag> 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<QueryMessage::PathFilter> &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<DependencyFilter>(f, mProject));
} else if (query->flags() & QueryMessage::MatchRegex) {
mFilters.append(std::make_shared<RegexFilter>(filter.pattern));
} else {
mFilters.append(std::make_shared<PathFilter>(filter.pattern));
}
}
}
}
mKindFilters = query->kindFilters();
}
QueryJob::~QueryJob()
{
}
bool QueryJob::write(const String &out, Flags<WriteFlag> 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<out.size(); ++i) {
const char c = out.at(i);
switch (c) {
case '"':
case '\\':
*(ch + 1) = c;
*ch = '\\';
ch += 2;
l += 2;
break;
default:
++l;
*ch++ = c;
break;
}
}
o.truncate(l);
return writeRaw(o, flags);
} else {
return writeRaw(out, flags);
}
}
return true;
}
bool QueryJob::writeRaw(const String &out, Flags<WriteFlag> 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<void(LocationPiece, const String &)> &cb,
Flags<WriteFlag> writeFlags)
{
if (location.isNull())
return false;
Flags<Location::ToStringFlag> 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<WriteFlag> 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<WriteFlag> writeFlags)
{
Flags<Symbol::ToStringFlag> 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> &filter : mFilters) {
if (filter->match(fileId, path))
return true;
}
return false;
}
int QueryJob::run(const std::shared_ptr<Connection> &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> &filter : mFilters) {
if (filter->match(loc.fileId(), loc.path()))
return true;
}
return false;
}
return true;
}
-177
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef QueryJob_h
#define QueryJob_h
#include <regex>
#include <mutex>
#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<QueryMessage> &msg,
const std::shared_ptr<Project> &proj,
Flags<JobFlag> jobFlags = Flags<JobFlag>());
virtual ~QueryJob();
bool hasFilter() const { return mFileFilter || !mFilters.isEmpty(); }
bool hasKindFilter() const { return !mKindFilters.isEmpty(); }
bool hasPieceFilter() const { return !mPieceFilters.isEmpty(); }
List<QueryMessage::PathFilter> pathFilters() const
{
if (mQueryMessage)
return mQueryMessage->pathFilters();
return List<QueryMessage::PathFilter>();
}
Set<String> pieceFilters() const { return mPieceFilters; }
void setPieceFilters(Set<String> &&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<WriteFlag> flags = Flags<WriteFlag>());
bool write(const Symbol &symbol, Flags<WriteFlag> writeFlags = Flags<WriteFlag>());
bool write(Location location, Flags<WriteFlag> writeFlags = Flags<WriteFlag>());
enum LocationPiece {
Piece_Location,
Piece_Context,
Piece_SymbolName,
Piece_Kind,
Piece_ContainingFunctionName,
Piece_ContainingFunctionLocation
};
bool locationToString(Location location,
const std::function<void(LocationPiece, const String &)> &cb,
Flags<WriteFlag> writeFlags = Flags<WriteFlag>());
template <int StaticBufSize>
bool write(Flags<WriteFlag> writeFlags, const char *format, ...) RCT_PRINTF_WARNING(3, 4);
template <int StaticBufSize>
bool write(const char *format, ...) RCT_PRINTF_WARNING(2, 3);
Flags<JobFlag> jobFlags() const { return mJobFlags; }
void setJobFlags(Flags<JobFlag> flags) { mJobFlags = flags; }
void setJobFlag(JobFlag flag, bool on = true) { mJobFlags.set(flag, on); }
Flags<QueryMessage::Flag> queryFlags() const { return mQueryMessage ? mQueryMessage->flags() : Flags<QueryMessage::Flag>(); }
std::shared_ptr<QueryMessage> queryMessage() const { return mQueryMessage; }
Flags<Location::ToStringFlag> locationToStringFlags() const { return QueryMessage::locationToStringFlags(queryFlags()); }
bool filter(const String &val) const;
Signal<std::function<void(const String &)> > &output() { return mOutput; }
std::shared_ptr<Project> project() const { return mProject; }
virtual int execute() = 0;
int run(const std::shared_ptr<Connection> &connection = 0);
bool isAborted() const { std::lock_guard<std::mutex> lock(mMutex); return mAborted; }
void abort() { std::lock_guard<std::mutex> lock(mMutex); mAborted = true; }
std::mutex &mutex() const { return mMutex; }
const std::shared_ptr<Connection> &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<Project> &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> project;
};
mutable std::mutex mMutex;
bool mAborted;
int mLinesWritten;
bool writeRaw(const String &out, Flags<WriteFlag> flags);
std::shared_ptr<QueryMessage> mQueryMessage;
Flags<JobFlag> mJobFlags;
Signal<std::function<void(const String &)> > mOutput;
std::shared_ptr<Project> mProject;
uint32_t mFileFilter;
List<std::shared_ptr<Filter> > mFilters;
QueryMessage::KindFilters mKindFilters;
Set<String> mPieceFilters;
String mBuffer;
std::shared_ptr<Connection> mConnection;
Hash<Path, String> mContextCache;
};
RCT_FLAGS(QueryJob::JobFlag);
RCT_FLAGS(QueryJob::WriteFlag);
template <int StaticBufSize>
inline bool QueryJob::write(Flags<WriteFlag> flags, const char *format, ...)
{
va_list args;
va_start(args, format);
const String ret = String::format<StaticBufSize>(format, args);
va_end(args);
return write(ret, flags);
}
template <int StaticBufSize>
inline bool QueryJob::write(const char *format, ...)
{
va_list args;
va_start(args, format);
const String ret = String::format<StaticBufSize>(format, args);
va_end(args);
return write(ret);
}
#endif
-242
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<Location::ToStringFlag> QueryMessage::locationToStringFlags(Flags<Flag> queryFlags)
{
Flags<Location::ToStringFlag> 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<Match::Flag> 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<String, Flags<DefinitionType> > &map, bool hasWildcardsOrCategories) {
auto it = map.find(spelling);
auto matchDefinition = [&symbol](Flags<DefinitionType> f) {
f &= Definition|NotDefinition;
switch (f.cast<int>()) {
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<DefinitionType> f = Definition|NotDefinition;
Map<String, Flags<DefinitionType> > *target = &in;
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;
}
}
-292
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef QUERYMESSAGE_H
#define QUERYMESSAGE_H
#include <algorithm>
#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<Flag> flags;
Map<String, Flags<DefinitionType> > 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<PathFilter> &pathFilters() const { return mPathFilters; }
void setPathFilters(const Set<PathFilter> &filters)
{
mPathFilters = filters.toList();
std::sort(mPathFilters.begin(), mPathFilters.end());
}
#ifdef RTAGS_HAS_LUA
void setVisitASTScripts(const List<String> &scripts) { mVisitASTScripts = scripts; }
List<String> 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<Flag> flags() const { return mFlags; }
void setFlags(Flags<Flag> 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<Location::ToStringFlag> locationToStringFlags(Flags<Flag> queryFlags);
inline Flags<Location::ToStringFlag> locationToStringFlags() const { return locationToStringFlags(mFlags); }
virtual void encode(Serializer &serializer) const override;
virtual void decode(Deserializer &deserializer) override;
void setCurrentFile(const Path &currentFile) { 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<QueryMessage::Flag> mFlags;
int mMax, mMinLine, mMaxLine, mBuildIndex;
List<PathFilter> mPathFilters;
KindFilters mKindFilters;
Path mCurrentFile;
UnsavedFiles mUnsavedFiles;
int mTerminalWidth;
#ifdef RTAGS_HAS_LUA
List<String> 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<uint8_t>(filter.mode);
return s;
}
inline Deserializer &operator>>(Deserializer &s, QueryMessage::PathFilter &filter)
{
uint8_t mode;
s >> filter.pattern >> mode;
filter.mode = static_cast<QueryMessage::PathFilter::Mode>(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
File diff suppressed because it is too large. Load diff
-234
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<QueryMessage::PathFilter> &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<String> &rdmArgs() const { return mRdmArgs; }
const Path &currentFile() 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<QueryMessage::Flag> queryFlags() const { return mQueryFlags; }
int terminalWidth() const { return mTerminalWidth; }
String commandLine() const { return mCommandLine; }
void onNewMessage(const std::shared_ptr<Message> &message, const std::shared_ptr<Connection> &);
List<String> environment() const;
String codeCompletePrefix() const { return mCodeCompletePrefix; }
#ifdef RTAGS_HAS_LUA
List<String> visitASTScripts() const { return mVisitASTScripts; }
#endif
private:
void addQuery(QueryMessage::Type t, String &&query = String(),
Flags<QueryMessage::Flag> extraQueryFlags = Flags<QueryMessage::Flag>());
void addQuitCommand(int exitCode);
void addLog(LogLevel level);
void addCompile(String &&args, const Path &cwd);
void addCompile(Path &&compileCommands);
Flags<QueryMessage::Flag> mQueryFlags;
int mMax, mTimeout, mMinOffset, mMaxOffset, mConnectTimeout, mBuildIndex;
LogLevel mLogLevel;
Set<QueryMessage::PathFilter> mPathFilters;
QueryMessage::KindFilters mKindFilters;
UnsavedFiles mUnsavedFiles;
List<std::shared_ptr<RCCommand> > mCommands;
List<String> 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<String> mVisitASTScripts;
#endif
mutable List<String> mEnvironment;
String mCommandLine;
friend class CompileCommand;
};
#endif
-1278
View File
File diff suppressed because it is too large. Load diff
-1225
View File
File diff suppressed because it is too large. Load diff
-70
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#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<Connection> &conn = std::shared_ptr<Connection>())
: 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<LogFlag>, const char *msg, int len) override
{
if (mConnection) {
std::shared_ptr<EventLoop> 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> connection() const { return mConnection; }
private:
const unsigned int mFlags;
std::shared_ptr<Connection> mConnection;
};
#endif
-52
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#ifndef RTagsMessage_h
#define RTagsMessage_h
#include "rct/Message.h"
#include "rct/String.h"
#include <cstdint>
#include <string.h>
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
-9
View File
@@ -1,9 +0,0 @@
namespace RTags {
enum {
MajorVersion = @RTAGS_VERSION_MAJOR@,
MinorVersion = @RTAGS_VERSION_MINOR@,
DatabaseVersion = @RTAGS_VERSION_DATABASE@,
SourcesFileVersion = @RTAGS_VERSION_SOURCES_FILE@
};
}
-272
View File
@@ -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 <http://www.gnu.org/licenses/>. */
#include "ReferencesJob.h"
#include "Project.h"
#include "RTags.h"
#include "Server.h"
static inline Flags<QueryJob::JobFlag> jobFlags(Flags<QueryMessage::Flag> queryFlags)
{
return (queryFlags & QueryMessage::Elisp ? Flags<QueryJob::JobFlag>(QueryJob::QuoteOutput) : Flags<QueryJob::JobFlag>());
}
ReferencesJob::ReferencesJob(Location loc, const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &proj)
: QueryJob(query, proj, ::jobFlags(query->flags()))
{
mLocations.insert(loc);
}
ReferencesJob::ReferencesJob(const String &sym, const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &proj)
: QueryJob(query, proj, ::jobFlags(query->flags())), mSymbolName(sym)
{
}
int ReferencesJob::execute()
{
const bool rename = queryFlags() & QueryMessage::Rename;
std::shared_ptr<Project> proj = project();
if (!proj)
return 1;
Set<Symbol> refs;
Map<Location, std::pair<bool, CXCursorKind> > references;
if (!mSymbolName.isEmpty()) {
const bool hasFilter = QueryJob::hasFilter();
auto inserter = [this, hasFilter](Project::SymbolMatchType type, const String &string, const Set<Location> &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<String> 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<Symbol> 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<Symbol> 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<Symbol> 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<QueryJob::WriteFlag> 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<Location, std::pair<bool, CXCursorKind> >::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<RTags::SortedSymbol> sorted;
sorted.reserve(references.size());
for (Map<Location, std::pair<bool, CXCursorKind> >::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<RTags::SortedSymbol>());
} else {
std::sort(sorted.begin(), sorted.end());
}
int startIndex = 0;
const int count = sorted.size();
if (!startLocation.isNull()) {
for (int i=0; i<count; ++i) {
if (sorted.at(i).location == startLocation) {
startIndex = i + 1;
break;
}
}
}
for (int i=0; i<count; ++i) {
Location loc = sorted.at((startIndex + i) % count).location;
writeLoc(loc);
}
}
if (queryFlags() & QueryMessage::Elisp) {
write(")", DontQuote);
} else if (queryFlags() & QueryMessage::JSON) {
write(json.toJSON(), DontQuote|Unfiltered);
}
return references.isEmpty() ? 1 : 0;
}
-36
View File
@@ -1,36 +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 <http://www.gnu.org/licenses/>. */
#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<QueryMessage> &query, const std::shared_ptr<Project> &project);
ReferencesJob(const String &symbolName, const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &project);
protected:
virtual int execute() override;
private:
Set<Location> mLocations;
const String mSymbolName;
};
#endif
Loaded 100 of 225 files, more files were not shown because too many files have changed in this diff. Show more