irony-mode
irony-mode copied to clipboard
Question about C++11/14/17 auto completion
Hi Sarcasm,
Are irony able to make autocompletion of all C++11/14/17 features?
Thanks,
Levis
It should work if the appropriate -std=
option is given and if the feature is supported by your libclang version
I'm using clang 3.9.1 the latest one. When I try to use Template argument deduction for class templates:
template<typename T = float>
struct MyContainer
{
T val;
MyContainer() : val(){}
MyContainer(T val) : val (val){}
};
MyContainer c1 {1};
MyContainer c2;
Flycheck reports two errors: 27 1 error use of class template 'MyContainer' requires template arguments (irony) 28 1 error use of class template 'MyContainer' requires template arguments (irony)
I checked the clang support status for C++17 (http://clang.llvm.org/cxx_status.html) and I found that it is supported at the SVN repository and using the flag -std=c++1z. As windows user, I always take the binaries offered at http://releases.llvm.org/download.html#svn.
Which version of clang are you using, can you checked if Flycheck also reports the same to you? Thanks,
Interesting, I wasn't aware of this feature yet. the llvmweekly from today (http://llvmweekly.org/issue/164) says:
C++1z class template argument deduction is now considered 'done'. r295011.
So I guess this is pretty recent.
I built clang and libclang from today's ToT.
$ ./bin/irony-server --version
irony-server version 0.2.2-cvs
clang version 5.0.0
Once I setup the -std=c++1z
flag flycheck-irony reports the error:
error: declaration of variable 'c2' with deduced type 'MyContainer' requires an initializer (irony)
c1
is "compiling" fine.
This feature does not work with my system version of clang which is the 3.9.1 version. Since this is the version currently available for download at http://releases.llvm.org/download.html, I think you have to build from trunk yourself if you want the feature today.
Ok, good news. Questions:
- Did you build the whole LLMV?
- Where can I get LLMV latest version (the CVS source code) ?
I am not quite sure if it is possible to build LLMV in Windows using CVS. I tried long time ago but I couldn't build it. For that reason, I also take the latest pre-built binaries.
In this link you ca find more C++11/14/17 features with example: https://github.com/AnthonyCalandra/modern-cpp-features
In the past, 2013, LLVM wasn't too difficult to build on Windows. I used CMake + Ninja (like on Linux). Today, I'd like to think this is even easier.
Anyway, it also looks like there are snapshot builds available here:
- http://llvm.org/builds/
For example, today they have an a Windows installer, based on SVN r293544 (30 January 2017). If it contains libclang maybe you are already good.
Thank you.
Changing a little bit the topic. How do you detect when a .cpp or .h file is loaded in order to set up, for instance, the appropriated .clang_complete flags?
I am using the following hook (add-hook 'change-major-mode-hook #'module-headers)
to handle the problem. If a .h file is loaded the hook call the module-headers
function. The problem is that this hook is activated when a change in any emacs major mode occurs.
Is there a hook that just considers changes on c++-mode
andc-mode
or do you have any suggestion how to run a function when a .cpp or a .h file is loaded?
I'm not sure to understand the question.
I you look at irony-mode's configuration section, you have (trimmed down version):
(add-hook 'c++-mode-hook 'irony-mode)
(add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options)
This says:
- enable irony-mode when a C++ buffer is opened
- load the compilation database when irony-mode is started (which is when a C++ buffer is opened)
I'm not sure to understand the question
When a C++ buffer is opened, I search and read its associated .clang_complete
to extract the paths
where the headers are located. I use this information to setup company-c-headers. This is the reason why I use (add-hook 'change-major-mode-hook #'module-headers)
. When many buffers are opened, the hook is executed once a buffer is selected buffer. It is working, but I don't know if there is a more efficient way to do it.
Still not exactly sure.
What is the advantage of change-major-mode-hook
over c++-mode-hook
here?
I checked my function today and I'm already using the c++-mode-hook
. I commented ;;(add-hook 'change-major-mode-hook #'module-headers)
(add-hook 'c-mode-hook #'module-headers)
(add-hook 'c++-mode-hook #'module-headers)
;;(add-hook 'change-major-mode-hook #'module-headers)
Let me try to explain the problem I am facing:
-
If I open a c++ buffer from
project A
, the functionmodule-headers
is called and its associated .clang_complete is read without problems. -
Now, I open other c++ buffer from
project B
, the functionmodule-headers
is called and its respective .clang_complete is read without problems.
3. If I come back and select the c++ buffer form project A
, the function module-headers
in not called.
- If I kill the c++ buffer form project A and reopen it again, the function
module-headers
is called and its respective .clang_complete is read without problems.
Do you have any Idea how the problem (scenario 3 is where the problem is located). Maybe there is a way to execute the function when the focus changes among c++ buffers?
I don't think there is any problem with the time the function is called, it only depends on the definition of the function.
Would you mind sharing the code of this module-headers
function so I can eventually propose an educated on the first try?
The function bellow. I'm not a lisp expert as you can see. Please, let me know if I can improve it.
(defun module-headers ()
"Setup 'company-c-headers-path-user."
;;(message (format "%s" major-mode))
(when (or (equal major-mode 'c++-mode)
(equal major-mode 'minibuffer-inactive-mode)
(equal major-mode 'c-mode))
(setq company-c-headers-path-user nil)
(with-temp-buffer
(while (and (not (file-exists-p ".clang_complete"))
(not (equal ":/" (substring default-directory -2))))
(cd ".."))
(if (file-exists-p ".clang_complete")
(progn
(let ((file-content-list)
(length-item)
(ini-ref-path))
;;(message "Test: %s" default-directory)
(setq file-content-list
(read-lines (concat default-directory ".clang_complete")))
(while file-content-list
(setq length-item (length (car file-content-list)))
(when (> length-item 4)
(when (equal (substring (car file-content-list) 0 4) "-I./")
(add-to-list 'company-c-headers-path-user
(concat default-directory
(substring (car file-content-list) 4 length-item))))
(when (equal (substring (car file-content-list) 0 5) "-I../")
(setq ini-ref-path default-directory)
(cd "../")
(add-to-list 'company-c-headers-path-user
(concat default-directory
(substring (car file-content-list) 5 length-item)))
(cd ini-ref-path)))
(setq file-content-list (cdr file-content-list)))))))))
Many ways to improve! :)
Not thoroughly tested and using unsupported irony-mode functions (but they won't disappear tomorrow), but straightforward and should not exhibit the same issues as what you described:
(defun company-c-headers-path-user-irony ()
"Return the user include paths for the current buffer."
(when irony-mode
(irony--extract-user-search-paths irony--compile-options
irony--working-directory)))
(setq company-c-headers-path-user 'company-c-headers-path-user-irony)
Also note that there is a company-irony-c-headers which might already do the work.
Thank you for your feedback. I will test both tomorrow. Now I am using my tablet. What do you use for header completion?
Nothing... I should probably use one or integrate this into irony-mode (so that would simplify the company config). A long time ago irony was providing this feature but it did not survive some refactoring.
I tested both options and the first one, company-c-headers-path-user-irony
, solves my problem. The second option using company-irony-c-headers did not work.
How do you control when the focus change among C++ buffers? I would like to implement this functionality in my function module-headers
to learn more about Emacs lisp.
Oh right, I didn't even explain. You don't have to do anything when the focus change. Emacs has support for 'buffer local variable': https://www.gnu.org/software/emacs/manual/html_node/elisp/Buffer_002dLocal-Variables.html
The irony--compile-options
variable is a buffer local variable, which means there are as many "instance" of this variable as there is buffers, each buffer can give the variable a different value.
To set this variable for the *scratch*
buffer programmatically for example, you could do:
(with-current-buffer "*scratch*"
(setq irony--compile-options 1))
(with-current-buffer "*Messages*"
(setq irony--compile-options 2))
(dolist (buf-name '("*scratch*" "*Messages*"))
(with-current-buffer buf-name
(message "%s: %s" (buffer-name) irony--compile-options))
(sleep-for 1))
In your case, the variable company-c-headers-path-user
is not buffer local by default, so you need to make this variable buffer local.
There are a few ways to do this, they are explained here:
- https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Buffer_002dLocal.html
You may also be interested by http://stackoverflow.com/a/21919451/951426
Don't hesitate to share what you end up with, I can review it if you want. :+1:
Have either of you have a problem with "auto" in something like:
std::vector<std::string> theVec = { "one", "two", "three" };
std::for_each( theVec.begin(), theVec.end(), [&]( auto& ref ) { if ( ref.size() > 3 ) std::cout << "THREE!!" << std::endl; } );
I cannot seem to get completions on auto for this even when I hack in -std=c++14 in the .clang_complete.
Cheers.
@mambolevis
Hi,
is this what you are searching for?
Sorry, I mean that for some reasons I do not get completions on 'ref.' It seems that clang does not know how to resolve the auto type.
So, 'ref.' should give me completions for a std::string.
I have the following message: 'auto' not allowed in lambda parameter (irony)
from flycheck errors
I also don't get completions from ref.
Using the following flag -std=c++1z
the message from flycheck disappears.
https://clang.llvm.org/cxx_status.html
Thanks. I still cannot get completion on "ref" with c++1z, I will have to look into this a little later though.
Please, let me know if you find something.
I have the same behavior, and I think it's understandable that Clang does not get it right.
Doing M-x irony-get-type RET, shows a type of type-parameter-0-0
, which looks like a generated type name for the template argument.
IIUC, the generic lambda is converted to a template function/functor. With template we don't know the types of the argument until they are instantiated.
I believe libclang only sees a template function/functor, but does not see that it is instanciating it as well, which is where it would have the information about the type of ref
.
The right thing to do if you want this to be fixed is to propose a patch to the Clang folks. The next best thing, and with lower barrier to entry, is to submit an issue to their bug tracker, but you won't have the guarantee that someone will work on it anytime soon, but it's the right thing to do.