If clang >= 8, delete search path detection and use Sema::CodeCompleteIncludedFile

This commit is contained in:
Fangrui Song 2018-11-08 21:18:41 -08:00
parent 94d2b5821e
commit eeeb03c068
4 changed files with 96 additions and 112 deletions

View File

@ -143,13 +143,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());
@ -272,23 +265,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);
@ -358,8 +344,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);
@ -415,18 +399,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());
@ -482,6 +471,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)
@ -489,16 +479,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) {

View File

@ -104,7 +104,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();

View File

@ -24,7 +24,9 @@ limitations under the License.
#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;
@ -43,6 +45,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 = " ";
@ -90,6 +93,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
@ -121,7 +125,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;
@ -133,7 +137,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());
} }
@ -391,6 +395,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();
@ -443,51 +451,44 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
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;
{ {
@ -506,10 +507,12 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
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;
@ -517,8 +520,7 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
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([&]() {
@ -529,13 +531,6 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
} }
}; };
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; });
@ -547,6 +542,5 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
std::make_unique<CompletionConsumer>(CCOpts, false), CCOpts, std::make_unique<CompletionConsumer>(CCOpts, false), CCOpts,
callback)); callback));
} }
}
} }
} // namespace ccls } // namespace ccls

View File

@ -141,6 +141,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;
@ -191,6 +192,7 @@ struct ProjectProcessor {
break; break;
} }
} }
#endif
} }
}; };