mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 15:45:08 +00:00
If clang >= 8, delete search path detection and use Sema::CodeCompleteIncludedFile
This commit is contained in:
parent
444f0db1f2
commit
d398e071dc
@ -131,13 +131,6 @@ struct PreambleData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string StripFileType(const std::string &path) {
|
|
||||||
SmallString<128> Ret;
|
|
||||||
sys::path::append(Ret, sys::path::parent_path(path), sys::path::stem(path));
|
|
||||||
return sys::path::convert_to_slash(Ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocationInRange(SourceLocation L, CharSourceRange R,
|
bool LocationInRange(SourceLocation L, CharSourceRange R,
|
||||||
const SourceManager &M) {
|
const SourceManager &M) {
|
||||||
assert(R.isCharRange());
|
assert(R.isCharRange());
|
||||||
@ -260,23 +253,16 @@ public:
|
|||||||
std::unique_ptr<CompilerInstance> BuildCompilerInstance(
|
std::unique_ptr<CompilerInstance> BuildCompilerInstance(
|
||||||
CompletionSession &session, std::unique_ptr<CompilerInvocation> CI,
|
CompletionSession &session, std::unique_ptr<CompilerInvocation> CI,
|
||||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, DiagnosticConsumer &DC,
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, DiagnosticConsumer &DC,
|
||||||
const PreambleData *preamble, const WorkingFiles::Snapshot &snapshot,
|
const PreambleData *preamble, const std::string &path,
|
||||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Bufs) {
|
std::unique_ptr<llvm::MemoryBuffer> &Buf) {
|
||||||
std::string main = ResolveIfRelative(
|
if (preamble) {
|
||||||
session.file.directory,
|
|
||||||
sys::path::convert_to_slash(CI->getFrontendOpts().Inputs[0].getFile()));
|
|
||||||
for (auto &file : snapshot.files) {
|
|
||||||
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(file.content));
|
|
||||||
if (preamble && file.filename == main) {
|
|
||||||
#if LLVM_VERSION_MAJOR >= 7
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
preamble->Preamble.OverridePreamble(*CI, FS, Bufs.back().get());
|
preamble->Preamble.OverridePreamble(*CI, FS, Buf.get());
|
||||||
#else
|
#else
|
||||||
preamble->Preamble.AddImplicitPreamble(*CI, FS, Bufs.back().get());
|
preamble->Preamble.AddImplicitPreamble(*CI, FS, Buf.get());
|
||||||
#endif
|
#endif
|
||||||
continue;
|
} else {
|
||||||
}
|
CI->getPreprocessorOpts().addRemappedFile(path, Buf.get());
|
||||||
CI->getPreprocessorOpts().addRemappedFile(file.filename,
|
|
||||||
Bufs.back().get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Clang = std::make_unique<CompilerInstance>(session.PCH);
|
auto Clang = std::make_unique<CompilerInstance>(session.PCH);
|
||||||
@ -347,8 +333,6 @@ void *CompletionPreloadMain(void *manager_) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto &args = session->file.args;
|
const auto &args = session->file.args;
|
||||||
WorkingFiles::Snapshot snapshot =
|
|
||||||
session->wfiles->AsSnapshot({StripFileType(session->file.filename)});
|
|
||||||
auto stat_cache = std::make_unique<PreambleStatCache>();
|
auto stat_cache = std::make_unique<PreambleStatCache>();
|
||||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
|
||||||
stat_cache->Producer(session->FS);
|
stat_cache->Producer(session->FS);
|
||||||
@ -404,18 +388,23 @@ void *CompletionMain(void *manager_) {
|
|||||||
CI->getLangOpts()->CommentOpts.ParseAllComments = true;
|
CI->getLangOpts()->CommentOpts.ParseAllComments = true;
|
||||||
|
|
||||||
DiagnosticConsumer DC;
|
DiagnosticConsumer DC;
|
||||||
WorkingFiles::Snapshot snapshot =
|
std::string content = manager->wfiles_->GetContent(path);
|
||||||
manager->wfiles_->AsSnapshot({StripFileType(path)});
|
auto Buf = llvm::MemoryBuffer::getMemBuffer(content);
|
||||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
|
bool in_preamble =
|
||||||
|
GetOffsetForPosition(
|
||||||
|
{request->position.line, request->position.character}, content) <
|
||||||
|
ComputePreambleBounds(*CI->getLangOpts(), Buf.get(), 0).Size;
|
||||||
|
if (in_preamble)
|
||||||
|
preamble.reset();
|
||||||
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
|
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
|
||||||
preamble.get(), snapshot, Bufs);
|
preamble.get(), path, Buf);
|
||||||
if (!Clang)
|
if (!Clang)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Clang->getPreprocessorOpts().SingleFileParseMode = in_preamble;
|
||||||
Clang->setCodeCompletionConsumer(request->Consumer.release());
|
Clang->setCodeCompletionConsumer(request->Consumer.release());
|
||||||
if (!Parse(*Clang))
|
if (!Parse(*Clang))
|
||||||
continue;
|
continue;
|
||||||
for (auto &Buf : Bufs)
|
|
||||||
Buf.release();
|
Buf.release();
|
||||||
|
|
||||||
request->on_complete(&Clang->getCodeCompletionConsumer());
|
request->on_complete(&Clang->getCodeCompletionConsumer());
|
||||||
@ -471,6 +460,7 @@ void *DiagnosticMain(void *manager_) {
|
|||||||
std::shared_ptr<PreambleData> preamble = session->GetPreamble();
|
std::shared_ptr<PreambleData> preamble = session->GetPreamble();
|
||||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
|
||||||
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
|
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
|
||||||
|
|
||||||
std::unique_ptr<CompilerInvocation> CI =
|
std::unique_ptr<CompilerInvocation> CI =
|
||||||
BuildCompilerInvocation(session->file.args, FS);
|
BuildCompilerInvocation(session->file.args, FS);
|
||||||
if (!CI)
|
if (!CI)
|
||||||
@ -478,16 +468,14 @@ void *DiagnosticMain(void *manager_) {
|
|||||||
CI->getDiagnosticOpts().IgnoreWarnings = false;
|
CI->getDiagnosticOpts().IgnoreWarnings = false;
|
||||||
CI->getLangOpts()->SpellChecking = g_config->diagnostics.spellChecking;
|
CI->getLangOpts()->SpellChecking = g_config->diagnostics.spellChecking;
|
||||||
StoreDiags DC(path);
|
StoreDiags DC(path);
|
||||||
WorkingFiles::Snapshot snapshot =
|
std::string content = manager->wfiles_->GetContent(path);
|
||||||
manager->wfiles_->AsSnapshot({StripFileType(path)});
|
auto Buf = llvm::MemoryBuffer::getMemBuffer(content);
|
||||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
|
|
||||||
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
|
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
|
||||||
preamble.get(), snapshot, Bufs);
|
preamble.get(), path, Buf);
|
||||||
if (!Clang)
|
if (!Clang)
|
||||||
continue;
|
continue;
|
||||||
if (!Parse(*Clang))
|
if (!Parse(*Clang))
|
||||||
continue;
|
continue;
|
||||||
for (auto &Buf : Bufs)
|
|
||||||
Buf.release();
|
Buf.release();
|
||||||
|
|
||||||
auto Fill = [](const DiagBase &d, Diagnostic &ret) {
|
auto Fill = [](const DiagBase &d, Diagnostic &ret) {
|
||||||
|
@ -92,7 +92,7 @@ IncludeComplete::IncludeComplete(Project *project)
|
|||||||
: is_scanning(false), project_(project) {}
|
: is_scanning(false), project_(project) {}
|
||||||
|
|
||||||
void IncludeComplete::Rescan() {
|
void IncludeComplete::Rescan() {
|
||||||
if (is_scanning)
|
if (is_scanning || LLVM_VERSION_MAJOR >= 8)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
completion_items.clear();
|
completion_items.clear();
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
#include <clang/Sema/CodeCompleteConsumer.h>
|
#include <clang/Sema/CodeCompleteConsumer.h>
|
||||||
#include <clang/Sema/Sema.h>
|
#include <clang/Sema/Sema.h>
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR < 8
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@ -31,6 +33,7 @@ struct CompletionList {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(CompletionList, isIncomplete, items);
|
MAKE_REFLECT_STRUCT(CompletionList, isIncomplete, items);
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR < 8
|
||||||
void DecorateIncludePaths(const std::smatch &match,
|
void DecorateIncludePaths(const std::smatch &match,
|
||||||
std::vector<CompletionItem> *items) {
|
std::vector<CompletionItem> *items) {
|
||||||
std::string spaces_after_include = " ";
|
std::string spaces_after_include = " ";
|
||||||
@ -78,6 +81,7 @@ ParseIncludeLineResult ParseIncludeLine(const std::string &line) {
|
|||||||
bool ok = std::regex_match(line, match, pattern);
|
bool ok = std::regex_match(line, match, pattern);
|
||||||
return {ok, match[3], match[5], match[6], match};
|
return {ok, match[3], match[5], match[6], match};
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Pre-filters completion responses before sending to vscode. This results in a
|
// Pre-filters completion responses before sending to vscode. This results in a
|
||||||
// significantly snappier completion experience as vscode is easily overloaded
|
// significantly snappier completion experience as vscode is easily overloaded
|
||||||
@ -109,7 +113,7 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text,
|
|||||||
for (auto &item : items) {
|
for (auto &item : items) {
|
||||||
item.textEdit.range = lsRange{begin_pos, end_pos};
|
item.textEdit.range = lsRange{begin_pos, end_pos};
|
||||||
if (has_open_paren && item.filterText)
|
if (has_open_paren && item.filterText)
|
||||||
item.textEdit.newText = item.filterText.value();
|
item.textEdit.newText = *item.filterText;
|
||||||
// https://github.com/Microsoft/language-server-protocol/issues/543
|
// https://github.com/Microsoft/language-server-protocol/issues/543
|
||||||
// Order of textEdit and additionalTextEdits is unspecified.
|
// Order of textEdit and additionalTextEdits is unspecified.
|
||||||
auto &edits = item.additionalTextEdits;
|
auto &edits = item.additionalTextEdits;
|
||||||
@ -121,7 +125,7 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text,
|
|||||||
item.filterText =
|
item.filterText =
|
||||||
buffer_line.substr(start.character,
|
buffer_line.substr(start.character,
|
||||||
end.character - start.character) +
|
end.character - start.character) +
|
||||||
item.filterText.value();
|
*item.filterText;
|
||||||
}
|
}
|
||||||
edits.erase(edits.begin());
|
edits.erase(edits.begin());
|
||||||
}
|
}
|
||||||
@ -379,6 +383,10 @@ public:
|
|||||||
includeBriefComments());
|
includeBriefComments());
|
||||||
CompletionItem ls_item;
|
CompletionItem ls_item;
|
||||||
ls_item.kind = GetCompletionKind(R.CursorKind);
|
ls_item.kind = GetCompletionKind(R.CursorKind);
|
||||||
|
#if LLVM_VERSION_MAJOR >= 8
|
||||||
|
if (Context.getKind() == CodeCompletionContext::CCC_IncludedFile)
|
||||||
|
ls_item.kind = CompletionItemKind::File;
|
||||||
|
#endif
|
||||||
if (const char *brief = CCS->getBriefComment())
|
if (const char *brief = CCS->getBriefComment())
|
||||||
ls_item.documentation = brief;
|
ls_item.documentation = brief;
|
||||||
ls_item.detail = CCS->getParentContextName().str();
|
ls_item.detail = CCS->getParentContextName().str();
|
||||||
@ -431,51 +439,44 @@ void MessageHandler::textDocument_completion(CompletionParam ¶m,
|
|||||||
param.position.line < file->buffer_lines.size())
|
param.position.line < file->buffer_lines.size())
|
||||||
buffer_line = file->buffer_lines[param.position.line];
|
buffer_line = file->buffer_lines[param.position.line];
|
||||||
|
|
||||||
// Check for - and : before completing -> or ::, since vscode does not
|
clang::CodeCompleteOptions CCOpts;
|
||||||
// support multi-character trigger characters.
|
CCOpts.IncludeBriefComments = true;
|
||||||
|
CCOpts.IncludeCodePatterns = StringRef(buffer_line).ltrim().startswith("#");
|
||||||
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
|
CCOpts.IncludeFixIts = true;
|
||||||
|
#endif
|
||||||
|
CCOpts.IncludeMacros = true;
|
||||||
|
|
||||||
if (param.context.triggerKind == CompletionTriggerKind::TriggerCharacter &&
|
if (param.context.triggerKind == CompletionTriggerKind::TriggerCharacter &&
|
||||||
param.context.triggerCharacter) {
|
param.context.triggerCharacter) {
|
||||||
bool did_fail_check = false;
|
bool ok = true;
|
||||||
|
int col = param.position.character - 2;
|
||||||
std::string character = *param.context.triggerCharacter;
|
switch ((*param.context.triggerCharacter)[0]) {
|
||||||
int preceding_index = param.position.character - 2;
|
case '"':
|
||||||
|
case '/':
|
||||||
// If the character is '"', '<' or '/', make sure that the line starts
|
case '<':
|
||||||
// with '#'.
|
ok = CCOpts.IncludeCodePatterns; // start with #
|
||||||
if (character == "\"" || character == "<" || character == "/") {
|
break;
|
||||||
size_t i = 0;
|
case ':':
|
||||||
while (i < buffer_line.size() && isspace(buffer_line[i]))
|
ok = col >= 0 && buffer_line[col] == ':'; // ::
|
||||||
++i;
|
break;
|
||||||
if (i >= buffer_line.size() || buffer_line[i] != '#')
|
case '>':
|
||||||
did_fail_check = true;
|
ok = col >= 0 && buffer_line[col] == '-'; // ->
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// If the character is > or : and we are at the start of the line, do not
|
if (!ok) {
|
||||||
// show completion results.
|
|
||||||
else if ((character == ">" || character == ":") && preceding_index < 0) {
|
|
||||||
did_fail_check = true;
|
|
||||||
}
|
|
||||||
// If the character is > but - does not preced it, or if it is : and :
|
|
||||||
// does not preced it, do not show completion results.
|
|
||||||
else if (preceding_index >= 0 &&
|
|
||||||
preceding_index < (int)buffer_line.size()) {
|
|
||||||
char preceding = buffer_line[preceding_index];
|
|
||||||
did_fail_check = (preceding != '-' && character == ">") ||
|
|
||||||
(preceding != ':' && character == ":");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (did_fail_check) {
|
|
||||||
reply(result);
|
reply(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string completion_text;
|
std::string filter;
|
||||||
Position end_pos = param.position;
|
Position end_pos = param.position;
|
||||||
Position begin_pos = file->FindStableCompletionSource(
|
Position begin_pos =
|
||||||
param.position, &completion_text, &end_pos);
|
file->FindStableCompletionSource(param.position, &filter, &end_pos);
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR < 8
|
||||||
ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line);
|
ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line);
|
||||||
|
|
||||||
if (preprocess.ok && preprocess.keyword.compare("include") == 0) {
|
if (preprocess.ok && preprocess.keyword.compare("include") == 0) {
|
||||||
CompletionList result;
|
CompletionList result;
|
||||||
{
|
{
|
||||||
@ -494,10 +495,12 @@ void MessageHandler::textDocument_completion(CompletionParam ¶m,
|
|||||||
buffer_line);
|
buffer_line);
|
||||||
DecorateIncludePaths(preprocess.match, &result.items);
|
DecorateIncludePaths(preprocess.match, &result.items);
|
||||||
reply(result);
|
reply(result);
|
||||||
} else {
|
return;
|
||||||
std::string path = param.textDocument.uri.GetPath();
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CompletionManager::OnComplete callback =
|
CompletionManager::OnComplete callback =
|
||||||
[completion_text, path, begin_pos, end_pos, reply,
|
[filter, path, begin_pos, end_pos, reply,
|
||||||
buffer_line](CodeCompleteConsumer *OptConsumer) {
|
buffer_line](CodeCompleteConsumer *OptConsumer) {
|
||||||
if (!OptConsumer)
|
if (!OptConsumer)
|
||||||
return;
|
return;
|
||||||
@ -505,8 +508,7 @@ void MessageHandler::textDocument_completion(CompletionParam ¶m,
|
|||||||
CompletionList result;
|
CompletionList result;
|
||||||
result.items = Consumer->ls_items;
|
result.items = Consumer->ls_items;
|
||||||
|
|
||||||
FilterCandidates(result, completion_text, begin_pos, end_pos,
|
FilterCandidates(result, filter, begin_pos, end_pos, buffer_line);
|
||||||
buffer_line);
|
|
||||||
reply(result);
|
reply(result);
|
||||||
if (!Consumer->from_cache) {
|
if (!Consumer->from_cache) {
|
||||||
cache.WithLock([&]() {
|
cache.WithLock([&]() {
|
||||||
@ -517,13 +519,6 @@ void MessageHandler::textDocument_completion(CompletionParam ¶m,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
clang::CodeCompleteOptions CCOpts;
|
|
||||||
CCOpts.IncludeBriefComments = true;
|
|
||||||
CCOpts.IncludeCodePatterns = preprocess.ok; // if there is a #
|
|
||||||
#if LLVM_VERSION_MAJOR >= 7
|
|
||||||
CCOpts.IncludeFixIts = true;
|
|
||||||
#endif
|
|
||||||
CCOpts.IncludeMacros = true;
|
|
||||||
if (cache.IsCacheValid(path, begin_pos)) {
|
if (cache.IsCacheValid(path, begin_pos)) {
|
||||||
CompletionConsumer Consumer(CCOpts, true);
|
CompletionConsumer Consumer(CCOpts, true);
|
||||||
cache.WithLock([&]() { Consumer.ls_items = cache.result; });
|
cache.WithLock([&]() { Consumer.ls_items = cache.result; });
|
||||||
@ -536,5 +531,4 @@ void MessageHandler::textDocument_completion(CompletionParam ¶m,
|
|||||||
callback));
|
callback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // namespace ccls
|
} // namespace ccls
|
||||||
|
@ -129,6 +129,7 @@ struct ProjectProcessor {
|
|||||||
}
|
}
|
||||||
args.push_back(Intern("-working-directory=" + entry.directory));
|
args.push_back(Intern("-working-directory=" + entry.directory));
|
||||||
entry.args = args;
|
entry.args = args;
|
||||||
|
#if LLVM_VERSION_MAJOR < 8
|
||||||
args.push_back("-fsyntax-only");
|
args.push_back("-fsyntax-only");
|
||||||
if (!command_set.insert(hash).second)
|
if (!command_set.insert(hash).second)
|
||||||
return;
|
return;
|
||||||
@ -179,6 +180,7 @@ struct ProjectProcessor {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user