Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reading compilation database using rapidjson. #230

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "server/src/rapidjson"]
path = server/src/rapidjson
url = https://github.com/miloyip/rapidjson
35 changes: 16 additions & 19 deletions irony-cdb-libclang.el → irony-cdb-server.el
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
;;; irony-cdb-libclang.el --- Compilation Database for irony using libclang
;;; irony-cdb-server.el --- Compilation Database querying irony-server

;; Copyright (C) 2015 Karl Hylén

Expand All @@ -18,11 +18,6 @@
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:
;;
;; Compilation Database support for Irony using libclangs CXCompilationDatabase,
;; http://clang.llvm.org/doxygen/group__COMPILATIONDB.html

;;; Code:

(require 'irony-cdb)
Expand All @@ -31,24 +26,26 @@
(require 'cl-lib)

;;;###autoload
(defun irony-cdb-libclang (command &rest args)
(defun irony-cdb-server (command &rest args)
(cl-case command
(get-compile-options (irony-cdb-libclang--get-compile-options))))
(get-compile-options (irony-cdb-server--get-compile-options))))

(defun irony-cdb-libclang--get-compile-options ()
(defun irony-cdb-server--get-compile-options ()
(irony--awhen (irony-cdb-json--locate-db)
(irony-cdb-libclang--server-exact-flags it)))
(irony-cdb-server--server-exact-flags buffer-file-name it)))

(defun irony-cdb-libclang--server-exact-flags (db-file)
(defun irony-cdb-server--server-exact-flags (src-file db-file)
"Get compilation options from irony-server.

The parameter DB-FILE is the database file."
(let ((build-dir (file-name-directory db-file))
(file buffer-file-name))
(irony-cdb-libclang--adjust-options-and-remove-compiler
file (irony--send-request-sync "get-compile-options" build-dir file))))
The parameter SRC-FILE is the source file we seek the compile command of and
DB-FILE is the database file."
(irony-cdb-server--adjust-options-and-remove-compiler
src-file
(irony--send-request-sync "get-compile-options"
db-file
src-file)))

(defun irony-cdb-libclang--adjust-options-and-remove-compiler (file cmds)
(defun irony-cdb-server--adjust-options-and-remove-compiler (file cmds)
"Remove compiler, target file FILE and output file from CMDS.

The parameter CMDS is a list of conses. In each cons, the car holds the options
Expand All @@ -61,10 +58,10 @@ and the cdr holds the working directory where the compile command was issued."
wdir)))
cmds))

