diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..0be97f5fe9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +massif.out.* +.vscode +.devcontainer +build/ +bin/ \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000000..d43672257e --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,25 @@ +name: pull_request + +on: [pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Unshallow + run: git fetch --prune --unshallow && git submodule update --init --recursive + - uses: docker/setup-buildx-action@v1 + - name: Docker login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Just build (no push) + id: docker_build + uses: docker/build-push-action@v2 + with: + push: false + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..faa1655973 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: release + +on: + push: + branches: + - llvmorg-10.0.0-lsif-clang + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Unshallow + run: git fetch --prune --unshallow && git submodule update --init --recursive + - uses: docker/setup-buildx-action@v1 + - name: Docker login + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Build and push + id: docker_build + uses: docker/build-push-action@v2 + with: + push: true + tags: sourcegraph/lsif-clang:latest + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..33b563f521 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +massif.out.* +vgcore.* +valgrind* +.clangd +.cache +bin +build +cmake-build-debug* +.clangd +compile_commands.json +dump.lsif diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..5fe1420c7f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/indexer/backward-cpp"] + path = src/indexer/backward-cpp + url = https://github.com/bombela/backward-cpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 069a0aee90..407381f9ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.16) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_BUILD_TYPE RelWithDebInfo) +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -DNDEBUG -g") include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..2e49eb8719 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:20.10 as build + +RUN apt update && apt install -y llvm-10 clang-10 libclang-10-dev cmake + +WORKDIR /lsif-clang + +COPY . . + +RUN CC=clang-10 CXX=clang-10 cmake -B build && make -C build -j$(nproc) + +FROM ubuntu:20.10 + +RUN apt update && apt install -y libllvm10 cmake clang-10 + +# Might as well set this, for auto-index purposes +ENV DEBIAN_FRONTEND=noninteractive + +COPY --from=build /lsif-clang/bin/lsif-clang /usr/local/bin/lsif-clang + +ENTRYPOINT [ "lsif-clang" ] \ No newline at end of file diff --git a/README.md b/README.md index 94de7299fe..686dbe3c02 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# lsif-clang indexer ![Status: Development](https://img.shields.io/badge/status-development-yellow?style=flat) +# lsif-clang indexer ![Status: Development](https://img.shields.io/badge/status-beta-yellow?style=flat) -![GIF displaying usage on the linux kernel.](docs/gifs/torvalds-linux.gif) +![GIF displaying usage on the linux kernel.](docs/images/torvalds-linux.gif) This project is a fork of [clangd](https://clangd.llvm.org/) with patches to add support for outputting [LSIF indexes](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.5.0/specification/). Specifically, a fork of the `clang-tools-extra/clangd` subdirectory of the [llvm-project repo](https://github.com/llvm/llvm-project/). diff --git a/docs/compdb.md b/docs/compdb.md index 41309010c4..4dd1e37d86 100644 --- a/docs/compdb.md +++ b/docs/compdb.md @@ -36,11 +36,11 @@ http_archive( ``` Then you can run: -``` +```bash bazel build \ --aspects=@bazel_compdb//:aspects.bzl%compilation_database_aspect \ - --output_groups=compdb_files,header_files `# this should include any generated outputs needed for cpp compilation` \ - $(bazel query 'kind("cc_(library|binary|test|inc_library|proto_library)", //...)')' + --output_groups=compdb_files,header_files \ # this should include any generated outputs needed for cpp compilation + $(bazel query 'kind("cc_(library|binary|test|inc_library|proto_library)", //...)') ``` The bazel query might look different for your project. diff --git a/docs/examples.md b/docs/examples.md index 442b0c5ff6..e39f507b56 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -4,13 +4,13 @@ This page provides examples of generating compile_commands.json files for differ ## [github.com/torvalds/linux](https://github.com/torvalds/linux) -![GIF displaying usage on the linux kernel.](gifs/torvalds-linux.gif) +![GIF displaying usage on the linux kernel.](images/torvalds-linux.gif) Once you've installed the kernel dependencies (you can use the table in `Documentation/process/changes.rst`), run the following commands from the repository root: ```sh make allyesconfig -make CC=clang-10 HOSTCC=clang-10 `# replace with your clang version` -scripts/gen_compile_commands.py +make CC=clang-10 HOSTCC=clang-10 # replace with your clang version +scripts/clang-tools/gen_compile_commands.py lsif-clang compile_commands.json ``` @@ -18,7 +18,7 @@ lsif-clang compile_commands.json Use the following steps: ```sh -./bazel/setup_clang.sh /usr/lib/llvm-10 `# or wherever your llvm installation lives` +./bazel/setup_clang.sh /usr/lib/llvm-10 # or wherever your llvm installation lives echo 'build --config=clang' > user.bazelrc TEST_TMPDIR=/tmp tools/gen_compilation_database.py --include_headers --run_bazel_build lsif-clang compile_commands.json @@ -28,6 +28,6 @@ lsif-clang compile_commands.json Install the [Ninja build tool](https://ninja-build.org/), and run the following commands from the repository root: ```sh cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Dgrpc_BUILD_TESTS=ON -G Ninja -ninja -C build $(egrep -e '^build[^:]+.pb.(cc|h|c|cpp|inc|hpp)[: ]' build/build.ninja | awk '{print $2}') `# generate pb` +ninja -C build $(egrep -e '^build[^:]+.pb.(cc|h|c|cpp|inc|hpp)[: ]' build/build.ninja | awk '{print $2}') # generate pb lsif-clang build/compile_commands.json ``` diff --git a/docs/images/stacktrace.png b/docs/images/stacktrace.png new file mode 100644 index 0000000000..ac4c056d3e Binary files /dev/null and b/docs/images/stacktrace.png differ diff --git a/docs/gifs/torvalds-linux.gif b/docs/images/torvalds-linux.gif similarity index 100% rename from docs/gifs/torvalds-linux.gif rename to docs/images/torvalds-linux.gif diff --git a/docs/install.md b/docs/install.md index b3069196f6..b95c0f8a4e 100644 --- a/docs/install.md +++ b/docs/install.md @@ -5,7 +5,7 @@ This project depends on LLVM and Clang. lsif-clang itself should be built agains ### Ubuntu (20.04) ```sh -apt install llvm-10 clang clang-10 libclang-10-dev cmake +apt install llvm-10 clang clang-10 libclang-10-dev cmake binutils-dev ``` #### Older versions of Ubuntu @@ -19,13 +19,15 @@ don't exist in the `apt` package repository. ### MacOS ```sh -brew install cmake sourcegraph/brew/llvm@10 +brew install cmake sourcegraph/brew/llvm@10 binutils ``` > Note: lsif-clang must currently be built using LLVM 10 # Installation +Make sure to checkout any submodules, either with `git clone --recurse-submodules ...` or `git submodule update --init --recursive` + ### Ubuntu ```sh diff --git a/docs/segfault.md b/docs/segfault.md new file mode 100644 index 0000000000..cf284a55ae --- /dev/null +++ b/docs/segfault.md @@ -0,0 +1,48 @@ +# How to troubleshoot a segfault + +This document outlines how to configure your system to provide enough information to debug lsif-clang in the case of a segfault. + +## Information to be provided + +Along with the information gathered by reading the section below, please also provide: + +1. lsif-clang version (commit/tag/etc) +1. Output of `ldd ` +1. lsif-clang source (self-compiled/docker/prebuilt binary) + - In the case of self-compiled, it may be useful to attach the binary in the bug report +1. One or both of the below (stacktrace/core dump) + +## Stacktrace + +The lsif-clang indexer has the ability to emit a detailed stacktrace (when possible) as shown in the screenshot below if a segfault is encountered. In the case of the stacktrace not being annotated with source fragments as shown below, we may also ask for a core dump. To shorten the feedback loop, it can be beneficial to include the core dump with the original bug report. + +![stacktrace in terminal](images/stacktrace.png) + +## Core dump + +If there's no stacktrace, then the next option is to configure the OS to save a core dump on segfault. + +As the process is a bit more involved, we will outline general guidelines for coercing the system to save a core dump. + +### Linux + +1. Run `ulimit -c unlimited` +1. Check the core-dump handler + - You can find the configured handler by running `cat /proc/sys/kernel/core_pattern` + - The output can be either a path with format verbs or a path prefixed by `|` followed by format verbs + - If the latter, then the binary at that path will be invoked with the core dump and you should read the manual for the given program as to where it stores core dumps and how to proper configure it to do so + - Else if the former, assuming the aforementioned `ulimit` command was invoked, then it should save the file at that location with the filename based on the format verbs passed + - e.g `/tmp/core-%e.%p.%h.%t` vs `|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h` +1. Configure the core-dump handler (if necessary) + - This can be done by running `sysctl -w kernel.core_pattern=` as root + +### Docker + +If invoking `lsif-clang` from a docker container, the core dump settings are inherited from the host OS (or VM if Mac/Windows). +In this case, it is highly recommended to configure the core pattern to save to a file that can be copied to the host from the container. + +### Mac OS + +1. Run `ulimit -c unlimited` +1. Make sure `/cores` directory is writeable by the current user +1. And that should be it : ) diff --git a/src/index/LSIFSerialization.cpp b/src/index/LSIFSerialization.cpp index 6ff6774de9..dc15fd624d 100644 --- a/src/index/LSIFSerialization.cpp +++ b/src/index/LSIFSerialization.cpp @@ -64,10 +64,11 @@ template <> struct DenseMapInfo { namespace { struct LSIFMeta { LSIFMeta(llvm::raw_ostream &OS, const clang::clangd::IndexFileOut &O) - : OS(OS), ProjectRoot(O.ProjectRoot), Debug(O.Debug) {} + : OS(OS), ProjectRoot(O.ProjectRoot), Debug(O.Debug), DebugFiles(O.DebugFiles) {} llvm::raw_ostream &OS; const std::string ProjectRoot; const bool Debug; + const bool DebugFiles; int IDCounter = 0; llvm::StringMap DocumentIDs; llvm::DenseMap ReferenceResultIDs; @@ -76,6 +77,9 @@ struct LSIFMeta { bool contains(const char *FileURI) { bool contains = FileURI && llvm::StringRef(FileURI).startswith(ProjectRoot); + if (!contains && DebugFiles) { + llvm::errs() << "Ignoring file: " << llvm::StringRef(FileURI) << "\n"; + } return contains; } }; @@ -254,8 +258,13 @@ void writeHoverResult(LSIFMeta &Meta, const clang::clangd::Symbol &Sym, JSONOut.attribute("value", OHover.str()); }); - if (Sym.Documentation.data() && !Sym.Documentation.empty()) - JSONOut.value(Sym.Documentation); + if (Sym.Documentation.data() && !Sym.Documentation.empty()) { + auto docString = Sym.Documentation; + if(!llvm::json::isUTF8(docString)) { + docString = llvm::StringRef(llvm::json::fixUTF8(Sym.Documentation)); + } + JSONOut.value(docString); + } }); }); }); diff --git a/src/index/Merge.cpp b/src/index/Merge.cpp index 0cef7dc763..6a6889836d 100644 --- a/src/index/Merge.cpp +++ b/src/index/Merge.cpp @@ -22,139 +22,10 @@ namespace clang { namespace clangd { -// FIXME: Deleted symbols in dirty files are still returned (from Static). -// To identify these eliminate these, we should: -// - find the generating file from each Symbol which is Static-only -// - ask Dynamic if it has that file (needs new SymbolIndex method) -// - if so, drop the Symbol. -bool MergedIndex::fuzzyFind( - const FuzzyFindRequest &Req, - llvm::function_ref Callback) const { - // We can't step through both sources in parallel. So: - // 1) query all dynamic symbols, slurping results into a slab - // 2) query the static symbols, for each one: - // a) if it's not in the dynamic slab, yield it directly - // b) if it's in the dynamic slab, merge it and yield the result - // 3) now yield all the dynamic symbols we haven't processed. - trace::Span Tracer("MergedIndex fuzzyFind"); - bool More = false; // We'll be incomplete if either source was. - SymbolSlab::Builder DynB; - unsigned DynamicCount = 0; - unsigned StaticCount = 0; - unsigned MergedCount = 0; - More |= Dynamic->fuzzyFind(Req, [&](const Symbol &S) { - ++DynamicCount; - DynB.insert(S); - }); - SymbolSlab Dyn = std::move(DynB).build(); - - llvm::DenseSet SeenDynamicSymbols; - More |= Static->fuzzyFind(Req, [&](const Symbol &S) { - auto DynS = Dyn.find(S.ID); - ++StaticCount; - if (DynS == Dyn.end()) - return Callback(S); - ++MergedCount; - SeenDynamicSymbols.insert(S.ID); - Callback(mergeSymbol(*DynS, S)); - }); - SPAN_ATTACH(Tracer, "dynamic", DynamicCount); - SPAN_ATTACH(Tracer, "static", StaticCount); - SPAN_ATTACH(Tracer, "merged", MergedCount); - for (const Symbol &S : Dyn) - if (!SeenDynamicSymbols.count(S.ID)) - Callback(S); - return More; -} - -void MergedIndex::lookup( - const LookupRequest &Req, - llvm::function_ref Callback) const { - trace::Span Tracer("MergedIndex lookup"); - SymbolSlab::Builder B; - - Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); }); - - auto RemainingIDs = Req.IDs; - Static->lookup(Req, [&](const Symbol &S) { - const Symbol *Sym = B.find(S.ID); - RemainingIDs.erase(S.ID); - if (!Sym) - Callback(S); - else - Callback(mergeSymbol(*Sym, S)); - }); - for (const auto &ID : RemainingIDs) - if (const Symbol *Sym = B.find(ID)) - Callback(*Sym); -} - -bool MergedIndex::refs(const RefsRequest &Req, - llvm::function_ref Callback) const { - trace::Span Tracer("MergedIndex refs"); - bool More = false; - uint32_t Remaining = - Req.Limit.getValueOr(std::numeric_limits::max()); - // We don't want duplicated refs from the static/dynamic indexes, - // and we can't reliably deduplicate them because offsets may differ slightly. - // We consider the dynamic index authoritative and report all its refs, - // and only report static index refs from other files. - // - // FIXME: The heuristic fails if the dynamic index contains a file, but all - // refs were removed (we will report stale ones from the static index). - // Ultimately we should explicit check which index has the file instead. - llvm::StringSet<> DynamicIndexFileURIs; - More |= Dynamic->refs(Req, [&](const Ref &O) { - DynamicIndexFileURIs.insert(O.Location.FileURI); - Callback(O); - assert(Remaining != 0); - --Remaining; - }); - if (Remaining == 0 && More) - return More; - // We return less than Req.Limit if static index returns more refs for dirty - // files. - bool StaticHadMore = Static->refs(Req, [&](const Ref &O) { - if (DynamicIndexFileURIs.count(O.Location.FileURI)) - return; // ignore refs that have been seen from dynamic index. - if (Remaining == 0) { - More = true; - return; - } - --Remaining; - Callback(O); - }); - return More || StaticHadMore; -} - -void MergedIndex::relations( - const RelationsRequest &Req, - llvm::function_ref Callback) const { - uint32_t Remaining = - Req.Limit.getValueOr(std::numeric_limits::max()); - // Return results from both indexes but avoid duplicates. - // We might return stale relations from the static index; - // we don't currently have a good way of identifying them. - llvm::DenseSet> SeenRelations; - Dynamic->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) { - Callback(Subject, Object); - SeenRelations.insert(std::make_pair(Subject, Object.ID)); - --Remaining; - }); - if (Remaining == 0) - return; - Static->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) { - if (Remaining > 0 && - !SeenRelations.count(std::make_pair(Subject, Object.ID))) { - --Remaining; - Callback(Subject, Object); - } - }); -} - // Returns true if \p L is (strictly) preferred to \p R (e.g. by file paths). If // neither is preferred, this returns false. -bool prefer(const SymbolLocation &L, const SymbolLocation &R) { +bool prefer(const SymbolLocation &L, const SymbolLocation &R, + const std::string &ProjectRoot) { if (!L) return false; if (!R) @@ -166,10 +37,15 @@ bool prefer(const SymbolLocation &L, const SymbolLocation &R) { return llvm::StringRef(Loc.FileURI).endswith(Suffix); }); }; - return HasCodeGenSuffix(L) && !HasCodeGenSuffix(R); + auto InProject = [ProjectRoot](const SymbolLocation &Loc) { + return Loc.FileURI && llvm::StringRef(Loc.FileURI).startswith(ProjectRoot); + }; + + return (HasCodeGenSuffix(L) && !HasCodeGenSuffix(R)) || (InProject(L) && !InProject(R)); } -Symbol mergeSymbol(const Symbol &L, const Symbol &R) { +Symbol mergeSymbol(const Symbol &L, const Symbol &R, + const std::string &ProjectRoot) { assert(L.ID == R.ID); // We prefer information from TUs that saw the definition. // Classes: this is the def itself. Functions: hopefully the header decl. @@ -184,9 +60,9 @@ Symbol mergeSymbol(const Symbol &L, const Symbol &R) { const Symbol &O = PreferR ? L : R; // The "other" less-preferred symbol. // Only use locations in \p O if it's (strictly) preferred. - if (prefer(O.CanonicalDeclaration, S.CanonicalDeclaration)) + if (prefer(O.CanonicalDeclaration, S.CanonicalDeclaration, ProjectRoot)) S.CanonicalDeclaration = O.CanonicalDeclaration; - if (prefer(O.Definition, S.Definition)) + if (prefer(O.Definition, S.Definition, ProjectRoot)) S.Definition = O.Definition; S.References += O.References; if (S.Signature == "") diff --git a/src/index/Merge.h b/src/index/Merge.h index 3288aef120..b383b09444 100644 --- a/src/index/Merge.h +++ b/src/index/Merge.h @@ -17,38 +17,8 @@ namespace clangd { // Merge symbols L and R, preferring data from L in case of conflict. // The two symbols must have the same ID. // Returned symbol may contain data owned by either source. -Symbol mergeSymbol(const Symbol &L, const Symbol &R); - -// MergedIndex is a composite index based on two provided Indexes: -// - the Dynamic index covers few files, but is relatively up-to-date. -// - the Static index covers a bigger set of files, but is relatively stale. -// The returned index attempts to combine results, and avoid duplicates. -// -// FIXME: We don't have a mechanism in Index to track deleted symbols and -// refs in dirty files, so the merged index may return stale symbols -// and refs from Static index. -class MergedIndex : public SymbolIndex { - const SymbolIndex *Dynamic, *Static; - -public: - // The constructor does not access the symbols. - // It's safe to inherit from this class and pass pointers to derived members. - MergedIndex(const SymbolIndex *Dynamic, const SymbolIndex *Static) - : Dynamic(Dynamic), Static(Static) {} - - bool fuzzyFind(const FuzzyFindRequest &, - llvm::function_ref) const override; - void lookup(const LookupRequest &, - llvm::function_ref) const override; - bool refs(const RefsRequest &, - llvm::function_ref) const override; - void relations(const RelationsRequest &, - llvm::function_ref) - const override; - size_t estimateMemoryUsage() const override { - return Dynamic->estimateMemoryUsage() + Static->estimateMemoryUsage(); - } -}; +Symbol mergeSymbol(const Symbol &L, const Symbol &R, + const std::string &ProjectRoot); } // namespace clangd } // namespace clang diff --git a/src/index/Serialization.h b/src/index/Serialization.h index 149977685a..deb5e63f1b 100644 --- a/src/index/Serialization.h +++ b/src/index/Serialization.h @@ -63,6 +63,7 @@ struct IndexFileOut { IndexFileFormat Format = IndexFileFormat::RIFF; std::string ProjectRoot = ""; bool Debug = false; + bool DebugFiles = false; const tooling::CompileCommand *Cmd = nullptr; IndexFileOut() = default; diff --git a/src/indexer/CMakeLists.txt b/src/indexer/CMakeLists.txt index 6daba144c4..3798f1583f 100644 --- a/src/indexer/CMakeLists.txt +++ b/src/indexer/CMakeLists.txt @@ -1,8 +1,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backward-cpp) + add_executable(lsif-clang - IndexerMain.cpp - ) + IndexerMain.cpp + ${BACKWARD_ENABLE} +) + +add_backward(lsif-clang) install(TARGETS lsif-clang) diff --git a/src/indexer/IndexerMain.cpp b/src/indexer/IndexerMain.cpp index 0621f5e0c4..c5ddfec6df 100644 --- a/src/indexer/IndexerMain.cpp +++ b/src/indexer/IndexerMain.cpp @@ -32,6 +32,8 @@ #include "llvm/Support/raw_ostream.h" #include +#define BACKWARD_HAS_DWARF 1 + using namespace clang::tooling; using namespace llvm; @@ -53,9 +55,12 @@ static cl::opt static cl::opt DebugArg("debug", cl::desc("Enable verbose debug output."), cl::init(false), cl::cat(LSIFClangCategory)); +static cl::opt DebugFilesArg("debug-files", cl::desc("Debug files being processed."), + cl::init(false), cl::cat(LSIFClangCategory)); + class IndexActionFactory : public FrontendActionFactory { public: - IndexActionFactory(clang::clangd::IndexFileIn &Result) : Result(Result) {} + IndexActionFactory(clang::clangd::IndexFileIn &Result, std::string &ProjectRoot) : Result(Result), ProjectRoot(ProjectRoot) {} std::unique_ptr create() override { clang::clangd::SymbolCollector::Options Opts; @@ -76,7 +81,7 @@ class IndexActionFactory : public FrontendActionFactory { std::lock_guard Lock(SymbolsMu); for (const auto &Sym : S) { if (const auto *Existing = Symbols.find(Sym.ID)) - Symbols.insert(mergeSymbol(*Existing, Sym)); + Symbols.insert(mergeSymbol(*Existing, Sym, ProjectRoot)); else Symbols.insert(Sym); } @@ -112,22 +117,22 @@ class IndexActionFactory : public FrontendActionFactory { clang::clangd::SymbolSlab::Builder Symbols; clang::clangd::RefSlab::Builder Refs; clang::clangd::RelationSlab::Builder Relations; + std::string &ProjectRoot; }; int main(int argc, const char **argv) { - sys::PrintStackTraceOnErrorSignal(argv[0]); + //sys::PrintStackTraceOnErrorSignal(argv[0]); CommonOptionsParser OptionsParser(argc, argv, LSIFClangCategory, cl::OneOrMore); std::string ProjectRoot = ProjectRootArg; if (ProjectRoot == "") { - SmallString<128> CurrentPath; + SmallString<1024> CurrentPath; sys::fs::current_path(CurrentPath); - ProjectRoot = std::string("file://") + CurrentPath.c_str(); - } else if (ProjectRoot.rfind("file://", 0) != 0) { - ProjectRoot = std::string("file://") + ProjectRoot; + ProjectRoot = std::string(CurrentPath.c_str()); } + ProjectRoot = clang::clangd::URI("file", "", ProjectRoot).toString(); if (DebugArg) { llvm::errs() << "Using project root " << ProjectRoot << "\n"; } @@ -139,9 +144,13 @@ int main(int argc, const char **argv) { // Collect symbols found in each translation unit, merging as we go. clang::clangd::IndexFileIn Data; - AllTUsToolExecutor Executor(OptionsParser.getCompilations(), 0); + auto& compilations = OptionsParser.getCompilations(); + if (compilations.getAllFiles().size() == 0) { + exit(1); + } + AllTUsToolExecutor Executor(compilations, 0); auto Err = - Executor.execute(std::make_unique(Data), Adjuster); + Executor.execute(std::make_unique(Data, ProjectRoot), Adjuster); if (Err) { } @@ -149,6 +158,7 @@ int main(int argc, const char **argv) { clang::clangd::IndexFileOut Out(Data); Out.Format = clang::clangd::IndexFileFormat::LSIF; Out.Debug = DebugArg; + Out.DebugFiles = DebugFilesArg; Out.ProjectRoot = ProjectRoot; if (!IndexDestinationArg.empty()) { std::error_code FileErr; diff --git a/src/indexer/backward-cpp b/src/indexer/backward-cpp new file mode 160000 index 0000000000..27a89004a8 --- /dev/null +++ b/src/indexer/backward-cpp @@ -0,0 +1 @@ +Subproject commit 27a89004a86fe2a665f041c198c7fbab7489e278