summaryrefslogtreecommitdiff
path: root/elpa/irony-20220110.849/server/src
diff options
context:
space:
mode:
authormattkae <mattkae@protonmail.com>2022-05-11 09:23:58 -0400
committermattkae <mattkae@protonmail.com>2022-05-11 09:23:58 -0400
commit3f4a0d5370ae6c34afe180df96add3b8522f4af1 (patch)
treeae901409e02bde8ee278475f8cf6818f8f680a60 /elpa/irony-20220110.849/server/src
initial commit
Diffstat (limited to 'elpa/irony-20220110.849/server/src')
-rw-r--r--elpa/irony-20220110.849/server/src/CMakeLists.txt111
-rw-r--r--elpa/irony-20220110.849/server/src/Command.cpp278
-rw-r--r--elpa/irony-20220110.849/server/src/Command.h73
-rw-r--r--elpa/irony-20220110.849/server/src/Commands.def39
-rw-r--r--elpa/irony-20220110.849/server/src/CompDBCache.cpp71
-rw-r--r--elpa/irony-20220110.849/server/src/CompDBCache.h86
-rw-r--r--elpa/irony-20220110.849/server/src/Irony.cpp638
-rw-r--r--elpa/irony-20220110.849/server/src/Irony.h147
-rw-r--r--elpa/irony-20220110.849/server/src/Style.h17
-rw-r--r--elpa/irony-20220110.849/server/src/TUManager.cpp182
-rw-r--r--elpa/irony-20220110.849/server/src/TUManager.h109
-rw-r--r--elpa/irony-20220110.849/server/src/main.cpp235
-rw-r--r--elpa/irony-20220110.849/server/src/support/CIndex.h33
-rw-r--r--elpa/irony-20220110.849/server/src/support/CommandLineParser.cpp119
-rw-r--r--elpa/irony-20220110.849/server/src/support/CommandLineParser.h21
-rw-r--r--elpa/irony-20220110.849/server/src/support/NonCopyable.h34
-rw-r--r--elpa/irony-20220110.849/server/src/support/TemporaryFile.cpp74
-rw-r--r--elpa/irony-20220110.849/server/src/support/TemporaryFile.h36
-rw-r--r--elpa/irony-20220110.849/server/src/support/iomanip_quoted.h52
19 files changed, 2355 insertions, 0 deletions
diff --git a/elpa/irony-20220110.849/server/src/CMakeLists.txt b/elpa/irony-20220110.849/server/src/CMakeLists.txt
new file mode 100644
index 0000000..c516e70
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/CMakeLists.txt
@@ -0,0 +1,111 @@
+# XXX: if there are issues
+# due to https://reviews.llvm.org/D30911 / SVN Revision 298424
+# then use the fallback when LLVM_VERSION VERSION_LESS 5.0.1
+find_package(Clang)
+
+if (Clang_FOUND)
+ # XXX: at least since Clang 8.0.0
+ # it's looks like the 'libclang' IMPORTED target
+ # does not specify the following target property:
+ # INTERFACE_INCLUDE_DIRECTORIES ${CLANG_INCLUDE_DIRS}
+ # which is confirmed by https://github.com/Sarcasm/irony-mode/issues/530
+ # so we work around this,
+ # but ideally Clang upstream should export fully usable IMPORTED targets
+ add_library(irony_libclang INTERFACE)
+ target_link_libraries(irony_libclang INTERFACE libclang)
+ target_include_directories(irony_libclang INTERFACE ${CLANG_INCLUDE_DIRS})
+
+ get_property(IRONY_CLANG_EXECUTABLE TARGET clang PROPERTY LOCATION)
+ execute_process(
+ COMMAND "${IRONY_CLANG_EXECUTABLE}" -print-resource-dir
+ OUTPUT_VARIABLE CLANG_RESOURCE_DIR
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+else()
+ # fallback to historically FindLibClang.cmake
+ # and -resource-dir guess mecanism
+ include(CheckClangResourceDir)
+ find_package(LibClang REQUIRED)
+ check_clang_resource_dir()
+endif()
+
+# not to be taken as a module-definition file to link on Windows
+set_source_files_properties(Commands.def PROPERTIES HEADER_FILE_ONLY TRUE)
+
+if(MSVC)
+ # irony-server uses some code that breaks when iterator debugging is enabled
+ #
+ # The culprit is CommandLineArgumentParser who initialize its member
+ # 'Position', of type 'std::string::const_iterator', to 'Input.begin() - 1'.
+ # With checked iterator the begin() - 1 breaks in debug build.
+ add_definitions(/D_ITERATOR_DEBUG_LEVEL=0)
+endif()
+
+add_executable(irony-server
+ support/CommandLineParser.cpp
+ support/CommandLineParser.h
+ support/iomanip_quoted.h
+ support/NonCopyable.h
+ support/CIndex.h
+ support/TemporaryFile.cpp
+ support/TemporaryFile.h
+
+ Command.cpp
+ Commands.def
+ Command.h
+ CompDBCache.h
+ CompDBCache.cpp
+ Irony.cpp
+ Irony.h
+ TUManager.cpp
+ TUManager.h
+
+ main.cpp)
+
+irony_target_set_cxx_standard(irony-server)
+
+target_include_directories(irony-server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+
+# retrieve the package version from irony.el
+function(irony_find_package_version OUTPUT_VAR)
+ # this is a hack that force CMake to reconfigure, it is necessary to see if
+ # the version in irony.el has changed, this is not possible to add the
+ # definitions at build time
+ configure_file(${PROJECT_SOURCE_DIR}/../irony.el
+ ${CMAKE_CURRENT_BINARY_DIR}/irony.el
+ COPYONLY)
+
+ set(version_header "\;\; Version: ")
+ file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/irony.el version
+ LIMIT_COUNT 1
+ REGEX "^${version_header}*")
+
+ if (NOT version)
+ message (FATAL_ERROR "couldn't find irony.el's version header!")
+ endif()
+
+ string(LENGTH ${version_header} version_header_length)
+ string(SUBSTRING ${version} ${version_header_length} -1 package_version)
+ set(${OUTPUT_VAR} ${package_version} PARENT_SCOPE)
+endfunction()
+
+irony_find_package_version(IRONY_PACKAGE_VERSION)
+message(STATUS "Irony package version is '${IRONY_PACKAGE_VERSION}'")
+
+set_source_files_properties(main.cpp
+ PROPERTIES
+ COMPILE_DEFINITIONS IRONY_PACKAGE_VERSION=\"${IRONY_PACKAGE_VERSION}\")
+
+if (CLANG_RESOURCE_DIR)
+ # look for CLANG_RESOURCE_DIR_DIR usage in the code for an explanation
+ set_source_files_properties(TUManager.cpp
+ PROPERTIES
+ COMPILE_DEFINITIONS CLANG_RESOURCE_DIR=\"${CLANG_RESOURCE_DIR}\")
+endif()
+
+target_link_libraries(irony-server irony_libclang)
+
+set_target_properties(irony-server
+ PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
+
+install(TARGETS irony-server DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/elpa/irony-20220110.849/server/src/Command.cpp b/elpa/irony-20220110.849/server/src/Command.cpp
new file mode 100644
index 0000000..363b6cb
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Command.cpp
@@ -0,0 +1,278 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief Command parser definitions.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#include "Command.h"
+
+#include "support/CommandLineParser.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <map>
+
+
+namespace {
+
+struct StringConverter {
+ StringConverter(std::string *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ *dest_ = str;
+ return true;
+ }
+
+private:
+ std::string *dest_;
+};
+
+struct UnsignedIntConverter {
+ UnsignedIntConverter(unsigned *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ char *end;
+ long num = std::strtol(str.c_str(), &end, 10);
+
+ if (end != (str.c_str() + str.size()))
+ return false;
+
+ if (errno == ERANGE)
+ return false;
+
+ if (num < 0)
+ return false;
+
+ unsigned long unum = static_cast<unsigned long>(num);
+ if (unum > std::numeric_limits<unsigned>::max())
+ return false;
+
+ *dest_ = unum;
+ return true;
+ }
+
+private:
+ unsigned *dest_;
+};
+
+/// Convert "on" and "off" to a boolean
+struct OptionConverter {
+ OptionConverter(bool *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ if (str == "on") {
+ *dest_ = true;
+ } else if (str == "off") {
+ *dest_ = false;
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+private:
+ bool *dest_;
+};
+
+const std::map<std::string, PrefixMatchStyle> PREFIX_MATCH_STYLE_MAP = {
+ { "exact", PrefixMatchStyle::Exact },
+ { "case-insensitive", PrefixMatchStyle::CaseInsensitive },
+ { "smart-case", PrefixMatchStyle::SmartCase},
+};
+
+/// Convert style to a PrefixMatchStyle
+struct PrefixMatchStyleConverter {
+ PrefixMatchStyleConverter(PrefixMatchStyle *dest) : dest_(dest) {
+ }
+
+ bool operator()(const std::string &str) {
+ auto res = PREFIX_MATCH_STYLE_MAP.find(str);
+
+ if (res == PREFIX_MATCH_STYLE_MAP.cend()) {
+ return false;
+ }
+ *dest_ = res->second;
+ return true;
+ }
+
+private:
+ PrefixMatchStyle *dest_;
+};
+
+std::ostream &operator<<(std::ostream &os, PrefixMatchStyle style) {
+ for (auto it : PREFIX_MATCH_STYLE_MAP) {
+ if (it.second == style) {
+ os << it.first;
+ return os;
+ }
+ }
+ os << "UnknownStyle";
+ return os;
+}
+
+
+} // unnamed namespace
+
+std::ostream &operator<<(std::ostream &os, const Command::Action &action) {
+ os << "Command::";
+
+ switch (action) {
+#define X(sym, str, help) \
+ case Command::sym: \
+ os << #sym; \
+ break;
+#include "Commands.def"
+ }
+ return os;
+}
+
+std::ostream &operator<<(std::ostream &os, const Command &command) {
+ os << "Command{action=" << command.action << ", "
+ << "file='" << command.file << "', "
+ << "unsavedFile='" << command.unsavedFile << "', "
+ << "dir='" << command.dir << "', "
+ << "line=" << command.line << ", "
+ << "column=" << command.column << ", "
+ << "prefix='" << command.prefix << "', "
+ << "caseStyle='" << command.style << "', "
+ << "flags=[";
+ bool first = true;
+ for (const std::string &flag : command.flags) {
+ if (!first)
+ os << ", ";
+ os << "'" << flag << "'";
+ first = false;
+ }
+ os << "], "
+ << "opt=" << (command.opt ? "on" : "off");
+
+ return os << "}";
+}
+
+static Command::Action actionFromString(const std::string &actionStr) {
+#define X(sym, str, help) \
+ if (actionStr == str) \
+ return Command::sym;
+
+#include "Commands.def"
+
+ return Command::Unknown;
+}
+
+CommandParser::CommandParser() : tempFile_("irony-server") {
+}
+
+Command *CommandParser::parse(const std::vector<std::string> &argv) {
+ command_.clear();
+
+ if (argv.begin() == argv.end()) {
+ std::clog << "error: no command specified.\n"
+ "See 'irony-server help' to list available commands\n";
+ return 0;
+ }
+
+ const std::string &actionStr = argv[0];
+
+ command_.action = actionFromString(actionStr);
+
+ bool readCompileOptions = false;
+ std::vector<std::function<bool(const std::string &)>> positionalArgs;
+
+ switch (command_.action) {
+ case Command::SetDebug:
+ positionalArgs.push_back(OptionConverter(&command_.opt));
+ break;
+
+ case Command::Parse:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ readCompileOptions = true;
+ break;
+
+ case Command::Complete:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ positionalArgs.push_back(UnsignedIntConverter(&command_.line));
+ positionalArgs.push_back(UnsignedIntConverter(&command_.column));
+ readCompileOptions = true;
+ break;
+
+ case Command::GetType:
+ positionalArgs.push_back(UnsignedIntConverter(&command_.line));
+ positionalArgs.push_back(UnsignedIntConverter(&command_.column));
+ break;
+
+ case Command::SetUnsaved:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ positionalArgs.push_back(StringConverter(&command_.unsavedFile));
+ break;
+
+ case Command::ResetUnsaved:
+ positionalArgs.push_back(StringConverter(&command_.file));
+ break;
+
+ case Command::Candidates:
+ positionalArgs.push_back(StringConverter(&command_.prefix));
+ positionalArgs.push_back(PrefixMatchStyleConverter(&command_.style));
+ break;
+ case Command::CompletionDiagnostics:
+ case Command::Diagnostics:
+ case Command::Help:
+ case Command::Exit:
+ // no-arguments commands
+ break;
+
+ case Command::GetCompileOptions:
+ positionalArgs.push_back(StringConverter(&command_.dir));
+ positionalArgs.push_back(StringConverter(&command_.file));
+ break;
+
+ case Command::Unknown:
+ std::clog << "error: invalid command specified: " << actionStr << "\n";
+ return 0;
+ }
+
+ auto argsBegin = argv.begin() + 1;
+ const auto argsEnd = std::find(argsBegin, argv.end(), "--");
+ const int argCount = std::distance(argsBegin, argsEnd);
+
+ // compile options are provided after '--'
+ if (readCompileOptions && argsEnd != argv.end()) {
+ command_.flags.assign(std::next(argsEnd), argv.end());
+ }
+
+ if (argCount != static_cast<int>(positionalArgs.size())) {
+ std::clog << "error: invalid number of arguments for '" << actionStr
+ << "' (requires " << positionalArgs.size() << " got " << argCount
+ << ")\n";
+ return 0;
+ }
+
+ for (auto fn : positionalArgs) {
+ if (!fn(*argsBegin)) {
+ std::clog << "error: parsing command '" << actionStr
+ << "': invalid argument '" << *argsBegin << "'\n";
+ return 0;
+ }
+ ++argsBegin;
+ }
+
+ // '-' is used as a special file to inform that the buffer hasn't been saved
+ // on disk and only the buffer content is available. libclang needs a file, so
+ // this is treated as a special value for irony-server to create a temporary
+ // file for this. note that libclang will gladly accept '-' as a filename but
+ // we don't want to let this happen since irony already reads stdin.
+ if (command_.file == "-") {
+ command_.file = tempFile_.getPath();
+ }
+
+ return &command_;
+}
diff --git a/elpa/irony-20220110.849/server/src/Command.h b/elpa/irony-20220110.849/server/src/Command.h
new file mode 100644
index 0000000..9f36aa4
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Command.h
@@ -0,0 +1,73 @@
+/**-*-C++-*-
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief Command parser declarations.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_COMMAND_H_
+#define IRONY_MODE_SERVER_COMMAND_H_
+
+#include "support/CIndex.h"
+#include "support/TemporaryFile.h"
+#include "Style.h"
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+class TemporaryFile;
+
+// TODO: a tagged union?
+struct Command {
+ Command() {
+ clear();
+ }
+
+ void clear() {
+ action = Unknown;
+ flags.clear();
+ file.clear();
+ unsavedFile.clear();
+ dir.clear();
+ prefix.clear();
+ style = PrefixMatchStyle::Exact;
+ line = 0;
+ column = 0;
+ opt = false;
+ }
+
+#define X(sym, str, desc) sym,
+ enum Action {
+#include "Commands.def"
+ } action;
+
+ std::vector<std::string> flags;
+ std::string file;
+ std::string unsavedFile;
+ std::string dir;
+ std::string prefix;
+ PrefixMatchStyle style;
+ unsigned line;
+ unsigned column;
+ bool opt;
+};
+
+std::ostream &operator<<(std::ostream &os, const Command::Action &action);
+std::ostream &operator<<(std::ostream &os, const Command &command);
+
+class CommandParser {
+public:
+ CommandParser();
+
+ Command *parse(const std::vector<std::string> &argv);
+
+private:
+ Command command_;
+ TemporaryFile tempFile_;
+};
+
+#endif // IRONY_MODE_SERVER_COMMAND_H_
diff --git a/elpa/irony-20220110.849/server/src/Commands.def b/elpa/irony-20220110.849/server/src/Commands.def
new file mode 100644
index 0000000..f99d8af
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Commands.def
@@ -0,0 +1,39 @@
+/**-*-C++-*-
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief Command list.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef X
+#error Please define the 'X(id, command, description)' macro before inclusion!
+#endif
+
+X(Candidates, "candidates",
+ "PREFIX STYLE - print completion candidates (require previous complete). "
+ "STYLE is \"exact\", \"case-insensitive\" or \"smart-case\"")
+X(Complete, "complete",
+ "FILE LINE COL [-- [COMPILE_OPTIONS...]] - perform code completion at a given location")
+X(CompletionDiagnostics, "completion-diagnostics",
+ "print the diagnostics generated during complete")
+X(Diagnostics, "diagnostics", "print the diagnostics of the last parse")
+X(Exit, "exit", "exit interactive mode, print nothing")
+X(GetCompileOptions, "get-compile-options", "BUILD_DIR FILE - "
+ "get compile options for FILE from JSON database in BUILD_DIR")
+X(GetType, "get-type", "LINE COL - get type of symbol at a given location")
+X(Help, "help", "show this message")
+X(Parse, "parse", "FILE [-- [COMPILE_OPTIONS...]] - parse the given file")
+X(ResetUnsaved, "reset-unsaved", "FILE - reset FILE, its content is up to date")
+X(SetDebug, "set-debug", "ON|OFF - enable or disable verbose logging")
+X(SetUnsaved,
+ "set-unsaved",
+ "FILE UNSAVED-CONTENT-FILE - tell irony-server that "
+ "UNSAVED-CONTENT-FILE contains the effective content of FILE")
+
+// sentinel value, should be the last one
+X(Unknown, "<unkown>", "<unspecified>")
+
+#undef X
diff --git a/elpa/irony-20220110.849/server/src/CompDBCache.cpp b/elpa/irony-20220110.849/server/src/CompDBCache.cpp
new file mode 100644
index 0000000..f79ec8c
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/CompDBCache.cpp
@@ -0,0 +1,71 @@
+#include "CompDBCache.h"
+
+#include <sys/stat.h>
+
+#include <cassert>
+
+CompDBCache::CompDBCache()
+ : db_(nullptr), mtime_(0) {
+}
+
+CompDBCache::~CompDBCache() {
+ clear();
+}
+
+CXCompilationDatabase CompDBCache::fromDirectory(const std::string &buildDir,
+ CXCompilationDatabase_Error *error) {
+ assert(error != nullptr);
+
+ const std::string jsonFilename = constructJsonDbFilename(buildDir);
+ const time_t mtime = modificationTime(jsonFilename);
+
+ if (jsonFilename == filename_ && mtime != 0 && mtime == mtime_) {
+ // Using the cached compilation database.
+ // Just set the provided error code to indicate success.
+ *error = CXCompilationDatabase_NoError;
+ } else {
+ clear();
+
+ db_ = clang_CompilationDatabase_fromDirectory(buildDir.c_str(), error);
+
+ if (mtime != 0 && *error == CXCompilationDatabase_NoError) {
+ // Successfully loaded a JSON compilation database.
+ // Cache the result.
+ filename_ = jsonFilename;
+ mtime_ = mtime;
+ }
+ }
+
+ return db_;
+}
+
+void CompDBCache::clear() {
+ if (db_) {
+ clang_CompilationDatabase_dispose(db_);
+ db_ = nullptr;
+ filename_.clear();
+ mtime_ = 0;
+ }
+}
+
+std::string CompDBCache::constructJsonDbFilename(const std::string &buildDir) const {
+ std::string ret = buildDir;
+ if (!buildDir.empty() && buildDir.back() != '/')
+ ret += '/';
+ ret += "compile_commands.json";
+ return ret;
+}
+
+time_t CompDBCache::modificationTime(const std::string &filename) const {
+ time_t mtime = 0;
+#ifdef _WIN32
+ struct _stat st;
+ const int statRes = _stat(filename.c_str(), &st);
+#else
+ struct stat st;
+ const int statRes = stat(filename.c_str(), &st);
+#endif
+ if (statRes == 0)
+ mtime = st.st_mtime;
+ return mtime;
+}
diff --git a/elpa/irony-20220110.849/server/src/CompDBCache.h b/elpa/irony-20220110.849/server/src/CompDBCache.h
new file mode 100644
index 0000000..568b790
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/CompDBCache.h
@@ -0,0 +1,86 @@
+/**-*-C++-*-
+ * \file
+ * \author Idar Tollefsen <idart@hotmail.com>
+ *
+ * \brief Creates a compilation database and caches it.
+ *
+ * Keeps a cache of the loaded compilation database, only creating a new
+ * one when needed.
+ *
+ * This file is distributed under the GNU General Public License.
+ * See COPYING for details.
+ */
+
+#ifndef IRONY_MODE_COMPDBCACHE_H_
+#define IRONY_MODE_COMPDBCACHE_H_
+
+#include "support/CIndex.h"
+#include "support/NonCopyable.h"
+
+#include <ctime>
+#include <string>
+
+class CompDBCache : public util::NonCopyable {
+public:
+ CompDBCache();
+ ~CompDBCache();
+
+ /**
+ * \brief Get a compilation database from a database found in a directory.
+ *
+ * This in essence a wrapper around
+ * \c clang_CompilationDatabase_fromDirectory() with added caching.
+ * It will either create a new compilation database or return the
+ * already loaded one (if any).
+ *
+ * This class owns the resulting compilation database.
+ * Therefore, unlike \c clang_CompilationDatabase_fromDirectory(),
+ * callers must NOT call \c clang_CompilationDatabase_dispose() on the
+ * returned compilation database. This class will handle that internally.
+ *
+ * \param buildDir Directory containing the database (such as
+ * "compile_commands.json") to create a compilation
+ * database from.
+ * \param error Error code from attempting to create a compilation
+ * database (\c CXCompilationDatabase_NoError on success).
+ *
+ * \return The compilation database or nullptr.
+ */
+ CXCompilationDatabase fromDirectory(const std::string &buildDir,
+ CXCompilationDatabase_Error *error);
+
+private:
+ /**
+ * \brief Clear the cache.
+ *
+ * This will dispose the currently loaded compilation database (if any) by
+ * calling \c clang_CompilationDatabase_dispose() on it. And it will reset
+ * other internal housekeeping variables related to the caching of the
+ * compilation database.
+ */
+ void clear();
+
+ /**
+ * \brief Construct JSON compilation database filename.
+ *
+ * \param buildDir Directory that might contain "compile_commands.json".
+ *
+ * \return Path to "compilation_commands.json" in \c buildDir.
+ */
+ std::string constructJsonDbFilename(const std::string &buildDir) const;
+
+ /**
+ * \brief Get modification time of a file.
+ *
+ * \param filename The file to get last modification time of.
+ *
+ * \return The modification time of \c filename or 0.
+ */
+ time_t modificationTime(const std::string &filename) const;
+
+ CXCompilationDatabase db_;
+ std::string filename_;
+ time_t mtime_;
+};
+
+#endif
diff --git a/elpa/irony-20220110.849/server/src/Irony.cpp b/elpa/irony-20220110.849/server/src/Irony.cpp
new file mode 100644
index 0000000..2157b32
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Irony.cpp
@@ -0,0 +1,638 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief irony-server "API" definitions.
+ *
+ * \sa Irony.h for more information.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#include "Irony.h"
+
+#include "support/iomanip_quoted.h"
+
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+#include <fstream>
+#include <cctype>
+
+namespace {
+
+std::string cxStringToStd(CXString cxString) {
+ std::string stdStr;
+
+ if (const char *cstr = clang_getCString(cxString)) {
+ stdStr = cstr;
+ }
+
+ clang_disposeString(cxString);
+ return stdStr;
+}
+
+const char *diagnosticSeverity(const CXDiagnostic &diagnostic) {
+ switch (clang_getDiagnosticSeverity(diagnostic)) {
+ case CXDiagnostic_Ignored:
+ return "ignored";
+ case CXDiagnostic_Note:
+ return "note";
+ case CXDiagnostic_Warning:
+ return "warning";
+ case CXDiagnostic_Error:
+ return "error";
+ case CXDiagnostic_Fatal:
+ return "fatal";
+ }
+
+ return "unknown";
+}
+
+void dumpDiagnostic(const CXDiagnostic &diagnostic) {
+ std::string file;
+ unsigned line = 0, column = 0, offset = 0;
+ CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
+ if (!clang_equalLocations(location, clang_getNullLocation())) {
+ CXFile cxFile;
+
+// clang_getInstantiationLocation() has been marked deprecated and
+// is aimed to be replaced by clang_getExpansionLocation().
+#if CINDEX_VERSION >= 6
+ clang_getExpansionLocation(location, &cxFile, &line, &column, &offset);
+#else
+ clang_getInstantiationLocation(location, &cxFile, &line, &column, &offset);
+#endif
+
+ file = cxStringToStd(clang_getFileName(cxFile));
+ }
+
+ const char *severity = diagnosticSeverity(diagnostic);
+
+ std::string message = cxStringToStd(clang_getDiagnosticSpelling(diagnostic));
+
+ std::cout << '(' << support::quoted(file) //
+ << ' ' << line //
+ << ' ' << column //
+ << ' ' << offset //
+ << ' ' << severity //
+ << ' ' << support::quoted(message) //
+ << ")\n";
+}
+
+bool readFileContent(const std::string &filename,
+ Irony::UnsavedBuffer &outBuf) {
+ std::ifstream ifs(filename.c_str(),
+ std::ios::in | std::ios::binary | std::ios::ate);
+
+ if (!ifs.is_open()) {
+ return false;
+ }
+
+ // FIXME: it's possible that this method of reading the file is 100% reliable,
+ // I can't confirm that tellg() is guaranteed to return a byte count.
+ // std::streamoff does not mention 'byte'.
+ // In practice it seems to work but this may be just luck.
+ // See also this discussion:
+ // - http://stackoverflow.com/questions/22984956/tellg-function-give-wrong-size-of-file/22986486#22986486
+ auto nbytes = ifs.tellg();
+
+ if (nbytes == std::ifstream::pos_type(-1)) {
+ return false;
+ }
+
+ outBuf.resize(nbytes);
+ ifs.seekg(0, std::ios::beg);
+
+ ifs.read(&outBuf[0], outBuf.size());
+
+ if (!ifs){
+ outBuf.clear();
+ return false;
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+
+Irony::Irony()
+ : activeTu_(nullptr), activeCompletionResults_(nullptr), debug_(false) {
+}
+
+void Irony::parse(const std::string &file,
+ const std::vector<std::string> &flags) {
+ resetCache();
+ activeTu_ = tuManager_.parse(file, flags, cxUnsavedFiles_);
+ file_ = file;
+
+ if (activeTu_ == nullptr) {
+ std::cout << "(error . ("
+ << "parse-error"
+ << " \"failed to parse file\""
+ << " " << support::quoted(file) << "))\n";
+ return;
+ }
+
+ std::cout << "(success . t)\n";
+}
+
+void Irony::diagnostics() const {
+ unsigned diagnosticCount;
+
+ if (activeTu_ == nullptr) {
+ diagnosticCount = 0;
+ } else {
+ diagnosticCount = clang_getNumDiagnostics(activeTu_);
+ }
+
+ std::cout << "(\n";
+
+ for (unsigned i = 0; i < diagnosticCount; ++i) {
+ CXDiagnostic diagnostic = clang_getDiagnostic(activeTu_, i);
+
+ dumpDiagnostic(diagnostic);
+
+ clang_disposeDiagnostic(diagnostic);
+ }
+
+ std::cout << ")\n";
+}
+
+void Irony::resetCache() {
+ activeTu_ = nullptr;
+
+ if (activeCompletionResults_ != nullptr) {
+ clang_disposeCodeCompleteResults(activeCompletionResults_);
+ activeCompletionResults_ = nullptr;
+ }
+}
+
+void Irony::getType(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());
+ CXSourceLocation sourceLoc = clang_getLocation(activeTu_, cxFile, line, col);
+ CXCursor cursor = clang_getCursor(activeTu_, sourceLoc);
+
+ if (clang_Cursor_isNull(cursor)) {
+ // TODO: "error: no type at point"?
+ std::cout << "nil";
+ return;
+ }
+
+ CXType cxTypes[2];
+ cxTypes[0] = clang_getCursorType(cursor);
+ cxTypes[1] = clang_getCanonicalType(cxTypes[0]);
+
+ std::cout << "(";
+
+ for (const CXType &cxType : cxTypes) {
+ CXString typeDescr = clang_getTypeSpelling(cxType);
+ std::string typeStr = clang_getCString(typeDescr);
+ clang_disposeString(typeDescr);
+
+ if (typeStr.empty())
+ break;
+
+ std::cout << support::quoted(typeStr) << " ";
+ }
+
+ std::cout << ")\n";
+}
+
+namespace {
+
+class CompletionChunk {
+public:
+ explicit CompletionChunk(CXCompletionString completionString)
+ : completionString_(completionString)
+ , numChunks_(clang_getNumCompletionChunks(completionString_))
+ , chunkIdx_(0) {
+ }
+
+ bool hasNext() const {
+ return chunkIdx_ < numChunks_;
+ }
+
+ void next() {
+ if (!hasNext()) {
+ assert(0 && "out of range completion chunk");
+ abort();
+ }
+
+ ++chunkIdx_;
+ }
+
+ CXCompletionChunkKind kind() const {
+ return clang_getCompletionChunkKind(completionString_, chunkIdx_);
+ }
+
+ // TODO: operator>> so that one can re-use string allocated buffer
+ std::string text() const {
+ return cxStringToStd(
+ clang_getCompletionChunkText(completionString_, chunkIdx_));
+ }
+
+private:
+ CXCompletionString completionString_;
+ unsigned int numChunks_;
+ unsigned chunkIdx_;
+};
+
+} // unnamed namespace
+
+void Irony::complete(const std::string &file,
+ unsigned line,
+ unsigned col,
+ const std::vector<std::string> &flags) {
+ resetCache();
+
+ if (CXTranslationUnit tu =
+ tuManager_.getOrCreateTU(file, flags, cxUnsavedFiles_)) {
+ activeCompletionResults_ =
+ clang_codeCompleteAt(tu,
+ file.c_str(),
+ line,
+ col,
+ const_cast<CXUnsavedFile *>(cxUnsavedFiles_.data()),
+ cxUnsavedFiles_.size(),
+ (clang_defaultCodeCompleteOptions() &
+ ~CXCodeComplete_IncludeCodePatterns)
+#if HAS_BRIEF_COMMENTS_IN_COMPLETION
+ |
+ CXCodeComplete_IncludeBriefComments
+#endif
+ );
+ }
+
+ if (activeCompletionResults_ == nullptr) {
+ std::cout << "(error . ("
+ << "complete-error"
+ << " \"failed to perform code completion\""
+ << " " << support::quoted(file) << " " << line << " " << col
+ << "))\n";
+ return;
+ }
+
+ clang_sortCodeCompletionResults(activeCompletionResults_->Results,
+ activeCompletionResults_->NumResults);
+
+ std::cout << "(success . t)\n";
+}
+
+namespace {
+
+bool hasUppercase(const std::string &prefix)
+{
+ for (char c : prefix) {
+ if (std::isupper(c)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isEqual(const bool insensitive, const char a, const char b)
+{
+ if (insensitive) {
+ return std::tolower(a) == std::tolower(b);
+ } else {
+ return a == b;
+ }
+}
+
+bool startsWith(const std::string& str, const std::string &prefix, bool caseInsensitive)
+{
+ if (str.length() < prefix.length()) {
+ return false;
+ }
+
+ const auto charCmp = [&](const char a, const char b) {
+ return isEqual(caseInsensitive, a, b);
+ };
+
+ auto res = std::mismatch(prefix.begin(), prefix.end(), str.begin(), charCmp);
+ return res.first == prefix.end();
+}
+
+bool isStyleCaseInsensitive(const std::string &prefix, PrefixMatchStyle style)
+{
+ if (style == PrefixMatchStyle::SmartCase) {
+ // For SmartCase style, do case insensitive matching only there isn't upper
+ // case letter.
+ if (!hasUppercase(prefix)) {
+ style = PrefixMatchStyle::CaseInsensitive;
+ }
+ }
+ return style == PrefixMatchStyle::CaseInsensitive;
+}
+
+} // unnamed namespace
+
+void Irony::completionDiagnostics() const {
+ unsigned diagnosticCount;
+
+ if (activeCompletionResults_ == nullptr) {
+ diagnosticCount = 0;
+ } else {
+ diagnosticCount =
+ clang_codeCompleteGetNumDiagnostics(activeCompletionResults_);
+ }
+
+ std::cout << "(\n";
+
+ for (unsigned i = 0; i < diagnosticCount; ++i) {
+ CXDiagnostic diagnostic =
+ clang_codeCompleteGetDiagnostic(activeCompletionResults_, i);
+
+ dumpDiagnostic(diagnostic);
+ clang_disposeDiagnostic(diagnostic);
+ }
+
+ std::cout << ")\n";
+}
+
+void Irony::candidates(const std::string &prefix, PrefixMatchStyle style) const {
+ if (activeCompletionResults_ == nullptr) {
+ std::cout << "nil\n";
+ return;
+ }
+
+ bool caseInsensitive = isStyleCaseInsensitive(prefix, style);
+
+ CXCodeCompleteResults *completions = activeCompletionResults_;
+
+ std::cout << "(\n";
+
+ // re-use the same buffers to avoid unnecessary allocations
+ std::string typedtext, brief, resultType, prototype, postCompCar;
+
+ std::vector<unsigned> postCompCdr;
+
+ for (unsigned i = 0; i < completions->NumResults; ++i) {
+ CXCompletionResult candidate = completions->Results[i];
+ CXAvailabilityKind availability =
+ clang_getCompletionAvailability(candidate.CompletionString);
+
+ unsigned priority =
+ clang_getCompletionPriority(candidate.CompletionString);
+ unsigned annotationStart = 0;
+ bool typedTextSet = false;
+ bool hasPrefix = true;
+
+
+ if (availability == CXAvailability_NotAccessible ||
+ availability == CXAvailability_NotAvailable) {
+ continue;
+ }
+
+ typedtext.clear();
+ brief.clear();
+ resultType.clear();
+ prototype.clear();
+ postCompCar.clear();
+ postCompCdr.clear();
+
+ for (CompletionChunk chunk(candidate.CompletionString); chunk.hasNext();
+ chunk.next()) {
+ char ch = 0;
+
+ auto chunkKind = chunk.kind();
+
+ switch (chunkKind) {
+ case CXCompletionChunk_ResultType:
+ resultType = chunk.text();
+ break;
+
+ case CXCompletionChunk_TypedText:
+ case CXCompletionChunk_Text:
+ case CXCompletionChunk_Placeholder:
+ case CXCompletionChunk_Informative:
+ case CXCompletionChunk_CurrentParameter:
+ prototype += chunk.text();
+ break;
+
+ case CXCompletionChunk_LeftParen: ch = '('; break;
+ case CXCompletionChunk_RightParen: ch = ')'; break;
+ case CXCompletionChunk_LeftBracket: ch = '['; break;
+ case CXCompletionChunk_RightBracket: ch = ']'; break;
+ case CXCompletionChunk_LeftBrace: ch = '{'; break;
+ case CXCompletionChunk_RightBrace: ch = '}'; break;
+ case CXCompletionChunk_LeftAngle: ch = '<'; break;
+ case CXCompletionChunk_RightAngle: ch = '>'; break;
+ case CXCompletionChunk_Comma: ch = ','; break;
+ case CXCompletionChunk_Colon: ch = ':'; break;
+ case CXCompletionChunk_SemiColon: ch = ';'; break;
+ case CXCompletionChunk_Equal: ch = '='; break;
+ case CXCompletionChunk_HorizontalSpace: ch = ' '; break;
+ case CXCompletionChunk_VerticalSpace: ch = '\n'; break;
+
+ case CXCompletionChunk_Optional:
+ // ignored for now
+ break;
+ }
+
+ if (ch != 0) {
+ prototype += ch;
+ // commas look better followed by a space
+ if (ch == ',') {
+ prototype += ' ';
+ }
+ }
+
+ if (typedTextSet) {
+ if (ch != 0) {
+ postCompCar += ch;
+ if (ch == ',') {
+ postCompCar += ' ';
+ }
+ } else if (chunkKind == CXCompletionChunk_Text ||
+ chunkKind == CXCompletionChunk_TypedText) {
+ postCompCar += chunk.text();
+ } else if (chunkKind == CXCompletionChunk_Placeholder ||
+ chunkKind == CXCompletionChunk_CurrentParameter) {
+ postCompCdr.push_back(postCompCar.size());
+ postCompCar += chunk.text();
+ postCompCdr.push_back(postCompCar.size());
+ }
+ }
+
+ // Consider only the first typed text. The CXCompletionChunk_TypedText
+ // doc suggests that exactly one typed text will be given but at least
+ // in Objective-C it seems that more than one can appear, see:
+ // https://github.com/Sarcasm/irony-mode/pull/78#issuecomment-37115538
+ if (chunkKind == CXCompletionChunk_TypedText && !typedTextSet) {
+ typedtext = chunk.text();
+ if (!startsWith(typedtext, prefix, caseInsensitive)) {
+ hasPrefix = false;
+ break;
+ }
+ // annotation is what comes after the typedtext
+ annotationStart = prototype.size();
+ typedTextSet = true;
+ }
+ }
+
+ if (!hasPrefix) {
+ continue;
+ }
+ if (!typedTextSet) {
+ // clang may generate candidates without any typedText, and we may
+ // generate some output like:
+ // ("" 1 "bool" "" "hasUppercase(const std::string &prefix)"
+ // 0 ("") available)
+ // That will cause infinite completion in irony.el
+ continue;
+ }
+
+#if HAS_BRIEF_COMMENTS_IN_COMPLETION
+ brief = cxStringToStd(
+ clang_getCompletionBriefComment(candidate.CompletionString));
+#endif
+
+ // see irony-completion.el#irony-completion-candidates
+ std::cout << '(' << support::quoted(typedtext)
+ << ' ' << priority
+ << ' ' << support::quoted(resultType)
+ << ' ' << support::quoted(brief)
+ << ' ' << support::quoted(prototype)
+ << ' ' << annotationStart
+ << " (" << support::quoted(postCompCar);
+ for (unsigned index : postCompCdr)
+ std::cout << ' ' << index;
+ std::cout << ")"
+ << ")\n";
+ }
+
+ std::cout << ")\n";
+}
+
+void Irony::computeCxUnsaved() {
+ cxUnsavedFiles_.clear();
+
+ for (const auto &p : filenameToContent_) {
+ CXUnsavedFile cxUnsavedFile;
+
+ cxUnsavedFile.Filename = p.first.c_str();
+ cxUnsavedFile.Contents = p.second.data();
+ cxUnsavedFile.Length = p.second.size();
+ cxUnsavedFiles_.push_back(cxUnsavedFile);
+ }
+}
+
+void Irony::setUnsaved(const std::string &file,
+ const std::string &unsavedContentFile) {
+ resetCache();
+
+ UnsavedBuffer content;
+ if (!readFileContent(unsavedContentFile, content)) {
+ filenameToContent_.erase(file);
+ std::cout << "(error . ("
+ << "file-read-error"
+ << " \"failed to read unsaved buffer\""
+ << " " << support::quoted(file) << " "
+ << support::quoted(unsavedContentFile) << ")\n";
+ } else {
+ filenameToContent_[file] = content;
+ std::cout << "(success . t)\n";
+ }
+
+ computeCxUnsaved();
+}
+
+void Irony::resetUnsaved(const std::string &file) {
+ resetCache();
+
+ const auto erasedCount = filenameToContent_.erase(file);
+
+ if (erasedCount == 0) {
+ std::cout << "(error . ("
+ << "no-such-entry"
+ << " \"failed reset unsaved buffer\""
+ << " " << support::quoted(file) << ")\n";
+ } else {
+ std::cout << "(success . t)\n";
+ }
+
+ computeCxUnsaved();
+}
+
+void Irony::getCompileOptions(const std::string &buildDir,
+ const std::string &file) const {
+#if !(HAS_COMPILATION_DATABASE)
+
+ (void)buildDir;
+ (void)file;
+
+ CXString cxVersionString = clang_getClangVersion();
+
+ std::cout << "(error . ("
+ << "unsupported"
+ << " \"compilation database requires Clang >= 3.2\""
+ << " " << support::quoted(clang_getCString(cxVersionString))
+ << "))\n";
+
+ clang_disposeString(cxVersionString);
+
+ return;
+
+#else
+ CXCompilationDatabase_Error error;
+ CXCompilationDatabase db =
+ compDBCache_.fromDirectory(buildDir.c_str(), &error);
+
+ switch (error) {
+ case CXCompilationDatabase_CanNotLoadDatabase:
+ std::cout << "(error . ("
+ << "cannot-load-database"
+ << " \"failed to load compilation database from directory\""
+ << " " << support::quoted(buildDir) << "))\n";
+ return;
+
+ case CXCompilationDatabase_NoError:
+ break;
+ }
+
+ CXCompileCommands compileCommands =
+ clang_CompilationDatabase_getCompileCommands(db, file.c_str());
+
+ std::cout << "(success . (\n";
+
+ for (unsigned i = 0, numCompileCommands =
+ clang_CompileCommands_getSize(compileCommands);
+ i < numCompileCommands; ++i) {
+ CXCompileCommand compileCommand =
+ clang_CompileCommands_getCommand(compileCommands, i);
+
+ std::cout << "("
+ << "(";
+ for (unsigned j = 0,
+ numArgs = clang_CompileCommand_getNumArgs(compileCommand);
+ j < numArgs; ++j) {
+ CXString arg = clang_CompileCommand_getArg(compileCommand, j);
+ std::cout << support::quoted(clang_getCString(arg)) << " ";
+ clang_disposeString(arg);
+ }
+
+ std::cout << ")"
+ << " . ";
+
+ CXString directory = clang_CompileCommand_getDirectory(compileCommand);
+ std::cout << support::quoted(clang_getCString(directory));
+ clang_disposeString(directory);
+
+ std::cout << ")\n";
+ }
+
+ std::cout << "))\n";
+
+ clang_CompileCommands_dispose(compileCommands);
+#endif
+}
diff --git a/elpa/irony-20220110.849/server/src/Irony.h b/elpa/irony-20220110.849/server/src/Irony.h
new file mode 100644
index 0000000..66968f5
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Irony.h
@@ -0,0 +1,147 @@
+/**-*-C++-*-
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief irony-server "API" declarations.
+ *
+ * Contains the commands that the Emacs package relies on. These commands are
+ * mostly wrappers around a subset of the features provided by libclang. Command
+ * results are printed to \c std::cout as s-expr, in order to make it easy for
+ * Emacs to consume.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_IRONY_H_
+#define IRONY_MODE_SERVER_IRONY_H_
+
+#include "TUManager.h"
+
+#include "CompDBCache.h"
+#include "Style.h"
+
+#include <string>
+#include <vector>
+
+class Irony {
+public:
+ // use std::string over std::vector<char> because I have some doubts
+ // that libclang expect unsaved buffers to be a null terminated C strings
+ typedef std::string UnsavedBuffer;
+
+public:
+ Irony();
+
+ bool isDebugEnabled() const {
+ return debug_;
+ }
+
+ /// \name Command
+ /// \{
+
+ /// \brief Set or unset debugging of commands.
+ void setDebug(bool enable) {
+ debug_ = enable;
+ }
+
+ /// Parse or reparse the given file and compile options.
+ ///
+ /// If the compile options have changed, the translation unit is re-created to
+ /// take this into account.
+ ///
+ /// Output \c nil or \c t, whether or not parsing the translation unit
+ /// succeeded.
+ ///
+ /// \sa diagnostics(), getType()
+ void parse(const std::string &file, const std::vector<std::string> &flags);
+
+ /// Parse the given file for code completion.
+ ///
+ /// Shares the same semantics and output as \c parse().
+ ///
+ /// \sa candidates(), completionDiagnostics()
+ void complete(const std::string &file,
+ unsigned line,
+ unsigned col,
+ const std::vector<std::string> &flags);
+
+ void setUnsaved(const std::string &file,
+ const std::string &unsavedContentFile);
+
+ void resetUnsaved(const std::string &file);
+
+ /// \}
+
+ /// \name Queries
+ /// \{
+
+ /// \brief Retrieve the last parse diagnostics for the given file.
+ ///
+ /// \pre parse() was called.
+ void diagnostics() const;
+
+ /// \brief Get types of symbol at a given location.
+ ///
+ /// Example:
+ ///
+ /// \code
+ /// typedef int MyType;
+ /// MyType a;
+ /// \endcode
+ ///
+ /// Type of cursor location for 'a' is:
+ ///
+ /// \code{.el}
+ /// ("MyType" "int")
+ /// \endcode
+ ///
+ /// TODO: test with CXString(), seems to be twice the same string
+ ///
+ void getType(unsigned line, unsigned col) const;
+
+ /// Get all the completion candidates.
+ ///
+ /// \pre complete() was called.
+ void candidates(const std::string &prefix, PrefixMatchStyle style) const;
+
+ /// Get the diagnostics produced by the last \c complete().
+ ///
+ /// \pre complete() was called.
+ void completionDiagnostics() const;
+
+ /// \brief Get compile options from JSON database.
+ ///
+ /// \param buildDir Directory containing compile_commands.json
+ /// \param file File to obtain compile commands for.
+ ///
+ /// Example output:
+ ///
+ /// \code{.el}
+ /// (
+ /// (("-Wfoo" "-DBAR" "-Iqux") . "/path/to/working/directory")
+ /// (("-Wfoo-alt" "-DBAR_ALT" "-Iqux/alt") . "/alt/working/directory")
+ /// )
+ /// \endcode
+ ///
+ void getCompileOptions(const std::string &buildDir,
+ const std::string &file) const;
+
+ /// \}
+
+private:
+ void resetCache();
+ void computeCxUnsaved();
+
+private:
+ mutable CompDBCache compDBCache_;
+ TUManager tuManager_;
+ std::map<std::string, UnsavedBuffer> filenameToContent_;
+ CXTranslationUnit activeTu_;
+ std::string file_;
+ std::vector<CXUnsavedFile> cxUnsavedFiles_;
+ CXCodeCompleteResults *activeCompletionResults_;
+ bool debug_;
+};
+
+#endif // IRONY_MODE_SERVER_IRONY_H_
diff --git a/elpa/irony-20220110.849/server/src/Style.h b/elpa/irony-20220110.849/server/src/Style.h
new file mode 100644
index 0000000..52adb5e
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/Style.h
@@ -0,0 +1,17 @@
+/**-*-C++-*-
+ * \file
+ *
+ * \brief Style definition.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+#ifndef IRONY_MODE_SERVER_STYLE_H_
+#define IRONY_MODE_SERVER_STYLE_H_
+
+enum class PrefixMatchStyle {
+ Exact, CaseInsensitive, SmartCase,
+};
+
+
+#endif //IRONY_MODE_SERVER_STYLE_H_
diff --git a/elpa/irony-20220110.849/server/src/TUManager.cpp b/elpa/irony-20220110.849/server/src/TUManager.cpp
new file mode 100644
index 0000000..afbdc82
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/TUManager.cpp
@@ -0,0 +1,182 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief See TUManager.hh
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ *
+ */
+
+#include "TUManager.h"
+
+#include <iostream>
+
+TUManager::TUManager()
+ : index_(clang_createIndex(0, 0))
+ , translationUnits_()
+ , parseTUOptions_(clang_defaultEditingTranslationUnitOptions()) {
+
+ // this seems necessary to trigger "correct" reparse (/codeCompleteAt)
+ // clang_reparseTranslationUnit documentation states:
+ //
+ // > * \param TU The translation unit whose contents will be re-parsed. The
+ // > * translation unit must originally have been built with
+ // > * \c clang_createTranslationUnitFromSourceFile().
+ //
+ // clang_createTranslationUnitFromSourceFile() is just a call to
+ // clang_parseTranslationUnit() with
+ // CXTranslationUnit_DetailedPreprocessingRecord enabled but because we want
+ // some other flags to be set we can't just call
+ // clang_createTranslationUnitFromSourceFile()
+ parseTUOptions_ |= CXTranslationUnit_DetailedPreprocessingRecord;
+
+#if HAS_BRIEF_COMMENTS_IN_COMPLETION
+ parseTUOptions_ |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
+#endif
+
+ // XXX: A bug in old version of Clang (at least '3.1-8') caused the completion
+ // to fail on the standard library types when
+ // CXTranslationUnit_PrecompiledPreamble is used. We disable this option for
+ // old versions of libclang. As a result the completion will work but
+ // significantly slower.
+ //
+ // -- https://github.com/Sarcasm/irony-mode/issues/4
+ if (CINDEX_VERSION < 6) {
+ parseTUOptions_ &= ~CXTranslationUnit_PrecompiledPreamble;
+ }
+
+#if CINDEX_VERSION >= 34
+ // Keep going even after fatal errors, or syntax checking will stop after the
+ // first error. For instance unused variables will not be reported until the
+ // error has been fixed.
+ parseTUOptions_ |= CXTranslationUnit_KeepGoing;
+#endif
+}
+
+TUManager::~TUManager() {
+ clang_disposeIndex(index_);
+}
+
+CXTranslationUnit &TUManager::tuRef(const std::string &filename,
+ const std::vector<std::string> &flags) {
+ CXTranslationUnit &tu = translationUnits_[filename];
+
+ // if the flags changed since the last time, invalidate the translation unit
+ auto &flagsCache = flagsPerFileCache_[filename];
+ if (flagsCache.size() != flags.size() ||
+ !std::equal(flagsCache.begin(), flagsCache.end(), flags.begin())) {
+ if (tu) {
+ clang_disposeTranslationUnit(tu);
+ tu = nullptr;
+ }
+ // remember the flags for the next parse
+ flagsCache = flags;
+ }
+ return tu;
+}
+
+CXTranslationUnit
+TUManager::parse(const std::string &filename,
+ const std::vector<std::string> &flags,
+ const std::vector<CXUnsavedFile> &unsavedFiles) {
+ CXTranslationUnit &tu = tuRef(filename, flags);
+
+ if (tu == nullptr) {
+ std::vector<const char *> argv;
+
+#ifdef CLANG_RESOURCE_DIR
+ // Make sure libclang find its builtin headers, this is a known issue with
+ // libclang, see:
+ // - http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-July/022893.html
+ //
+ // > Make sure that Clang is using its own . It will be in a directory
+ // > ending in clang/3.2/include/ where 3.2 is the version of clang that you
+ // > are using. You may need to explicitly add it to your header search.
+ // > Usually clang finds this directory relative to the executable with
+ // > CompilerInvocation::GetResourcesPath(Argv0, MainAddr), but using just
+ // > the libraries, it can't automatically find it.
+ argv.push_back("-resource-dir");
+ argv.push_back(CLANG_RESOURCE_DIR);
+#endif
+
+ for (auto &flag : flags) {
+ argv.push_back(flag.c_str());
+ }
+
+ tu = clang_parseTranslationUnit(
+ index_,
+ filename.c_str(),
+ argv.data(),
+ static_cast<int>(argv.size()),
+ const_cast<CXUnsavedFile *>(unsavedFiles.data()),
+ unsavedFiles.size(),
+ parseTUOptions_);
+ }
+
+ if (tu == nullptr) {
+ std::clog << "error: libclang couldn't parse '" << filename << "'\n";
+ return nullptr;
+ }
+
+ // Reparsing is necessary to enable optimizations.
+ //
+ // From the clang mailing list (cfe-dev):
+ // From: Douglas Gregor
+ // Subject: Re: Clang indexing library performance
+ // ...
+ // You want to use the "default editing options" when parsing the translation
+ // unit
+ // clang_defaultEditingTranslationUnitOptions()
+ // and then reparse at least once. That will enable the various
+ // code-completion optimizations that should bring this time down
+ // significantly.
+ if (clang_reparseTranslationUnit(
+ tu,
+ unsavedFiles.size(),
+ const_cast<CXUnsavedFile *>(unsavedFiles.data()),
+ clang_defaultReparseOptions(tu))) {
+ // a 'fatal' error occured (even a diagnostic is impossible)
+ clang_disposeTranslationUnit(tu);
+ std::clog << "error: libclang couldn't reparse '" << filename << "'\n";
+ tu = 0;
+ return nullptr;
+ }
+
+ return tu;
+}
+
+CXTranslationUnit
+TUManager::getOrCreateTU(const std::string &filename,
+ const std::vector<std::string> &flags,
+ const std::vector<CXUnsavedFile> &unsavedFiles) {
+ if (auto tu = tuRef(filename, flags))
+ return tu;
+
+ return parse(filename, flags, unsavedFiles);
+}
+
+void TUManager::invalidateCachedTU(const std::string &filename) {
+ TranslationUnitsMap::iterator it = translationUnits_.find(filename);
+
+ if (it != translationUnits_.end()) {
+ if (CXTranslationUnit &tu = it->second)
+ clang_disposeTranslationUnit(tu);
+
+ translationUnits_.erase(it);
+ }
+}
+
+void TUManager::invalidateAllCachedTUs() {
+ TranslationUnitsMap::iterator it = translationUnits_.begin();
+
+ while (it != translationUnits_.end()) {
+ if (CXTranslationUnit &tu = it->second) {
+ clang_disposeTranslationUnit(tu);
+ translationUnits_.erase(it++); // post-increment keeps the iterator valid
+ } else {
+ ++it;
+ }
+ }
+}
diff --git a/elpa/irony-20220110.849/server/src/TUManager.h b/elpa/irony-20220110.849/server/src/TUManager.h
new file mode 100644
index 0000000..bd7730d
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/TUManager.h
@@ -0,0 +1,109 @@
+/**-*-C++-*-
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief Translation Unit manager.
+ *
+ * Keeps a cache of translation units, reparsing or recreating them as
+ * necessary.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_TUMANAGER_H_
+#define IRONY_MODE_SERVER_TUMANAGER_H_
+
+#include "support/CIndex.h"
+#include "support/NonCopyable.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+class TUManager : public util::NonCopyable {
+public:
+ TUManager();
+ ~TUManager();
+
+ /**
+ * \brief Parse \p filename with flag \p flags.
+ *
+ * The first time call \c clang_parseTranslationUnit() and save the TU in the
+ * member \c translationUnits_, The next call with the same \p filename will
+ * call \c clang_reparseTranslationUnit().
+ *
+ * usage:
+ * \code
+ * std::vector<std::string> flags;
+ * flags.push_back("-I../utils");
+ * CXTranslationUnit tu = tuManager.parse("file.cpp", flags);
+ *
+ * if (! tu)
+ * std::cerr << "parsing translation unit failed\n";
+ * \endcode
+ *
+ * \return The translation unit, if the parsing failed the translation unit
+ * will be \c NULL.
+ */
+ CXTranslationUnit parse(const std::string &filename,
+ const std::vector<std::string> &flags,
+ const std::vector<CXUnsavedFile> &unsavedFiles);
+
+ /**
+ * \brief Retrieve, creating it if necessary the TU associated to filename.
+ *
+ * \return The translation unit. Will be NULL if the translation unit couldn't
+ * be created.
+ */
+ CXTranslationUnit getOrCreateTU(const std::string &filename,
+ const std::vector<std::string> &flags,
+ const std::vector<CXUnsavedFile> &unsavedFiles);
+
+ /**
+ * \brief Invalidate a given cached TU, the next use of a TU will require
+ * reparsing.
+ *
+ * This can be useful for example: when the flags used to compile a file have
+ * changed.
+ *
+ * \param filename The filename for which the associated
+ * translation unit flags need to be invalidated.
+ *
+ * \sa invalidateAllCachedTUs()
+ */
+ void invalidateCachedTU(const std::string &filename);
+
+ /**
+ * \brief Invalidate all cached TU, the next use of a TU will require
+ * reparsing.
+ *
+ * \sa invalidateCachedTU()
+ */
+ void invalidateAllCachedTUs();
+
+private:
+ /**
+ * \brief Get a reference to the translation unit that matches \p filename
+ * with the given set of flags.
+ *
+ * The TU will be null if it has never been parsed or if the flags have
+ * changed.
+ *
+ * \todo Find a proper name.
+ */
+ CXTranslationUnit &tuRef(const std::string &filename,
+ const std::vector<std::string> &flags);
+
+private:
+ typedef std::map<const std::string, CXTranslationUnit> TranslationUnitsMap;
+ typedef std::map<const std::string, std::vector<std::string>> FilenameFlagsMap;
+
+private:
+ CXIndex index_;
+ TranslationUnitsMap translationUnits_; // cache variable
+ FilenameFlagsMap flagsPerFileCache_;
+ unsigned parseTUOptions_;
+};
+
+#endif /* !IRONY_MODE_SERVER_TUMANAGER_H_ */
diff --git a/elpa/irony-20220110.849/server/src/main.cpp b/elpa/irony-20220110.849/server/src/main.cpp
new file mode 100644
index 0000000..7797528
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/main.cpp
@@ -0,0 +1,235 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#include "Irony.h"
+#include "Command.h"
+
+#include "support/CIndex.h"
+#include "support/CommandLineParser.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+static void printHelp() {
+ std::cout << "usage: irony-server [OPTIONS...] [COMMAND] [ARGS...]\n"
+ "\n"
+ "Options:\n"
+ " -v, --version\n"
+ " -h, --help\n"
+ " -i, --interactive\n"
+ " -d, --debug\n"
+ " --log-file PATH\n"
+ "\n"
+ "Commands:\n";
+
+#define X(sym, str, desc) \
+ if (Command::sym != Command::Unknown) \
+ std::cout << std::left << std::setw(25) << " " str << desc << "\n";
+#include "Commands.def"
+}
+
+static void printVersion() {
+ // do not change the format for the first line, external programs should be
+ // able to rely on it
+ std::cout << "irony-server version " IRONY_PACKAGE_VERSION "\n";
+
+ CXString cxVersionString = clang_getClangVersion();
+ std::cout << clang_getCString(cxVersionString) << "\n";
+ clang_disposeString(cxVersionString);
+}
+
+struct CommandProviderInterface {
+ virtual ~CommandProviderInterface() { }
+
+ virtual std::vector<std::string> nextCommand() = 0;
+};
+
+struct CommandLineCommandProvider : CommandProviderInterface {
+ CommandLineCommandProvider(const std::vector<std::string> &argv)
+ : argv_(argv), firstCall_(true) {
+ }
+
+ std::vector<std::string> nextCommand() {
+ if (firstCall_) {
+ firstCall_ = false;
+ return argv_;
+ }
+
+ return std::vector<std::string>(1, "exit");
+ }
+
+private:
+ std::vector<std::string> argv_;
+ bool firstCall_;
+};
+
+struct InteractiveCommandProvider : CommandProviderInterface {
+ std::vector<std::string> nextCommand() {
+ std::string line;
+
+ if (std::getline(std::cin, line)) {
+ return unescapeCommandLine(line);
+ }
+
+ return std::vector<std::string>(1, "exit");
+ }
+};
+
+struct RestoreClogOnExit {
+ RestoreClogOnExit() : rdbuf_(std::clog.rdbuf()) {
+ }
+
+ ~RestoreClogOnExit() {
+ std::clog.rdbuf(rdbuf_);
+ }
+
+private:
+ RestoreClogOnExit(const RestoreClogOnExit &);
+ RestoreClogOnExit &operator=(const RestoreClogOnExit &);
+
+private:
+ std::streambuf *rdbuf_;
+};
+
+int main(int ac, const char *av[]) {
+ std::vector<std::string> argv(&av[1], &av[ac]);
+
+ // stick to STL streams, no mix of C and C++ for IO operations
+ std::ios_base::sync_with_stdio(false);
+
+ bool interactiveMode = false;
+
+ Irony irony;
+
+ if (ac == 1) {
+ printHelp();
+ return 1;
+ }
+
+ std::ofstream logFile;
+
+ // When logging to a specific file, std::clog.rdbuf() is replaced by the log
+ // file's one. When we return from the main, this buffer is deleted (at the
+ // same time as logFile) but std::clog is still active, and will try to
+ // release the rdbuf() which has already been released in logFile's
+ // destructor. To avoid this we restore std::clog()'s original rdbuf on exit.
+ RestoreClogOnExit clogBufferRestorer;
+
+ unsigned optCount = 0;
+ while (optCount < argv.size()) {
+ const std::string &opt = argv[optCount];
+
+ if (opt.c_str()[0] != '-')
+ break;
+
+ if (opt == "--help" || opt == "-h") {
+ printHelp();
+ return 0;
+ }
+
+ if (opt == "--version" || opt == "-v") {
+ printVersion();
+ return 0;
+ }
+
+ if (opt == "--interactive" || opt == "-i") {
+ interactiveMode = true;
+ } else if (opt == "--debug" || opt == "-d") {
+ irony.setDebug(true);
+ } else if (opt == "--log-file" && (optCount + 1) < argv.size()) {
+ ++optCount;
+ logFile.open(argv[optCount]);
+ std::clog.rdbuf(logFile.rdbuf());
+ } else {
+ std::cerr << "error: invalid option '" << opt << "'\n";
+ return 1;
+ }
+
+ ++optCount;
+ }
+
+ argv.erase(argv.begin(), argv.begin() + optCount);
+
+ CommandParser commandParser;
+ std::unique_ptr<CommandProviderInterface> commandProvider;
+
+ if (interactiveMode) {
+ commandProvider.reset(new InteractiveCommandProvider());
+ } else {
+ commandProvider.reset(new CommandLineCommandProvider(argv));
+ }
+
+ while (Command *c = commandParser.parse(commandProvider->nextCommand())) {
+ if (c->action != Command::Exit) {
+ std::clog << "execute: " << *c << std::endl;
+ }
+
+ switch (c->action) {
+ case Command::Help:
+ printHelp();
+ break;
+
+ case Command::Candidates:
+ irony.candidates(c->prefix, c->style);
+ break;
+
+ case Command::CompletionDiagnostics:
+ irony.completionDiagnostics();
+ break;
+
+ case Command::Complete:
+ irony.complete(c->file, c->line, c->column, c->flags);
+ break;
+
+ case Command::Diagnostics:
+ irony.diagnostics();
+ break;
+
+ case Command::Exit:
+ return 0;
+
+ case Command::GetCompileOptions:
+ irony.getCompileOptions(c->dir, c->file);
+ break;
+
+ case Command::GetType:
+ irony.getType(c->line, c->column);
+ break;
+
+ case Command::Parse:
+ irony.parse(c->file, c->flags);
+ break;
+
+ case Command::SetDebug:
+ irony.setDebug(c->opt);
+ break;
+
+ case Command::SetUnsaved:
+ irony.setUnsaved(c->file, c->unsavedFile);
+ break;
+
+ case Command::ResetUnsaved:
+ irony.resetUnsaved(c->file);
+ break;
+
+ case Command::Unknown:
+ assert(0 && "unreacheable code...reached!");
+ break;
+ }
+
+ std::cout << "\n;;EOT\n" << std::flush;
+ }
+
+ return 1;
+}
diff --git a/elpa/irony-20220110.849/server/src/support/CIndex.h b/elpa/irony-20220110.849/server/src/support/CIndex.h
new file mode 100644
index 0000000..89d3f62
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/CIndex.h
@@ -0,0 +1,33 @@
+/**
+ * \file
+ * \brief Wrapper around Clang Indexing Public C Interface header.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_SUPPORT_CINDEXVERSION_H_
+#define IRONY_MODE_SERVER_SUPPORT_CINDEXVERSION_H_
+
+#include <clang-c/Index.h>
+
+/// Use <tt>\#if CINDEX_VERSION_VERSION > 10047</tt> to test for
+/// CINDEX_VERSION_MAJOR = 1 and CINDEX_VERSION_MINOR = 47.
+#ifndef CINDEX_VERSION
+#define CINDEX_VERSION 0 // pre-clang 3.2 support
+#endif
+
+#if CINDEX_VERSION >= 6
+#define HAS_BRIEF_COMMENTS_IN_COMPLETION 1
+#else
+#define HAS_BRIEF_COMMENTS_IN_COMPLETION 0
+#endif
+
+#if CINDEX_VERSION >= 6
+#define HAS_COMPILATION_DATABASE 1
+#include <clang-c/CXCompilationDatabase.h>
+#else
+#define HAS_COMPILATION_DATABASE 0
+#endif
+
+#endif /* !IRONY_MODE_SERVER_SUPPORT_CINDEXVERSION_H_ */
diff --git a/elpa/irony-20220110.849/server/src/support/CommandLineParser.cpp b/elpa/irony-20220110.849/server/src/support/CommandLineParser.cpp
new file mode 100644
index 0000000..a838092
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/CommandLineParser.cpp
@@ -0,0 +1,119 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#include "CommandLineParser.h"
+
+namespace {
+
+/// \brief A parser for escaped strings of command line arguments.
+///
+/// Assumes \-escaping for quoted arguments (see the documentation of
+/// unescapeCommandLine(...)).
+class CommandLineArgumentParser {
+public:
+ CommandLineArgumentParser(const std::string &commandLine)
+ : input_(commandLine), position_(input_.begin() - 1) {
+ }
+
+ std::vector<std::string> parse() {
+ bool hasMoreInput = true;
+ while (hasMoreInput && nextNonWhitespace()) {
+ std::string argument;
+ hasMoreInput = parseStringInto(argument);
+ commandLine_.push_back(argument);
+ }
+ return commandLine_;
+ }
+
+private:
+ // All private methods return true if there is more input available.
+
+ bool parseStringInto(std::string &string) {
+ do {
+ if (*position_ == '"') {
+ if (!parseDoubleQuotedStringInto(string))
+ return false;
+ } else if (*position_ == '\'') {
+ if (!parseSingleQuotedStringInto(string))
+ return false;
+ } else {
+ if (!parseFreeStringInto(string))
+ return false;
+ }
+ } while (*position_ != ' ');
+ return true;
+ }
+
+ bool parseDoubleQuotedStringInto(std::string &string) {
+ if (!next())
+ return false;
+ while (*position_ != '"') {
+ if (!skipEscapeCharacter())
+ return false;
+ string.push_back(*position_);
+ if (!next())
+ return false;
+ }
+ return next();
+ }
+
+ bool parseSingleQuotedStringInto(std::string &string) {
+ if (!next())
+ return false;
+ while (*position_ != '\'') {
+ string.push_back(*position_);
+ if (!next())
+ return false;
+ }
+ return next();
+ }
+
+ bool parseFreeStringInto(std::string &string) {
+ do {
+ if (!skipEscapeCharacter())
+ return false;
+ string.push_back(*position_);
+ if (!next())
+ return false;
+ } while (*position_ != ' ' && *position_ != '"' && *position_ != '\'');
+ return true;
+ }
+
+ bool skipEscapeCharacter() {
+ if (*position_ == '\\') {
+ return next();
+ }
+ return true;
+ }
+
+ bool nextNonWhitespace() {
+ do {
+ if (!next())
+ return false;
+ } while (*position_ == ' ');
+ return true;
+ }
+
+ bool next() {
+ ++position_;
+ return position_ != input_.end();
+ }
+
+private:
+ const std::string input_;
+ std::string::const_iterator position_;
+ std::vector<std::string> commandLine_;
+};
+
+} // unnamed namespace
+
+std::vector<std::string>
+unescapeCommandLine(const std::string &escapedCommandLine) {
+ CommandLineArgumentParser parser(escapedCommandLine);
+ return parser.parse();
+}
diff --git a/elpa/irony-20220110.849/server/src/support/CommandLineParser.h b/elpa/irony-20220110.849/server/src/support/CommandLineParser.h
new file mode 100644
index 0000000..b764797
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/CommandLineParser.h
@@ -0,0 +1,21 @@
+/**
+ * \file
+ * \brief Facility to parse a command line into a string array.
+ *
+ * \note Please note that the code borrowed from the Clang,
+ * lib/Tooling/JSONCompilationDatabase.cpp.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_SUPPORT_COMMAND_LINE_PARSER_H_
+#define IRONY_MODE_SERVER_SUPPORT_COMMAND_LINE_PARSER_H_
+
+#include <string>
+#include <vector>
+
+std::vector<std::string>
+unescapeCommandLine(const std::string &escapedCommandLine);
+
+#endif // IRONY_MODE_SERVER_SUPPORT_COMMAND_LINE_PARSER_H_
diff --git a/elpa/irony-20220110.849/server/src/support/NonCopyable.h b/elpa/irony-20220110.849/server/src/support/NonCopyable.h
new file mode 100644
index 0000000..d30a5b2
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/NonCopyable.h
@@ -0,0 +1,34 @@
+/**-*-C++-*-
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief NonCopyable class like in Boost.
+ *
+ * \see http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-copyable_Mixin
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_SUPPORT_NONCOPYABLE_H_
+#define IRONY_MODE_SERVER_SUPPORT_NONCOPYABLE_H_
+
+namespace util {
+
+class NonCopyable {
+protected:
+ NonCopyable() {
+ }
+
+ // Protected non-virtual destructor
+ ~NonCopyable() {
+ }
+
+private:
+ NonCopyable(const NonCopyable &);
+ NonCopyable &operator=(const NonCopyable &);
+};
+
+} // ! namespace util
+
+#endif /* !IRONY_MODE_SERVER_SUPPORT_NONCOPYABLE_H_ */
diff --git a/elpa/irony-20220110.849/server/src/support/TemporaryFile.cpp b/elpa/irony-20220110.849/server/src/support/TemporaryFile.cpp
new file mode 100644
index 0000000..e7393e1
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/TemporaryFile.cpp
@@ -0,0 +1,74 @@
+/**
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#include "TemporaryFile.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <random>
+
+static std::string getTemporaryFileDirectory() {
+ const char *temporaryDirEnvVars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
+
+ for (const char *envVar : temporaryDirEnvVars) {
+ if (const char *dir = std::getenv(envVar))
+ return dir;
+ }
+
+ return "/tmp";
+}
+
+TemporaryFile::TemporaryFile(const std::string &prefix,
+ const std::string &suffix)
+ : pathOrPattern_(prefix + "-%%%%%%" + suffix) {
+}
+
+TemporaryFile::~TemporaryFile() {
+ if (openedFile_) {
+ openedFile_.reset();
+ std::remove(pathOrPattern_.c_str());
+ }
+}
+
+const std::string &TemporaryFile::getPath() {
+ if (!openedFile_) {
+ openedFile_.reset(new std::fstream);
+
+ std::random_device rd;
+ std::default_random_engine e(rd());
+ std::uniform_int_distribution<int> dist(0, 15);
+ std::string pattern = pathOrPattern_;
+ std::string tmpDir = getTemporaryFileDirectory() + "/";
+ int i = 0;
+
+ do {
+ // exiting is better than infinite loop
+ if (++i > TemporaryFile::MAX_ATTEMPS) {
+ std::cerr << "error: couldn't create temporary file, please check your "
+ "temporary file directory (" << tmpDir << ")\n";
+ exit(EXIT_FAILURE);
+ }
+
+ // make the filename based on the pattern
+ std::transform(pattern.begin(),
+ pattern.end(),
+ pathOrPattern_.begin(),
+ [&e, &dist](char ch) {
+ return ch == '%' ? "0123456789abcdef"[dist(e)] : ch;
+ });
+ // create the file
+ openedFile_->open(tmpDir + pathOrPattern_, std::ios_base::out);
+ } while (!openedFile_->is_open());
+ pathOrPattern_ = tmpDir + pathOrPattern_;
+ }
+
+ return pathOrPattern_;
+}
diff --git a/elpa/irony-20220110.849/server/src/support/TemporaryFile.h b/elpa/irony-20220110.849/server/src/support/TemporaryFile.h
new file mode 100644
index 0000000..5bf77f4
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/TemporaryFile.h
@@ -0,0 +1,36 @@
+/**-*-C++-*-
+ * \file
+ * \author Guillaume Papin <guillaume.papin@epitech.eu>
+ *
+ * \brief Not the best piece of code out there.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_SUPPORT_TEMPORARY_FILE_H_
+#define IRONY_MODE_SERVER_SUPPORT_TEMPORARY_FILE_H_
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+
+class TemporaryFile {
+ enum {
+ // if we can't create the temp file, exits.
+ MAX_ATTEMPS = 25
+ };
+
+public:
+ TemporaryFile(const std::string &prefix, const std::string &suffix = "");
+ ~TemporaryFile();
+
+ /// Returns the path of this temporary filename
+ const std::string &getPath();
+
+private:
+ std::string pathOrPattern_;
+ std::unique_ptr<std::fstream> openedFile_;
+};
+
+#endif // IRONY_MODE_SERVER_SUPPORT_TEMPORARY_FILE_H_
diff --git a/elpa/irony-20220110.849/server/src/support/iomanip_quoted.h b/elpa/irony-20220110.849/server/src/support/iomanip_quoted.h
new file mode 100644
index 0000000..a8ca38b
--- /dev/null
+++ b/elpa/irony-20220110.849/server/src/support/iomanip_quoted.h
@@ -0,0 +1,52 @@
+/**-*-C++-*-
+ * \file
+ * \brief Dumb implementation of something that might look like C++14
+ * std::quoted.
+ *
+ * This file is distributed under the GNU General Public License. See
+ * COPYING for details.
+ */
+
+#ifndef IRONY_MODE_SERVER_SUPPORT_IOMANIP_QUOTED_H_
+#define IRONY_MODE_SERVER_SUPPORT_IOMANIP_QUOTED_H_
+
+#include <ostream>
+#include <string>
+
+namespace support {
+namespace detail {
+
+struct QuotedStringProxy {
+ QuotedStringProxy(const std::string &s) : s(s) {
+ }
+
+ std::string s;
+};
+
+std::ostream &operator<<(std::ostream &os, const QuotedStringProxy &q) {
+ const std::string &s = q.s;
+
+ os << '"';
+ if (s.find_first_of("\"\\") == std::string::npos) {
+ os << s;
+ } else {
+ for (auto ch : s) {
+ if (ch == '\\' || ch == '"')
+ os << '\\';
+
+ os << ch;
+ }
+ }
+ os << '"';
+ return os;
+}
+
+} // namespace detail
+
+detail::QuotedStringProxy quoted(const std::string &s) {
+ return detail::QuotedStringProxy(s);
+}
+
+} // namespace support
+
+#endif // IRONY_MODE_SERVER_SUPPORT_IOMANIP_QUOTED_H_