(provide 'irony-cdb-libclang)
(provide 'irony-cdb-server)

;; Local Variables:
;; byte-compile-warnings: (not cl-functions)
;; End:

;;; irony-cdb-libclang ends here
;;; irony-cdb-server ends here
4 changes: 2 additions & 2 deletions irony-cdb.el
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

(autoload 'irony-cdb-clang-complete "irony-cdb-clang-complete")
(autoload 'irony-cdb-json "irony-cdb-json")
(autoload 'irony-cdb-libclang "irony-cdb-libclang")
(autoload 'irony-cdb-server "irony-cdb-server")


;;
Expand All @@ -48,7 +48,7 @@
:group 'irony)

(defcustom irony-cdb-compilation-databases '(irony-cdb-clang-complete
irony-cdb-libclang
irony-cdb-server
irony-cdb-json)
"List of active compilation databases.

Expand Down
20 changes: 17 additions & 3 deletions irony.el
Original file line number Diff line number Diff line change
Expand Up @@ -544,22 +544,26 @@ The installation requires CMake and the libclang developpement package."

When using a leading space, the buffer is hidden from the buffer
list (and undo information is not kept).")
(defvar irony--server-log nil
"The log file of irony-server.")

(defun irony--start-server-process ()
(when (setq irony--server-executable (or irony--server-executable
(irony--locate-server-executable)))
(let ((process-connection-type nil)
(process-adaptive-read-buffering nil)
process)
(setq irony--server-log (expand-file-name
(format-time-string
"irony.%Y-%m-%d_%Hh-%Mm-%Ss.log")
temporary-file-directory))
(setq process
(start-process-shell-command
"Irony" ;process name
irony--server-buffer ;buffer
(format "%s -i 2> %s" ;command
(shell-quote-argument irony--server-executable)
(expand-file-name
(format-time-string "irony.%Y-%m-%d_%Hh-%Mm-%Ss.log")
temporary-file-directory))))
irony--server-log)))
(buffer-disable-undo irony--server-buffer)
(set-process-query-on-exit-flag process nil)
(set-process-sentinel process 'irony--server-process-sentinel)
Expand All @@ -574,6 +578,16 @@ list (and undo information is not kept).")
(kill-process irony--server-process)
(setq irony--server-process nil)))

;;;###autoload
(defun irony-open-log-file ()
"Open irony server log file"
(interactive)
(if (and irony--server-log (file-exists-p irony--server-log))
(progn
(find-file irony--server-log)
(auto-revert-tail-mode))
(message "Log file doesn't exist yet!")))

(defun irony--get-server-process-create ()
(if (and irony--server-process
(process-live-p irony--server-process))
Expand Down
4 changes: 4 additions & 0 deletions server/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ find_package(LibClang REQUIRED)

include_directories(${LIBCLANG_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(rapidjson/include)

check_libclang_builtin_headers_dir()

Expand Down Expand Up @@ -32,6 +33,7 @@ add_executable(irony-server
Irony.h
TUManager.cpp
TUManager.h
CompilationDatabase.cpp

main.cpp)

Expand Down Expand Up @@ -67,4 +69,6 @@ set_source_files_properties(main.cpp

target_link_libraries(irony-server ${LIBCLANG_LIBRARIES})

# add_subdirectory(json-test)

install(TARGETS irony-server DESTINATION bin)
143 changes: 143 additions & 0 deletions server/src/CompilationDatabase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/** -*- C++ -*-
* \file
* \author Karl Hylén <[email protected]>
*
* This file is distributed under the GNU General Public License. See
* COPYING for details.
*/

#include "CompilationDatabase.h"

#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/encodedstream.h"

// TODO: ifdef linux/mac
#include <sys/stat.h>
// endif

#include <algorithm>
#include <cstdio>
#include <fstream>
#include <iostream>

struct FileHandle {
FileHandle(const std::string &fileName, const char *mode)
: fp_(fopen(fileName.c_str(), mode)) {
}
~FileHandle() {
if (fp_)
fclose(fp_);
}

FILE *fp_;
};

std::vector<std::string> CompileCommand::splitCommand(const std::string &Command) {
std::vector<std::string> cmdSplit;
std::istringstream iss(Command);

std::string cmdArg;
while (iss >> cmdArg)
cmdSplit.emplace_back(cmdArg);

return cmdSplit;
}

time_t CompilationDatabase::getModTime(const std::string &fileName) {
// TODO: Add suport for Windows
time_t time = 0;

struct stat dbStats;
if (stat(fileName.c_str(), &dbStats) != 0)
return time;

time = dbStats.st_atime;

return time;
}

void CompilationDatabase::readOrUpdateDatabase(const std::string &fileName) {
if (databaseFile_ != fileName ||
difftime(getModTime(fileName), readTime_) >= 0.0) {
std::clog << "I: Reloading database.\n";
readDatabase(fileName);
}
}

void CompilationDatabase::readDatabase(const std::string &fileName) {
FileHandle file(fileName, "r");

if (!file.fp_) {
std::clog << "I: Couldn't open compilation database file!\n";
return;
}

char buffer[bufferSize];
rapidjson::FileReadStream stream{file.fp_, buffer, sizeof(buffer)};
// TODO: What if the database isn't encoded as UTF8?
rapidjson::EncodedInputStream<rapidjson::UTF8<>, rapidjson::FileReadStream>
encStream{stream};

rapidjson::Document doc;
doc.ParseStream(encStream);

if (doc.HasParseError()) {
std::clog << "I: Error parsing compilation database file!\n";
return;
}

if (!doc.IsArray()) {
std::clog << "I: Expected top level array when reading compilation "
"database!\n";
return;
}

// If we've gotten this far without failure, consider the database read. Set
// the name of the database file, record the time of reading and clear the
// compile commands.
databaseFile_ = fileName;
readTime_ = time(nullptr);
cmdMap_.clear();

for (unsigned i = 0, e = doc.Size(); i != e; ++i) {
rapidjson::Value &compileCmd = doc[i];

if (!compileCmd.IsObject() || !compileCmd.HasMember("file") ||
!compileCmd.HasMember("directory") ||
!compileCmd.HasMember("command")) {
std::clog << "I: Badly formatted compile command in database!\n";
continue;
}

std::string file{compileCmd["file"].GetString()};
CompileCommand cmd{std::string{compileCmd["directory"].GetString()},
std::string{compileCmd["command"].GetString()}};
cmdMap_.emplace(std::move(file), std::move(cmd));
}
}

void CompilationDatabase::printDatabase() const {
for (const auto &cmd_pair : cmdMap_) {
std::cout << "file: " << cmd_pair.first << "\n"
<< "directory: " << cmd_pair.second.dir_ << "\n";

std::cout << "command:";
for (const std::string &cmdArg : cmd_pair.second.cmd_)
std::cout << " " << cmdArg;
std::cout << "\n";
}
}

std::vector<const CompileCommand *>
CompilationDatabase::getCommands(const std::string &srcFile) const {
std::vector<const CompileCommand*> cmds;

auto range = cmdMap_.equal_range(srcFile);
cmds.reserve(std::distance(range.first, range.second));

std::transform(range.first, range.second, std::back_inserter(cmds),
[] (const FileMapType::value_type &v) { return &v.second; });

return cmds;
}
73 changes: 73 additions & 0 deletions server/src/CompilationDatabase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/** -*- C++ -*-
* \file
* \author Karl Hylén <[email protected]>
*
* \brief Classes for reading JSON compilation database.
*
* This file is distributed under the GNU General Public License. See
* COPYING for details.
*/

#ifndef COMPILATION_DATABASE_H
#define COMPILATION_DATABASE_H

#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>

struct CompileCommand {
static std::vector<std::string> splitCommand(const std::string &command);

CompileCommand(const std::string &directory, const std::string &command)
: dir_(directory), cmd_(splitCommand(command)) {
}
CompileCommand(std::string &&directory, std::string &&command)
: dir_(directory), cmd_(splitCommand(command)) {
}

// Data members
std::string dir_;
std::vector<std::string> cmd_;
};

class CompilationDatabase {
public:
// TODO: Use something more optimal for storing file names?
using FileMapType = std::unordered_multimap<std::string, CompileCommand>;
using iterator = FileMapType::iterator;
using const_iterator = FileMapType::const_iterator;

CompilationDatabase() = default;

// Don't allow copy or move
CompilationDatabase(const CompilationDatabase&) = delete;
CompilationDatabase &operator=(const CompilationDatabase&) = delete;
CompilationDatabase(CompilationDatabase&&) = delete;
CompilationDatabase &operator=(CompilationDatabase&&) = delete;

~CompilationDatabase() = default;

iterator begin() { return cmdMap_.begin(); }
const_iterator begin() const { return cmdMap_.begin(); }
iterator end() { return cmdMap_.end(); }
const_iterator end() const { return cmdMap_.end(); }

// Get all compile commands of a file
std::vector<const CompileCommand *>
getCommands(const std::string &fileName) const;

void printDatabase() const;
void readOrUpdateDatabase(const std::string &fileName);

private:
void readDatabase(const std::string &fileName);
static time_t getModTime(const std::string &fileName);

static constexpr unsigned bufferSize = 65536;
std::string databaseFile_{};
time_t readTime_{0};
FileMapType cmdMap_;
};

#endif
Loading