-
Notifications
You must be signed in to change notification settings - Fork 259
M-x company-diag
, make sureUsed backend:
includes company-lsp
.
There are at least three sets of implicit include paths. They take effect without your -I
option in .ccls
or compile_commands.json
// a.cc
// system C header, usually in /usr/include
#include <stdio.h>
// system C++ header. The location varies among distributions, e.g. /usr/include/c++/{6,7.2.1}
#include <new>
// In Clang resource directory lib/clang/7.0.0, lib/clang/7.0.0/include/stddef.h
#include <stddef.h>
Put a.cc
in some directory with echo clang++ > .ccls
. Open the file, you should be able to jump to stdio.h
new
stddef.h
when you trigger textDocument/definition
on the include lines.
Note that this might not work on Windows. To solve this, add the system include directories to compile_commands.json via your build system of choice using the INCLUDE environment variable (available after executing VsDevCmd.bat).
For CMake this can be achieved in a single line: target_include_directories(<target> SYSTEM PRIVATE $ENV{INCLUDE})
Check Clang_EXECUTABLE
in your CMakeCache.txt
. The output of command $Clang_EXECUTABLE -print-resource-dir
will be passed to -DDEFAULT_RESOURCE_DIRECTORY
. Make sure you can locate include/stddef.h
in the resource directory.
Read Initialization options how to set "cacheFormat": "json"
.
If "cacheDirectory": "/tmp/ccls"
, and the source file is /tmp/c/a.cc
,
run jq . < /tmp/ccls/@tmp@c/a.cc.json
to see if -resource-dir
is correct, e.g. "-resource-dir=/home/ray/ccls/Debug/lib/clang+llvm-6.0.0-x86_64-linux-gnu-ubuntu-16.04/lib/clang/6.0.0"
ccls infers system search paths (e.g. /usr/include
). The underneath mechanism is similar to that of clang -v -E -x c++ /dev/null
.
-isystem
system include paths is usually unnecessary. But for cross compiling or on some bizarre system you may have to specify them. A simple approach other than trial and error (changing .ccls
and restarting your editor) is to use c-index-test
.
Debug/clang+llvm-6.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/c-index-test -index-file local /tmp/c/a.cc -isystem/usr/include/c++/7.3.0 -isystemyour_include_path2
Play with your -isystem
options until you get a group of options that you can add to .ccls
If you want the ccls binary at a specific location use a symlink - do not move the binary itself.
If you want to specify additional search paths:
print '%clang\n%cpp -std=gnu++17\n-isystem/tmp/include' > .ccls
- emacs-ccls:
(setq ccls-extra-init-params '(:clang (:extraArgs ["-isystem" "/tmp/include"])))
In C++17 mode, it is possible to cause clang to crash when bits/unordered_map.h
is indexed.
See https://bugs.llvm.org/show_bug.cgi?id=37695 for details.
The workaround is to add -D__cpp_deduction_guides=0 -Wno-macro-redefined
to the initialization option clang.extraArgs
In Emacs, it is:
(setq ccls-extra-init-params
'(:clang (:extraArgs ("-D__cpp_deduction_guides=0" "-Wno-macro-redefined"))))
emacs-ccls locates the project root in the following order:
-
.ccls-root
. If this file exists in any parent directory, that directory is treated as the project root. -
(lsp--suggest-project-root)
which in turn calls(projectile-project-root)
. Usually you don't want/usr/include/c++/8/algorithm
to be treated as in the project/usr/include/c++/8/
,(setq projectile-require-project-root t)
inhibits the behavior.
The root directory is sent to ccls (the language server) through the rootUri
field in the initialize
request.
ccls reads .ccls
or compile_commands.json
in the directory. If neither exists, ccls fallbacks to %clang $path
.
proj
.ccls-root # Use this file if you want subproject files to be associated with the root project
compile_commands.json
subproj0 # without .ccls-root, files will be associated with this root directory
.git
subproj1
.git
Some projects may require more than 1000 file descriptors. Remember to increase RLIMIT_NOFILE
.
ulimit -n 32768
/etc/security/limits.conf
:
* hard nofile 32768
* soft nofile 32768
Here is an example.
include/a.h
:
int bad;
a.cc
:
int main(){return bad;}
.ccls
:
%clang
%cpp -std=gnu++14
-Iinclude
ccls will save a file in cacheDirectory
:
jq . < /tmp/ccls/@tmp@c/a.cc.json
15
{
"last_modification_time": 1520737513,
"language": 1,
"import_file": "/tmp/c/a.cc",
"args": [
"clang++",
"-working-directory=/tmp/c",
"-std=gnu++14",
"-Iinclude",
"/tmp/c/a.cc",
"-resource-dir=/home/maskray/Dev/Util/ccls/build/debug/lib/clang+llvm-6.0.0-x86_64-linux-gnu-ubuntu-14.04/lib/clang/6.0.0",
"-Wno-unknown-warning-option",
"-fparse-all-comments"
],
"includes": [
{
"line": 0,
"resolved_path": "/tmp/c/include/a.h"
}
],
"dependencies": [
"/tmp/c/include/a.h"
],
...
For efficiency, headers are compiled on their own (as if clang [options] a.h
) to utilize Clang's preamble optimization.
For headers that are not self-contained (e.g. some /usr/include/bits/*.h
which require a predefined macro) ccls emits diagnostics that you don't see when building the project.
// a.c
#define M
#include "a.h"
// a.h
#ifndef M
#error M not defined
#endif
One approach ccls explored before was to compile its import file a.c
, but it caused severe performance issues for some projects.
For smaller files this does not matter and checking for a header guard may help the situation.
A header can be included in different translation units with different compiler flags. It may behave differently via #ifdef
.
Ideally, there should be some mechanism to switch among different views (compiler flags) when you are editing the file.
For efficiency, a header is only indexed with one set of compiler flags, so either the #if
block or #else
is indexed, the other is left blank.
For macros, there is code to track different usage, thus you may find them able to jump to multiple targets.
index.multiVersion
is an experimental option to index every version to certify that the author is aware of this issue :)
It may not be very useful though. It is of type number
but not boolean
as the author is also aware of other dimensions of the multi-version problem.
textDocument/definition
can be used in many places. Some are current implementation details and may subject to change.
-
void foo();
A declaration jumps to the definition -
void foo() {}
The definition lists all declarations -
A a;
For variables of custom types, besides declarations of the variable, both the type and the variable jump to the declaration/definition of its typeA
-
class C {
jumps to declarations (and constructors/destructors) -
a.field
jumps to the member in the struct declaration -
#include <map>
jumps to the header -
std::string a = "a";
takes you to the constructor. Many implicit constructors can also be jumped in this way. -
a == b
operator==
for user defined operators -
namespace ns {
find original or extension namespaces -
// ns::foo
in comments, it recognizes the identifier around the cursor, approximately finds the best matching symbol and jumps to it; onns
, it jumps to the namespace
-
#include <iostream>
lists all#include
lines in the project pointing to the included file -
[](){}
lists all(?) lambda expressions thanks to implicitstd::function
move constructor -
extern int a;
IfReferenceContext.includeDeclaration
is true, the definition and declarations are also listed. - If no references is found but the point is on the first line, list
#include
lines referencing current file.
-
struct B{virtual void f();};
derived classes or virtual function overrides
-
A a;
lists all instances of user-definedA
. -
int i;
lists all instances ofint
.
Find callers. If parameter callee:true
is specified, find callees instead.
Specify hierarchy:true
to enable hierarchical view.
Find base classes/overriden functions. If parameter derived:true
is specified, find derived classes/functions instead.
It also works fine for jumping between primary template and partial specialization.
Specify hierarchy:true
to enable hierarchical view.
Recursively list member variables of a record type. 😂 nobody has implemented vscode-ccls UI for the feature. Help wanted!
-
struct A:B{void f()override;};
listsB
orB::f()
If parameter kind:3
is specified, list member functions/functions in a namespace
-
struct A{void f();};
listsA::f()