From ac02a00cb79f07a93d8fd1fdceb0d7dba01ee07b Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Tue, 2 May 2017 22:10:06 -0400 Subject: [PATCH 01/10] Initial implementation of xref. --- irony-xref.el | 119 ++++++++++++++++++++++++++++++++++++++++ server/CMakeLists.txt | 2 + server/src/Command.cpp | 10 ++++ server/src/Commands.def | 2 + server/src/Irony.cpp | 94 +++++++++++++++++++++++++++++++ server/src/Irony.h | 3 + server/src/TUManager.h | 5 ++ server/src/main.cpp | 8 +++ 8 files changed, 243 insertions(+) create mode 100644 irony-xref.el diff --git a/irony-xref.el b/irony-xref.el new file mode 100644 index 00000000..7b298186 --- /dev/null +++ b/irony-xref.el @@ -0,0 +1,119 @@ +;;; irony-xref.el --- Irony xref interface +;; +;;; Commentary: +;; +;;; Code: + +(require 'irony) +(require 'irony-completion) + +(require 'xref) +(require 'dash) + + +;; +;; IO tasks +;; + +(irony-iotask-define-task irony--t-find-definitions + "`xref' server command." + :start (lambda (line col) + (irony--server-send-command "xref" line col)) + :update irony--server-query-update) + +(irony-iotask-define-task irony--t-find-references + "`grep' server command." + :start (lambda (line col) + (irony--server-send-command "grep" line col)) + :update irony--server-query-update) + + +;; +;; Functions +;; + +;;;###autoload +(defun irony-find-definitions (&optional pos) + (interactive) + (let* ((line-column (irony--completion-line-column pos)) + (line (car line-column)) + (column (cdr line-column))) + (irony--run-task + (irony-iotask-chain + (irony--parse-task) + (irony-iotask-package-task irony--t-find-definitions line column))))) + +;;;###autoload +(defun irony-find-references (&optional pos) + (interactive) + (let* ((line-column (irony--completion-line-column pos)) + (result (irony--run-task + (irony-iotask-chain + (irony--parse-task) + (irony-iotask-package-task irony--t-find-references + (car line-column) (cdr line-column)))))) + (cl-loop for item in result + do (message "%S" item)))) + + +;; +;; Xref backend +;; + +;;;###autoload +(defun irony--xref-backend () 'irony) + +;; (add-hook 'irony-mode (lambda () (add-hook 'xref-backend-functions #'irony--xref-backend nil t))) + +(cl-defmethod xref-backend-identifier-at-point ((_backend (eql irony))) + ;; FIXME These propertized strings are not suitable for completion + ;; FIXME which xref asks for + (let* ((bounds (irony-completion-symbol-bounds)) + (start (car bounds)) + (end (cdr bounds)) + ;; FIXME Is (buffer-file-name) the right thing here? + (file (buffer-file-name)) + (buffer (current-buffer)) + (line-column (irony--completion-line-column start)) + (thing (buffer-substring-no-properties start end))) + (put-text-property 0 (length thing) 'irony-xref (list file buffer start end) thing) + thing)) + +(cl-defmethod xref-backend-definitions ((_backend (eql irony)) identifier) + (-when-let* + ((thing (get-text-property 0 'irony-xref identifier)) + (buffer (nth 1 thing)) + (line-column (irony--completion-line-column (nth 2 thing))) + (result + ;; Must be synchronous + (irony--run-task + (irony-iotask-chain + (irony--parse-task buffer) + (irony-iotask-package-task irony--t-find-definitions + (car line-column) (cdr line-column)))))) + (cl-loop + for (kind name filename line column start end) in result + collect + (xref-make name (xref-make-file-location filename line column)) + do (message "result: %S" (list kind name filename line column start end))))) + +(cl-defmethod xref-backend-references ((_backend (eql irony)) identifier) + (-when-let* + ((thing (get-text-property 0 'irony-xref identifier)) + (buffer (nth 1 thing)) + (line-column (irony--completion-line-column (nth 2 thing))) + (result + ;; Must be synchronous + (irony--run-task + (irony-iotask-chain + (irony--parse-task buffer) + (irony-iotask-package-task irony--t-find-references + (car line-column) (cdr line-column)))))) + (cl-loop + for (kind name filename line column start end) in result + collect + (xref-make name (xref-make-file-location filename line column)) + do (message "result: %S" (list kind name filename line column start end))))) + +(provide 'irony-xref) +;;; irony-xref.el ends here diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index a1838d8e..e24a8060 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -14,6 +14,8 @@ include(CTest) check_for_in_source_build() release_as_default_build_type() +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -fsanitize=address -fsanitize=undefined -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-prototypes -Wno-shadow-field-in-constructor") + # Disable exception, we aren't using them and right now clang-cl needs them # disabled to parse Windows headers. # diff --git a/server/src/Command.cpp b/server/src/Command.cpp index a3c35c87..344b6eba 100644 --- a/server/src/Command.cpp +++ b/server/src/Command.cpp @@ -188,6 +188,16 @@ Command *CommandParser::parse(const std::vector &argv) { std::vector> positionalArgs; switch (command_.action) { + case Command::Xref: + positionalArgs.push_back(UnsignedIntConverter(&command_.line)); + positionalArgs.push_back(UnsignedIntConverter(&command_.column)); + break; + + case Command::Grep: + positionalArgs.push_back(UnsignedIntConverter(&command_.line)); + positionalArgs.push_back(UnsignedIntConverter(&command_.column)); + break; + case Command::SetDebug: positionalArgs.push_back(OptionConverter(&command_.opt)); break; diff --git a/server/src/Commands.def b/server/src/Commands.def index f99d8af1..de3e2993 100644 --- a/server/src/Commands.def +++ b/server/src/Commands.def @@ -15,6 +15,8 @@ X(Candidates, "candidates", "PREFIX STYLE - print completion candidates (require previous complete). " "STYLE is \"exact\", \"case-insensitive\" or \"smart-case\"") +X(Xref, "xref", "LINE COL - print definition/reference of what is at the given location") +X(Grep, "grep", "LINE COL - print all uses of what is at the given location") X(Complete, "complete", "FILE LINE COL [-- [COMPILE_OPTIONS...]] - perform code completion at a given location") X(CompletionDiagnostics, "completion-diagnostics", diff --git a/server/src/Irony.cpp b/server/src/Irony.cpp index fcb877c2..12d197a1 100644 --- a/server/src/Irony.cpp +++ b/server/src/Irony.cpp @@ -649,3 +649,97 @@ void Irony::getCompileOptions(const std::string &buildDir, clang_CompilationDatabase_dispose(db); #endif } + +void ppCursor(std::string label, CXCursor cursor) { + if (clang_Cursor_isNull(cursor)) { + // std::cout << "(" << label << ")\n"; + return; + } + CXString name = clang_getCursorDisplayName(cursor); + CXSourceRange loc = clang_getCursorExtent(cursor); + CXSourceLocation start = clang_getRangeStart(loc), + end = clang_getRangeEnd(loc); + CXFile file; + unsigned start_line, start_col, start_offset, end_offset; + clang_getSpellingLocation(start, &file, &start_line, &start_col, + &start_offset); + clang_getSpellingLocation(end, nullptr, nullptr, nullptr, &end_offset); + CXString filename = clang_getFileName(file); + std::cout << "(" << label << " " << support::quoted(clang_getCString(name)) + << " " << support::quoted(clang_getCString(filename)) << " " + << start_line << " " << start_col << " " << start_offset << " " + << end_offset << ")\n"; + clang_disposeString(name); + clang_disposeString(filename); +} + +void Irony::xref(unsigned line, unsigned col) const { + if (activeTu_ == nullptr) { + std::clog << "W: get-type - parse wasn't called\n"; + std::cout << "nil\n"; + return; + } + + // std::cerr << "xref:" << line << ":" << col << std::endl; + std::cout << "("; + + CXFile cxFile = clang_getFile(activeTu_, file_.c_str()); + CXCursor c = clang_getCursor(activeTu_, + clang_getLocation(activeTu_, cxFile, line, col)); + + // CXTranslationUnit tu = tuManager_.getOrCreateTU(file, flags, + // cxUnsavedFiles_); + // CXFile f = clang_getFile(tu, file.c_str()); + // CXSourceLocation s = clang_getLocation(tu, f, line, col); + // CXCursor c = clang_getCursor(tu, s); + + // std::cerr << "getCursorSpelling(c): " + // << clang_getCString(clang_getCursorSpelling(c)) << std::endl; + // std::cerr << "getCursorDisplayName(c): " + // << clang_getCString(clang_getCursorDisplayName(c)) << std::endl; + // std::cerr << "getCursorUSR(c): " << clang_getCString(clang_getCursorUSR(c)) + // << std::endl; + + CXCursor def = clang_getCursorDefinition(c), + ref = clang_getCursorReferenced(c); + ppCursor("reference", ref); + if (!clang_Cursor_isNull(def) && !clang_equalCursors(def, ref)) { + ppCursor("definition", def); + } + + std::cout << ")" << std::endl; +} + +void Irony::grep(unsigned line, unsigned col) const { + if (activeTu_ == nullptr) { + std::clog << "W: get-type - parse wasn't called\n"; + std::cout << "nil\n"; + return; + } + CXFile cxFile = clang_getFile(activeTu_, file_.c_str()); + CXCursor what = clang_getCursor(activeTu_, clang_getLocation(activeTu_, cxFile, line, col)); + what = clang_getCanonicalCursor(clang_getCursorReferenced(what)); + + std::cout << "("; + + for (auto file_tu : tuManager_.allAvailableTranslationUnits()) { + + CXCursor tuCursor = clang_getTranslationUnitCursor(file_tu.second); + // std::cerr << "\n" << file_tu.first << ": " << clang_getCString(clang_getFileName(cxFile)) << std::endl; + + typedef std::function visitor; + visitor visit = [&](CXCursor cursor, CXCursor) { + CXCursor ref = clang_getCursorReferenced(cursor); + if (clang_equalCursors(what, clang_getCanonicalCursor(ref))) + ppCursor("grep", cursor); + return CXChildVisit_Recurse; + }; + clang_visitChildren(tuCursor, + [](CXCursor c, CXCursor p, void *f) { + return (*static_cast(f))(c, p); + }, + &visit); + } + + std::cout << ")" << std::endl; +} diff --git a/server/src/Irony.h b/server/src/Irony.h index 1a23bd05..90a08222 100644 --- a/server/src/Irony.h +++ b/server/src/Irony.h @@ -109,6 +109,9 @@ class Irony { /// \pre complete() was called. void completionDiagnostics() const; + void xref(unsigned line, unsigned col) const; + void grep(unsigned line, unsigned col) const; + /// \brief Get compile options from JSON database. /// /// \param buildDir Directory containing compile_commands.json diff --git a/server/src/TUManager.h b/server/src/TUManager.h index bd7730dd..ed7fac72 100644 --- a/server/src/TUManager.h +++ b/server/src/TUManager.h @@ -82,6 +82,11 @@ class TUManager : public util::NonCopyable { */ void invalidateAllCachedTUs(); + const std::map + allAvailableTranslationUnits() const { + return translationUnits_; + } + private: /** * \brief Get a reference to the translation unit that matches \p filename diff --git a/server/src/main.cpp b/server/src/main.cpp index 77975286..1100643a 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -176,6 +176,14 @@ int main(int ac, const char *av[]) { } switch (c->action) { + case Command::Xref: + irony.xref(c->line, c->column); + break; + + case Command::Grep: + irony.grep(c->line, c->column); + break; + case Command::Help: printHelp(); break; From e091d0541f06289b4ef01822f12ac5da2f72410f Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Wed, 3 May 2017 03:14:50 -0400 Subject: [PATCH 02/10] squash! Finished irony-find-references. --- irony-xref.el | 64 ++++++++++++++++++------- server/src/Command.cpp | 4 +- server/src/Commands.def | 4 +- server/src/Irony.cpp | 104 +++++++++++++++++++--------------------- server/src/Irony.h | 11 ++++- server/src/main.cpp | 8 ++-- 6 files changed, 113 insertions(+), 82 deletions(-) diff --git a/irony-xref.el b/irony-xref.el index 7b298186..34883db0 100644 --- a/irony-xref.el +++ b/irony-xref.el @@ -2,6 +2,13 @@ ;; ;;; Commentary: ;; +;; To enable, run +;; +;; (add-hook 'irony-mode-hook (lambda () (add-hook 'xref-backend-functions #'irony--xref-backend nil t))) +;; +;; Missing commands: +;; - ‘xref-find-apropos’ +;; ;;; Code: (require 'irony) @@ -15,18 +22,23 @@ ;; IO tasks ;; -(irony-iotask-define-task irony--t-find-definitions - "`xref' server command." +(irony-iotask-define-task irony--t-xref-definitions + "`xref-definitions' server command." :start (lambda (line col) - (irony--server-send-command "xref" line col)) + (irony--server-send-command "xref-definitions" line col)) :update irony--server-query-update) -(irony-iotask-define-task irony--t-find-references - "`grep' server command." +(irony-iotask-define-task irony--t-xref-references + "`xref-references' server command." :start (lambda (line col) - (irony--server-send-command "grep" line col)) + (irony--server-send-command "xref-references" line col)) :update irony--server-query-update) +;; (irony-iotask-define-task irony--t-find-apropos +;; "`xref-apropos' server command." +;; :start (lambda (what) (irony--server-send-command "xref-apropos" what)) +;; :update irony--server-query-update) + ;; ;; Functions @@ -40,8 +52,8 @@ (column (cdr line-column))) (irony--run-task (irony-iotask-chain - (irony--parse-task) - (irony-iotask-package-task irony--t-find-definitions line column))))) + (irony--parse-task) ; FIXME Is parsing even necessary here? + (irony-iotask-package-task irony--t-xref-definitions line column))))) ;;;###autoload (defun irony-find-references (&optional pos) @@ -49,8 +61,8 @@ (let* ((line-column (irony--completion-line-column pos)) (result (irony--run-task (irony-iotask-chain - (irony--parse-task) - (irony-iotask-package-task irony--t-find-references + (irony--parse-task) ; FIXME Is parsing necessary here? + (irony-iotask-package-task irony--t-xref-references (car line-column) (cdr line-column)))))) (cl-loop for item in result do (message "%S" item)))) @@ -63,7 +75,9 @@ ;;;###autoload (defun irony--xref-backend () 'irony) -;; (add-hook 'irony-mode (lambda () (add-hook 'xref-backend-functions #'irony--xref-backend nil t))) +(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql irony))) + "A dummy completion table." + nil) (cl-defmethod xref-backend-identifier-at-point ((_backend (eql irony))) ;; FIXME These propertized strings are not suitable for completion @@ -77,6 +91,7 @@ (line-column (irony--completion-line-column start)) (thing (buffer-substring-no-properties start end))) (put-text-property 0 (length thing) 'irony-xref (list file buffer start end) thing) + ;; (message "xref-backend-identifier-at-point: %S" thing) thing)) (cl-defmethod xref-backend-definitions ((_backend (eql irony)) identifier) @@ -85,17 +100,18 @@ (buffer (nth 1 thing)) (line-column (irony--completion-line-column (nth 2 thing))) (result - ;; Must be synchronous + ;; FIXME Must this be synchronous (irony--run-task (irony-iotask-chain (irony--parse-task buffer) - (irony-iotask-package-task irony--t-find-definitions + (irony-iotask-package-task irony--t-xref-definitions (car line-column) (cdr line-column)))))) (cl-loop for (kind name filename line column start end) in result collect - (xref-make name (xref-make-file-location filename line column)) - do (message "result: %S" (list kind name filename line column start end))))) + (xref-make (concat name "(" (symbol-name kind) ")") (xref-make-file-location filename line column)) + ;; do (message "result: %S" (list kind name filename line column start end)) + ))) (cl-defmethod xref-backend-references ((_backend (eql irony)) identifier) (-when-let* @@ -103,17 +119,29 @@ (buffer (nth 1 thing)) (line-column (irony--completion-line-column (nth 2 thing))) (result - ;; Must be synchronous + ;; FIXME Must this be synchronous (irony--run-task (irony-iotask-chain (irony--parse-task buffer) - (irony-iotask-package-task irony--t-find-references + (irony-iotask-package-task irony--t-xref-references (car line-column) (cdr line-column)))))) (cl-loop for (kind name filename line column start end) in result collect (xref-make name (xref-make-file-location filename line column)) - do (message "result: %S" (list kind name filename line column start end))))) + ;; do (message "result: %S" (list kind name filename line column start end)) + ))) + +;; (cl-defmethod xref-backend-apropos ((_backend (eql irony)) pattern) +;; (let ((result +;; ;; FIXME Must this be synchronous +;; (irony--run-task +;; (irony-iotask-package-task irony--t-find-apropos pattern)))) +;; (dolist (item result) (message "xref-backend-apropos: %S" item)) +;; (cl-loop +;; for (kind name filename line column start end) in result +;; collect +;; (xref-make name (xref-make-file-location filename line column))))) (provide 'irony-xref) ;;; irony-xref.el ends here diff --git a/server/src/Command.cpp b/server/src/Command.cpp index 344b6eba..9d96ddf5 100644 --- a/server/src/Command.cpp +++ b/server/src/Command.cpp @@ -188,12 +188,12 @@ Command *CommandParser::parse(const std::vector &argv) { std::vector> positionalArgs; switch (command_.action) { - case Command::Xref: + case Command::XrefDefinitions: positionalArgs.push_back(UnsignedIntConverter(&command_.line)); positionalArgs.push_back(UnsignedIntConverter(&command_.column)); break; - case Command::Grep: + case Command::XrefReferences: positionalArgs.push_back(UnsignedIntConverter(&command_.line)); positionalArgs.push_back(UnsignedIntConverter(&command_.column)); break; diff --git a/server/src/Commands.def b/server/src/Commands.def index de3e2993..704e352d 100644 --- a/server/src/Commands.def +++ b/server/src/Commands.def @@ -15,8 +15,8 @@ X(Candidates, "candidates", "PREFIX STYLE - print completion candidates (require previous complete). " "STYLE is \"exact\", \"case-insensitive\" or \"smart-case\"") -X(Xref, "xref", "LINE COL - print definition/reference of what is at the given location") -X(Grep, "grep", "LINE COL - print all uses of what is at the given location") +X(XrefDefinitions, "xref-definitions", "LINE COL - print definition/reference") +X(XrefReferences, "xref-references", "LINE COL - print all uses") X(Complete, "complete", "FILE LINE COL [-- [COMPILE_OPTIONS...]] - perform code completion at a given location") X(CompletionDiagnostics, "completion-diagnostics", diff --git a/server/src/Irony.cpp b/server/src/Irony.cpp index 12d197a1..a6369057 100644 --- a/server/src/Irony.cpp +++ b/server/src/Irony.cpp @@ -115,6 +115,32 @@ bool readFileContent(const std::string &filename, return true; } +void prettyPrintCursor(std::string label, CXCursor cursor) { + if (clang_Cursor_isNull(cursor)) { + // std::cout << "(" << label << ")\n"; + return; + } + CXString name = clang_getCursorDisplayName(cursor); + CXSourceRange loc = clang_getCursorExtent(cursor); + CXSourceLocation start = clang_getRangeStart(loc), + end = clang_getRangeEnd(loc); + CXFile file; + unsigned start_line, start_col, start_offset, end_offset; + clang_getSpellingLocation(start, &file, &start_line, &start_col, + &start_offset); + clang_getSpellingLocation(end, nullptr, nullptr, nullptr, &end_offset); + CXString filename = clang_getFileName(file); + // FIXME It would be nice to print cursor’s enclosing statement, or similar + // FIXME But there doesn’t seem to be a clear way to do it without going + // FIXME throught the whole AST. + std::cout << "(" << label << " " << support::quoted(clang_getCString(name)) + << " " << support::quoted(clang_getCString(filename)) << " " + << start_line << " " << start_col << " " << start_offset << " " + << end_offset << ")\n"; + clang_disposeString(name); + clang_disposeString(filename); +} + } // unnamed namespace Irony::Irony() @@ -650,88 +676,58 @@ void Irony::getCompileOptions(const std::string &buildDir, #endif } -void ppCursor(std::string label, CXCursor cursor) { - if (clang_Cursor_isNull(cursor)) { - // std::cout << "(" << label << ")\n"; - return; - } - CXString name = clang_getCursorDisplayName(cursor); - CXSourceRange loc = clang_getCursorExtent(cursor); - CXSourceLocation start = clang_getRangeStart(loc), - end = clang_getRangeEnd(loc); - CXFile file; - unsigned start_line, start_col, start_offset, end_offset; - clang_getSpellingLocation(start, &file, &start_line, &start_col, - &start_offset); - clang_getSpellingLocation(end, nullptr, nullptr, nullptr, &end_offset); - CXString filename = clang_getFileName(file); - std::cout << "(" << label << " " << support::quoted(clang_getCString(name)) - << " " << support::quoted(clang_getCString(filename)) << " " - << start_line << " " << start_col << " " << start_offset << " " - << end_offset << ")\n"; - clang_disposeString(name); - clang_disposeString(filename); -} - -void Irony::xref(unsigned line, unsigned col) const { +void Irony::xrefDefinitions(unsigned line, unsigned col) const { if (activeTu_ == nullptr) { std::clog << "W: get-type - parse wasn't called\n"; - std::cout << "nil\n"; + std::cout << "nil" << std::endl; return; } - - // std::cerr << "xref:" << line << ":" << col << std::endl; - std::cout << "("; - CXFile cxFile = clang_getFile(activeTu_, file_.c_str()); CXCursor c = clang_getCursor(activeTu_, clang_getLocation(activeTu_, cxFile, line, col)); - // CXTranslationUnit tu = tuManager_.getOrCreateTU(file, flags, - // cxUnsavedFiles_); - // CXFile f = clang_getFile(tu, file.c_str()); - // CXSourceLocation s = clang_getLocation(tu, f, line, col); - // CXCursor c = clang_getCursor(tu, s); - - // std::cerr << "getCursorSpelling(c): " - // << clang_getCString(clang_getCursorSpelling(c)) << std::endl; - // std::cerr << "getCursorDisplayName(c): " - // << clang_getCString(clang_getCursorDisplayName(c)) << std::endl; - // std::cerr << "getCursorUSR(c): " << clang_getCString(clang_getCursorUSR(c)) - // << std::endl; - CXCursor def = clang_getCursorDefinition(c), ref = clang_getCursorReferenced(c); - ppCursor("reference", ref); - if (!clang_Cursor_isNull(def) && !clang_equalCursors(def, ref)) { - ppCursor("definition", def); - } - + // FIXME If the cursors are in system headers, should we print nil? + // if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref))) { + // std::cout << "nil" << std::endl; + // return; + // } + std::cout << "("; + prettyPrintCursor("reference", ref); + if (!clang_Cursor_isNull(def) && !clang_equalCursors(def, ref)) + prettyPrintCursor("definition", def); std::cout << ")" << std::endl; } -void Irony::grep(unsigned line, unsigned col) const { +void Irony::xrefReferences(unsigned line, unsigned col) const { if (activeTu_ == nullptr) { std::clog << "W: get-type - parse wasn't called\n"; std::cout << "nil\n"; return; } CXFile cxFile = clang_getFile(activeTu_, file_.c_str()); - CXCursor what = clang_getCursor(activeTu_, clang_getLocation(activeTu_, cxFile, line, col)); - what = clang_getCanonicalCursor(clang_getCursorReferenced(what)); + CXCursor what = clang_getCursor( + activeTu_, clang_getLocation(activeTu_, cxFile, line, col)); + if (!clang_Cursor_isNull(clang_getCursorReferenced(what))) + what = clang_getCursorReferenced(what); + what = clang_getCanonicalCursor(what); std::cout << "("; for (auto file_tu : tuManager_.allAvailableTranslationUnits()) { - CXCursor tuCursor = clang_getTranslationUnitCursor(file_tu.second); - // std::cerr << "\n" << file_tu.first << ": " << clang_getCString(clang_getFileName(cxFile)) << std::endl; typedef std::function visitor; visitor visit = [&](CXCursor cursor, CXCursor) { + // Skip all system headers, because they are generally unreadable. + if (clang_Location_isInSystemHeader(clang_getCursorLocation(cursor))) + return CXChildVisit_Continue; CXCursor ref = clang_getCursorReferenced(cursor); - if (clang_equalCursors(what, clang_getCanonicalCursor(ref))) - ppCursor("grep", cursor); + if (clang_equalCursors(what, clang_getCanonicalCursor(ref))) { + prettyPrintCursor("xref", cursor); + return CXChildVisit_Continue; + } return CXChildVisit_Recurse; }; clang_visitChildren(tuCursor, diff --git a/server/src/Irony.h b/server/src/Irony.h index 90a08222..83286e65 100644 --- a/server/src/Irony.h +++ b/server/src/Irony.h @@ -109,8 +109,15 @@ class Irony { /// \pre complete() was called. void completionDiagnostics() const; - void xref(unsigned line, unsigned col) const; - void grep(unsigned line, unsigned col) const; + /// Lookup definition/declaration of the given symbol. + /// + /// \pre parse() was called. + void xrefDefinitions(unsigned line, unsigned col) const; + + /// Get all references to the given symbol. + /// + /// \pre parse() was called + void xrefReferences(unsigned line, unsigned col) const; /// \brief Get compile options from JSON database. /// diff --git a/server/src/main.cpp b/server/src/main.cpp index 1100643a..2a14ead4 100644 --- a/server/src/main.cpp +++ b/server/src/main.cpp @@ -176,12 +176,12 @@ int main(int ac, const char *av[]) { } switch (c->action) { - case Command::Xref: - irony.xref(c->line, c->column); + case Command::XrefDefinitions: + irony.xrefDefinitions(c->line, c->column); break; - case Command::Grep: - irony.grep(c->line, c->column); + case Command::XrefReferences: + irony.xrefReferences(c->line, c->column); break; case Command::Help: From 1a3a7d3ce20a255c297a8b8b1503b09e41707cac Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Wed, 3 May 2017 03:21:22 -0400 Subject: [PATCH 03/10] Formatting. --- server/src/Irony.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/Irony.cpp b/server/src/Irony.cpp index a6369057..e0aed9f4 100644 --- a/server/src/Irony.cpp +++ b/server/src/Irony.cpp @@ -123,7 +123,7 @@ void prettyPrintCursor(std::string label, CXCursor cursor) { CXString name = clang_getCursorDisplayName(cursor); CXSourceRange loc = clang_getCursorExtent(cursor); CXSourceLocation start = clang_getRangeStart(loc), - end = clang_getRangeEnd(loc); + end = clang_getRangeEnd(loc); CXFile file; unsigned start_line, start_col, start_offset, end_offset; clang_getSpellingLocation(start, &file, &start_line, &start_col, @@ -134,9 +134,9 @@ void prettyPrintCursor(std::string label, CXCursor cursor) { // FIXME But there doesn’t seem to be a clear way to do it without going // FIXME throught the whole AST. std::cout << "(" << label << " " << support::quoted(clang_getCString(name)) - << " " << support::quoted(clang_getCString(filename)) << " " - << start_line << " " << start_col << " " << start_offset << " " - << end_offset << ")\n"; + << " " << support::quoted(clang_getCString(filename)) << " " + << start_line << " " << start_col << " " << start_offset << " " + << end_offset << ")\n"; clang_disposeString(name); clang_disposeString(filename); } From 7c4a80d916d597bfdd98777602d7d87078d43e7c Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 11:24:53 +0000 Subject: [PATCH 04/10] Add functions for entering/exiting irony-xref --- irony-xref.el | 9 +++++++++ irony.el | 2 ++ 2 files changed, 11 insertions(+) diff --git a/irony-xref.el b/irony-xref.el index 34883db0..879ba31f 100644 --- a/irony-xref.el +++ b/irony-xref.el @@ -143,5 +143,14 @@ ;; collect ;; (xref-make name (xref-make-file-location filename line column))))) + +;; Setting up xref + +(defun irony-xref--enter () + (add-hook 'xref-backend-functions #'irony--xref-backend nil t)) + +(defun irony-xref--exit () + (remove-hook 'xref-backend-functions #'irony--xref-backend t)) + (provide 'irony-xref) ;;; irony-xref.el ends here diff --git a/irony.el b/irony.el index ec4ff8bd..e36b11cb 100644 --- a/irony.el +++ b/irony.el @@ -47,6 +47,7 @@ ;;; Code: (require 'irony-iotask) +(require 'irony-xref) (autoload 'irony-completion--enter "irony-completion") (autoload 'irony-completion--exit "irony-completion") @@ -426,6 +427,7 @@ If no such file exists on the filesystem the special file '-' is (display-warning 'irony "Performance will be bad because a\ pipe delay is set for this platform (see variable\ `w32-pipe-read-delay').")))) + (irony-xref--enter) (irony-completion--enter)) (defun irony--mode-exit () From c360ef7f771c71444bcb1aa81eaf9a1198309bce Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 11:42:45 +0000 Subject: [PATCH 05/10] Fix recursive require --- irony.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/irony.el b/irony.el index e36b11cb..1aec9a3e 100644 --- a/irony.el +++ b/irony.el @@ -47,10 +47,11 @@ ;;; Code: (require 'irony-iotask) -(require 'irony-xref) (autoload 'irony-completion--enter "irony-completion") (autoload 'irony-completion--exit "irony-completion") +(autoload 'irony-xref--enter "irony-xref") +(autoload 'irony-xref--exit "irony-xref") (require 'cl-lib) From 129795d1387c92f15c2b3a4741dd9afb22384a6c Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 11:42:54 +0000 Subject: [PATCH 06/10] Add short feature list --- irony-xref.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/irony-xref.el b/irony-xref.el index 879ba31f..e17ecde1 100644 --- a/irony-xref.el +++ b/irony-xref.el @@ -6,6 +6,11 @@ ;; ;; (add-hook 'irony-mode-hook (lambda () (add-hook 'xref-backend-functions #'irony--xref-backend nil t))) ;; +;; Features: +;; - will jump into system headers +;; - with overloaded functions, will jump to the right function definition +;; (it's not just string matching on the function name) +;; ;; Missing commands: ;; - ‘xref-find-apropos’ ;; From d0ae21cce69da806b001c6cf44e146d083b849dc Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 11:43:04 +0000 Subject: [PATCH 07/10] Fix log message --- server/src/Irony.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/Irony.cpp b/server/src/Irony.cpp index e0aed9f4..96df9362 100644 --- a/server/src/Irony.cpp +++ b/server/src/Irony.cpp @@ -678,7 +678,7 @@ void Irony::getCompileOptions(const std::string &buildDir, void Irony::xrefDefinitions(unsigned line, unsigned col) const { if (activeTu_ == nullptr) { - std::clog << "W: get-type - parse wasn't called\n"; + std::clog << "W: xref-definitions - parse wasn't called\n"; std::cout << "nil" << std::endl; return; } @@ -702,7 +702,7 @@ void Irony::xrefDefinitions(unsigned line, unsigned col) const { void Irony::xrefReferences(unsigned line, unsigned col) const { if (activeTu_ == nullptr) { - std::clog << "W: get-type - parse wasn't called\n"; + std::clog << "W: xref-references - parse wasn't called\n"; std::cout << "nil\n"; return; } From 2585b7001a4d1bf8c683ced6639542072b921a5e Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 11:51:58 +0000 Subject: [PATCH 08/10] remove commented out code, and fix up two comments --- irony-xref.el | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/irony-xref.el b/irony-xref.el index e17ecde1..bd63f902 100644 --- a/irony-xref.el +++ b/irony-xref.el @@ -39,11 +39,6 @@ (irony--server-send-command "xref-references" line col)) :update irony--server-query-update) -;; (irony-iotask-define-task irony--t-find-apropos -;; "`xref-apropos' server command." -;; :start (lambda (what) (irony--server-send-command "xref-apropos" what)) -;; :update irony--server-query-update) - ;; ;; Functions @@ -96,7 +91,6 @@ (line-column (irony--completion-line-column start)) (thing (buffer-substring-no-properties start end))) (put-text-property 0 (length thing) 'irony-xref (list file buffer start end) thing) - ;; (message "xref-backend-identifier-at-point: %S" thing) thing)) (cl-defmethod xref-backend-definitions ((_backend (eql irony)) identifier) @@ -105,7 +99,7 @@ (buffer (nth 1 thing)) (line-column (irony--completion-line-column (nth 2 thing))) (result - ;; FIXME Must this be synchronous + ;; FIXME Must this be synchronous? (irony--run-task (irony-iotask-chain (irony--parse-task buffer) @@ -114,9 +108,7 @@ (cl-loop for (kind name filename line column start end) in result collect - (xref-make (concat name "(" (symbol-name kind) ")") (xref-make-file-location filename line column)) - ;; do (message "result: %S" (list kind name filename line column start end)) - ))) + (xref-make (concat name "(" (symbol-name kind) ")") (xref-make-file-location filename line column))))) (cl-defmethod xref-backend-references ((_backend (eql irony)) identifier) (-when-let* @@ -124,7 +116,7 @@ (buffer (nth 1 thing)) (line-column (irony--completion-line-column (nth 2 thing))) (result - ;; FIXME Must this be synchronous + ;; FIXME Must this be synchronous? (irony--run-task (irony-iotask-chain (irony--parse-task buffer) @@ -133,20 +125,7 @@ (cl-loop for (kind name filename line column start end) in result collect - (xref-make name (xref-make-file-location filename line column)) - ;; do (message "result: %S" (list kind name filename line column start end)) - ))) - -;; (cl-defmethod xref-backend-apropos ((_backend (eql irony)) pattern) -;; (let ((result -;; ;; FIXME Must this be synchronous -;; (irony--run-task -;; (irony-iotask-package-task irony--t-find-apropos pattern)))) -;; (dolist (item result) (message "xref-backend-apropos: %S" item)) -;; (cl-loop -;; for (kind name filename line column start end) in result -;; collect -;; (xref-make name (xref-make-file-location filename line column))))) + (xref-make name (xref-make-file-location filename line column))))) ;; Setting up xref From 84276cb9e1bd57503dea0026b34a4dce6243cf09 Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 12:28:13 +0000 Subject: [PATCH 09/10] Apply clang-tidy --- server/src/Irony.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/server/src/Irony.cpp b/server/src/Irony.cpp index 96df9362..d09d7fa0 100644 --- a/server/src/Irony.cpp +++ b/server/src/Irony.cpp @@ -125,18 +125,18 @@ void prettyPrintCursor(std::string label, CXCursor cursor) { CXSourceLocation start = clang_getRangeStart(loc), end = clang_getRangeEnd(loc); CXFile file; - unsigned start_line, start_col, start_offset, end_offset; - clang_getSpellingLocation(start, &file, &start_line, &start_col, - &start_offset); - clang_getSpellingLocation(end, nullptr, nullptr, nullptr, &end_offset); + unsigned startLine, startCol, startOffset, endOffset; + clang_getSpellingLocation(start, &file, &startLine, &startCol, + &startOffset); + clang_getSpellingLocation(end, nullptr, nullptr, nullptr, &endOffset); CXString filename = clang_getFileName(file); // FIXME It would be nice to print cursor’s enclosing statement, or similar // FIXME But there doesn’t seem to be a clear way to do it without going // FIXME throught the whole AST. std::cout << "(" << label << " " << support::quoted(clang_getCString(name)) << " " << support::quoted(clang_getCString(filename)) << " " - << start_line << " " << start_col << " " << start_offset << " " - << end_offset << ")\n"; + << startLine << " " << startCol << " " << startOffset << " " + << endOffset << ")\n"; clang_disposeString(name); clang_disposeString(filename); } @@ -715,11 +715,11 @@ void Irony::xrefReferences(unsigned line, unsigned col) const { std::cout << "("; - for (auto file_tu : tuManager_.allAvailableTranslationUnits()) { - CXCursor tuCursor = clang_getTranslationUnitCursor(file_tu.second); + for (auto fileTu : tuManager_.allAvailableTranslationUnits()) { + CXCursor tuCursor = clang_getTranslationUnitCursor(fileTu.second); - typedef std::function visitor; - visitor visit = [&](CXCursor cursor, CXCursor) { + typedef std::function Visitor; + Visitor visit = [&](CXCursor cursor, CXCursor) { // Skip all system headers, because they are generally unreadable. if (clang_Location_isInSystemHeader(clang_getCursorLocation(cursor))) return CXChildVisit_Continue; From cd695db1123a9783035ef642bfa55adb125fe81f Mon Sep 17 00:00:00 2001 From: Kirill Ignatiev Date: Mon, 29 Oct 2018 12:35:30 +0000 Subject: [PATCH 10/10] clang-tidy missed one --- server/src/Irony.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/Irony.cpp b/server/src/Irony.cpp index d09d7fa0..114f2457 100644 --- a/server/src/Irony.cpp +++ b/server/src/Irony.cpp @@ -732,7 +732,7 @@ void Irony::xrefReferences(unsigned line, unsigned col) const { }; clang_visitChildren(tuCursor, [](CXCursor c, CXCursor p, void *f) { - return (*static_cast(f))(c, p); + return (*static_cast(f))(c, p); }, &visit); }