diff options
author | mattkae <mattkae@protonmail.com> | 2022-06-07 08:23:47 -0400 |
---|---|---|
committer | mattkae <mattkae@protonmail.com> | 2022-06-07 08:23:47 -0400 |
commit | bd18a38c2898548a3664a9ddab9f79c84f2caf4a (patch) | |
tree | 95b9933376770381bd8859782ae763be81c2d72b /elpa/irony-20220110.849/server/src/Irony.cpp | |
parent | b07628dddf418d4f47b858e6c35fd3520fbaeed2 (diff) | |
parent | ef160dea332af4b4fe5e2717b962936c67e5fe9e (diff) |
Merge conflict
Diffstat (limited to 'elpa/irony-20220110.849/server/src/Irony.cpp')
-rw-r--r-- | elpa/irony-20220110.849/server/src/Irony.cpp | 638 |
1 files changed, 0 insertions, 638 deletions
diff --git a/elpa/irony-20220110.849/server/src/Irony.cpp b/elpa/irony-20220110.849/server/src/Irony.cpp deleted file mode 100644 index 2157b32..0000000 --- a/elpa/irony-20220110.849/server/src/Irony.cpp +++ /dev/null @@ -1,638 +0,0 @@ -/** - * \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 -} |