summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/CodeComplete.cpp
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2018-08-17 09:32:30 +0000
committerIlya Biryukov <ibiryukov@google.com>2018-08-17 09:32:30 +0000
commit8a0f76b855afdf1099e4447dd30543ea7cb9c562 (patch)
tree48cba6fa353721d1215a469288f8141aedaec064 /clang-tools-extra/clangd/CodeComplete.cpp
parent5f4a351306de78453d5c35bbaa4f8f0717db9029 (diff)
downloadbcm5719-llvm-8a0f76b855afdf1099e4447dd30543ea7cb9c562.tar.gz
bcm5719-llvm-8a0f76b855afdf1099e4447dd30543ea7cb9c562.zip
[clangd] Fetch documentation from the Index during signature help
Summary: Sema can only be used for documentation in the current file, other doc comments should be fetched from the index. Reviewers: hokein, ioeric, kadircet Reviewed By: hokein, kadircet Subscribers: MaskRay, jkorous, mgrang, arphaman, cfe-commits Differential Revision: https://reviews.llvm.org/D50727 llvm-svn: 340005
Diffstat (limited to 'clang-tools-extra/clangd/CodeComplete.cpp')
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp157
1 files changed, 99 insertions, 58 deletions
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 02c65757f41..36d0f21ed09 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -687,18 +687,23 @@ private:
llvm::unique_function<void()> ResultsCallback;
};
-using ScoredSignature =
- std::pair<SignatureQualitySignals, SignatureInformation>;
+struct ScoredSignature {
+ // When set, requires documentation to be requested from the index with this
+ // ID.
+ llvm::Optional<SymbolID> IDForDoc;
+ SignatureInformation Signature;
+ SignatureQualitySignals Quality;
+};
class SignatureHelpCollector final : public CodeCompleteConsumer {
-
public:
SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
- SignatureHelp &SigHelp)
- : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
+ SymbolIndex *Index, SignatureHelp &SigHelp)
+ : CodeCompleteConsumer(CodeCompleteOpts,
+ /*OutputIsBinary=*/false),
SigHelp(SigHelp),
Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
- CCTUInfo(Allocator) {}
+ CCTUInfo(Allocator), Index(Index) {}
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
@@ -726,47 +731,74 @@ public:
const auto *CCS = Candidate.CreateSignatureString(
CurrentArg, S, *Allocator, CCTUInfo, true);
assert(CCS && "Expected the CodeCompletionString to be non-null");
- // FIXME: for headers, we need to get a comment from the index.
ScoredSignatures.push_back(processOverloadCandidate(
Candidate, *CCS,
Candidate.getFunction()
? getDeclComment(S.getASTContext(), *Candidate.getFunction())
: ""));
}
- std::sort(ScoredSignatures.begin(), ScoredSignatures.end(),
- [](const ScoredSignature &L, const ScoredSignature &R) {
- // Ordering follows:
- // - Less number of parameters is better.
- // - Function is better than FunctionType which is better than
- // Function Template.
- // - High score is better.
- // - Shorter signature is better.
- // - Alphebatically smaller is better.
- if (L.first.NumberOfParameters != R.first.NumberOfParameters)
- return L.first.NumberOfParameters <
- R.first.NumberOfParameters;
- if (L.first.NumberOfOptionalParameters !=
- R.first.NumberOfOptionalParameters)
- return L.first.NumberOfOptionalParameters <
- R.first.NumberOfOptionalParameters;
- if (L.first.Kind != R.first.Kind) {
- using OC = CodeCompleteConsumer::OverloadCandidate;
- switch (L.first.Kind) {
- case OC::CK_Function:
- return true;
- case OC::CK_FunctionType:
- return R.first.Kind != OC::CK_Function;
- case OC::CK_FunctionTemplate:
- return false;
- }
- llvm_unreachable("Unknown overload candidate type.");
- }
- if (L.second.label.size() != R.second.label.size())
- return L.second.label.size() < R.second.label.size();
- return L.second.label < R.second.label;
- });
- for (const auto &SS : ScoredSignatures)
- SigHelp.signatures.push_back(SS.second);
+
+ // Sema does not load the docs from the preamble, so we need to fetch extra
+ // docs from the index instead.
+ llvm::DenseMap<SymbolID, std::string> FetchedDocs;
+ if (Index) {
+ LookupRequest IndexRequest;
+ for (const auto &S : ScoredSignatures) {
+ if (!S.IDForDoc)
+ continue;
+ IndexRequest.IDs.insert(*S.IDForDoc);
+ }
+ Index->lookup(IndexRequest, [&](const Symbol &S) {
+ if (!S.Detail || S.Detail->Documentation.empty())
+ return;
+ FetchedDocs[S.ID] = S.Detail->Documentation;
+ });
+ log("SigHelp: requested docs for {0} symbols from the index, got {1} "
+ "symbols with non-empty docs in the response",
+ IndexRequest.IDs.size(), FetchedDocs.size());
+ }
+
+ std::sort(
+ ScoredSignatures.begin(), ScoredSignatures.end(),
+ [](const ScoredSignature &L, const ScoredSignature &R) {
+ // Ordering follows:
+ // - Less number of parameters is better.
+ // - Function is better than FunctionType which is better than
+ // Function Template.
+ // - High score is better.
+ // - Shorter signature is better.
+ // - Alphebatically smaller is better.
+ if (L.Quality.NumberOfParameters != R.Quality.NumberOfParameters)
+ return L.Quality.NumberOfParameters < R.Quality.NumberOfParameters;
+ if (L.Quality.NumberOfOptionalParameters !=
+ R.Quality.NumberOfOptionalParameters)
+ return L.Quality.NumberOfOptionalParameters <
+ R.Quality.NumberOfOptionalParameters;
+ if (L.Quality.Kind != R.Quality.Kind) {
+ using OC = CodeCompleteConsumer::OverloadCandidate;
+ switch (L.Quality.Kind) {
+ case OC::CK_Function:
+ return true;
+ case OC::CK_FunctionType:
+ return R.Quality.Kind != OC::CK_Function;
+ case OC::CK_FunctionTemplate:
+ return false;
+ }
+ llvm_unreachable("Unknown overload candidate type.");
+ }
+ if (L.Signature.label.size() != R.Signature.label.size())
+ return L.Signature.label.size() < R.Signature.label.size();
+ return L.Signature.label < R.Signature.label;
+ });
+
+ for (auto &SS : ScoredSignatures) {
+ auto IndexDocIt =
+ SS.IDForDoc ? FetchedDocs.find(*SS.IDForDoc) : FetchedDocs.end();
+ if (IndexDocIt != FetchedDocs.end())
+ SS.Signature.documentation = IndexDocIt->second;
+
+ SigHelp.signatures.push_back(std::move(SS.Signature));
+ }
}
GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
@@ -779,11 +811,11 @@ private:
ScoredSignature processOverloadCandidate(const OverloadCandidate &Candidate,
const CodeCompletionString &CCS,
llvm::StringRef DocComment) const {
- SignatureInformation Result;
+ SignatureInformation Signature;
SignatureQualitySignals Signal;
const char *ReturnType = nullptr;
- Result.documentation = formatDocumentation(CCS, DocComment);
+ Signature.documentation = formatDocumentation(CCS, DocComment);
Signal.Kind = Candidate.getKind();
for (const auto &Chunk : CCS) {
@@ -802,10 +834,10 @@ private:
// A piece of text that describes the parameter that corresponds to
// the code-completion location within a function call, message send,
// macro invocation, etc.
- Result.label += Chunk.Text;
+ Signature.label += Chunk.Text;
ParameterInformation Info;
Info.label = Chunk.Text;
- Result.parameters.push_back(std::move(Info));
+ Signature.parameters.push_back(std::move(Info));
Signal.NumberOfParameters++;
Signal.ContainsActiveParameter = true;
break;
@@ -814,29 +846,36 @@ private:
// The rest of the parameters are defaulted/optional.
assert(Chunk.Optional &&
"Expected the optional code completion string to be non-null.");
- Result.label +=
- getOptionalParameters(*Chunk.Optional, Result.parameters, Signal);
+ Signature.label += getOptionalParameters(*Chunk.Optional,
+ Signature.parameters, Signal);
break;
}
case CodeCompletionString::CK_VerticalSpace:
break;
default:
- Result.label += Chunk.Text;
+ Signature.label += Chunk.Text;
break;
}
}
if (ReturnType) {
- Result.label += " -> ";
- Result.label += ReturnType;
+ Signature.label += " -> ";
+ Signature.label += ReturnType;
}
- dlog("Signal for {0}: {1}", Result, Signal);
- return {Signal, Result};
+ dlog("Signal for {0}: {1}", Signature, Signal);
+ ScoredSignature Result;
+ Result.Signature = std::move(Signature);
+ Result.Quality = Signal;
+ Result.IDForDoc =
+ Result.Signature.documentation.empty() && Candidate.getFunction()
+ ? clangd::getSymbolID(Candidate.getFunction())
+ : llvm::None;
+ return Result;
}
SignatureHelp &SigHelp;
std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
CodeCompletionTUInfo CCTUInfo;
-
+ const SymbolIndex *Index;
}; // SignatureHelpCollector
struct SemaCompleteInput {
@@ -1315,7 +1354,8 @@ SignatureHelp signatureHelp(PathRef FileName,
PrecompiledPreamble const *Preamble,
StringRef Contents, Position Pos,
IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs) {
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ SymbolIndex *Index) {
SignatureHelp Result;
clang::CodeCompleteOptions Options;
Options.IncludeGlobals = false;
@@ -1323,10 +1363,11 @@ SignatureHelp signatureHelp(PathRef FileName,
Options.IncludeCodePatterns = false;
Options.IncludeBriefComments = false;
IncludeStructure PreambleInclusions; // Unused for signatureHelp
- semaCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
- Options,
- {FileName, Command, Preamble, Contents, Pos, std::move(VFS),
- std::move(PCHs)});
+ semaCodeComplete(
+ llvm::make_unique<SignatureHelpCollector>(Options, Index, Result),
+ Options,
+ {FileName, Command, Preamble, Contents, Pos, std::move(VFS),
+ std::move(PCHs)});
return Result;
}
OpenPOWER on IntegriCloud