summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/CodeComplete.cpp
diff options
context:
space:
mode:
authorSam McCall <sam.mccall@gmail.com>2018-07-03 08:09:29 +0000
committerSam McCall <sam.mccall@gmail.com>2018-07-03 08:09:29 +0000
commit3f0243fdafaa7207fa6ade486e1bb9b99d2c4140 (patch)
tree370b8271f4c8701b309c077f419ecc57e2623f31 /clang-tools-extra/clangd/CodeComplete.cpp
parenta0a52bf195821a49a6920084a6ddb5139d9fa3fe (diff)
downloadbcm5719-llvm-3f0243fdafaa7207fa6ade486e1bb9b99d2c4140.tar.gz
bcm5719-llvm-3f0243fdafaa7207fa6ade486e1bb9b99d2c4140.zip
[clangd] Incorporate transitive #includes into code complete proximity scoring.
Summary: We now compute a distance from the main file to the symbol header, which is a weighted count of: - some number of #include traversals from source file --> included file - some number of FS traversals from file --> parent directory - some number of FS traversals from parent directory --> child file/dir This calculation is performed in the appropriate URI scheme. This means we'll get some proximity boost from header files in main-file contexts, even when these are in different directory trees. This extended file proximity model is not yet incorporated in the index interface/implementation. Reviewers: ioeric Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, cfe-commits Differential Revision: https://reviews.llvm.org/D48441 llvm-svn: 336177
Diffstat (limited to 'clang-tools-extra/clangd/CodeComplete.cpp')
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp120
1 files changed, 67 insertions, 53 deletions
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 33fdd853dd1..248c96b36db 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -22,6 +22,7 @@
#include "AST.h"
#include "CodeCompletionStrings.h"
#include "Compiler.h"
+#include "FileDistance.h"
#include "FuzzyMatch.h"
#include "Headers.h"
#include "Logger.h"
@@ -763,7 +764,6 @@ struct SemaCompleteInput {
PathRef FileName;
const tooling::CompileCommand &Command;
PrecompiledPreamble const *Preamble;
- const std::vector<Inclusion> &PreambleInclusions;
StringRef Contents;
Position Pos;
IntrusiveRefCntPtr<vfs::FileSystem> VFS;
@@ -771,12 +771,11 @@ struct SemaCompleteInput {
};
// Invokes Sema code completion on a file.
-// If \p Includes is set, it will be initialized after a compiler instance has
-// been set up.
+// If \p Includes is set, it will be updated based on the compiler invocation.
bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
const clang::CodeCompleteOptions &Options,
const SemaCompleteInput &Input,
- std::unique_ptr<IncludeInserter> *Includes = nullptr) {
+ IncludeStructure *Includes = nullptr) {
trace::Span Tracer("Sema completion");
std::vector<const char *> ArgStrs;
for (const auto &S : Input.Command.CommandLine)
@@ -837,29 +836,9 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
Input.FileName);
return false;
}
- if (Includes) {
- // Initialize Includes if provided.
-
- // FIXME(ioeric): needs more consistent style support in clangd server.
- auto Style = format::getStyle(format::DefaultFormatStyle, Input.FileName,
- format::DefaultFallbackStyle, Input.Contents,
- Input.VFS.get());
- if (!Style) {
- log("ERROR: failed to get FormatStyle for file " + Input.FileName +
- ". Fall back to use LLVM style. Error: " +
- llvm::toString(Style.takeError()));
- Style = format::getLLVMStyle();
- }
- *Includes = llvm::make_unique<IncludeInserter>(
- Input.FileName, Input.Contents, *Style, Input.Command.Directory,
- Clang->getPreprocessor().getHeaderSearchInfo());
- for (const auto &Inc : Input.PreambleInclusions)
- Includes->get()->addExisting(Inc);
- Clang->getPreprocessor().addPPCallbacks(collectInclusionsInMainFileCallback(
- Clang->getSourceManager(), [Includes](Inclusion Inc) {
- Includes->get()->addExisting(std::move(Inc));
- }));
- }
+ if (Includes)
+ Clang->getPreprocessor().addPPCallbacks(
+ collectIncludeStructureCallback(Clang->getSourceManager(), Includes));
if (!Action.Execute()) {
log("Execute() failed when running codeComplete for " + Input.FileName);
return false;
@@ -949,24 +928,23 @@ clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
// - TopN determines the results with the best score.
class CodeCompleteFlow {
PathRef FileName;
+ IncludeStructure Includes; // Complete once the compiler runs.
const CodeCompleteOptions &Opts;
// Sema takes ownership of Recorder. Recorder is valid until Sema cleanup.
CompletionRecorder *Recorder = nullptr;
int NSema = 0, NIndex = 0, NBoth = 0; // Counters for logging.
bool Incomplete = false; // Would more be available with a higher limit?
llvm::Optional<FuzzyMatcher> Filter; // Initialized once Sema runs.
- std::unique_ptr<IncludeInserter> Includes; // Initialized once compiler runs.
- FileProximityMatcher FileProximityMatch;
+ // Include-insertion and proximity scoring rely on the include structure.
+ // This is available after Sema has run.
+ llvm::Optional<IncludeInserter> Inserter; // Available during runWithSema.
+ llvm::Optional<URIDistance> FileProximity; // Initialized once Sema runs.
public:
// A CodeCompleteFlow object is only useful for calling run() exactly once.
- CodeCompleteFlow(PathRef FileName, const CodeCompleteOptions &Opts)
- : FileName(FileName), Opts(Opts),
- // FIXME: also use path of the main header corresponding to FileName to
- // calculate the file proximity, which would capture include/ and src/
- // project setup where headers and implementations are not in the same
- // directory.
- FileProximityMatch(ArrayRef<StringRef>({FileName})) {}
+ CodeCompleteFlow(PathRef FileName, const IncludeStructure &Includes,
+ const CodeCompleteOptions &Opts)
+ : FileName(FileName), Includes(Includes), Opts(Opts) {}
CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) && {
trace::Span Tracer("CodeCompleteFlow");
@@ -977,11 +955,45 @@ public:
CodeCompleteResult Output;
auto RecorderOwner = llvm::make_unique<CompletionRecorder>(Opts, [&]() {
assert(Recorder && "Recorder is not set");
- assert(Includes && "Includes is not set");
+ // FIXME(ioeric): needs more consistent style support in clangd server.
+ auto Style =
+ format::getStyle("file", SemaCCInput.FileName, "LLVM",
+ SemaCCInput.Contents, SemaCCInput.VFS.get());
+ if (!Style) {
+ log("Failed to get FormatStyle for file" + SemaCCInput.FileName + ": " +
+ llvm::toString(Style.takeError()) + ". Fallback is LLVM style.");
+ Style = format::getLLVMStyle();
+ }
// If preprocessor was run, inclusions from preprocessor callback should
- // already be added to Inclusions.
+ // already be added to Includes.
+ Inserter.emplace(
+ SemaCCInput.FileName, SemaCCInput.Contents, *Style,
+ SemaCCInput.Command.Directory,
+ Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
+ for (const auto &Inc : Includes.MainFileIncludes)
+ Inserter->addExisting(Inc);
+
+ // Most of the cost of file proximity is in initializing the FileDistance
+ // structures based on the observed includes, once per query. Conceptually
+ // that happens here (though the per-URI-scheme initialization is lazy).
+ // The per-result proximity scoring is (amortized) very cheap.
+ FileDistanceOptions ProxOpts{}; // Use defaults.
+ const auto &SM = Recorder->CCSema->getSourceManager();
+ llvm::StringMap<SourceParams> ProxSources;
+ for (auto &Entry : Includes.includeDepth(
+ SM.getFileEntryForID(SM.getMainFileID())->getName())) {
+ auto &Source = ProxSources[Entry.getKey()];
+ Source.Cost = Entry.getValue() * ProxOpts.IncludeCost;
+ // Symbols near our transitive includes are good, but only consider
+ // things in the same directory or below it. Otherwise there can be
+ // many false positives.
+ if (Entry.getValue() > 0)
+ Source.MaxUpTraversals = 1;
+ }
+ FileProximity.emplace(ProxSources, ProxOpts);
+
Output = runWithSema();
- Includes.reset(); // Make sure this doesn't out-live Clang.
+ Inserter.reset(); // Make sure this doesn't out-live Clang.
SPAN_ATTACH(Tracer, "sema_completion_kind",
getCompletionKindString(Recorder->CCContext.getKind()));
});
@@ -1044,6 +1056,7 @@ private:
Req.RestrictForCodeCompletion = true;
Req.Scopes = getQueryScopes(Recorder->CCContext,
Recorder->CCSema->getSourceManager());
+ // FIXME: we should send multiple weighted paths here.
Req.ProximityPaths.push_back(FileName);
log(llvm::formatv("Code complete: fuzzyFind(\"{0}\", scopes=[{1}])",
Req.Query,
@@ -1124,7 +1137,7 @@ private:
SymbolQualitySignals Quality;
SymbolRelevanceSignals Relevance;
Relevance.Query = SymbolRelevanceSignals::CodeComplete;
- Relevance.FileProximityMatch = &FileProximityMatch;
+ Relevance.FileProximityMatch = FileProximity.getPointer();
auto &First = Bundle.front();
if (auto FuzzyScore = fuzzyScore(First))
Relevance.NameMatch = *FuzzyScore;
@@ -1174,7 +1187,7 @@ private:
: nullptr;
if (!Builder)
Builder.emplace(Recorder->CCSema->getASTContext(), Item, SemaCCS,
- *Includes, FileName, Opts);
+ *Inserter, FileName, Opts);
else
Builder->add(Item, SemaCCS);
}
@@ -1182,15 +1195,16 @@ private:
}
};
-CodeCompleteResult codeComplete(
- PathRef FileName, const tooling::CompileCommand &Command,
- PrecompiledPreamble const *Preamble,
- const std::vector<Inclusion> &PreambleInclusions, StringRef Contents,
- Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs, CodeCompleteOptions Opts) {
- return CodeCompleteFlow(FileName, Opts)
- .run({FileName, Command, Preamble, PreambleInclusions, Contents, Pos, VFS,
- PCHs});
+CodeCompleteResult codeComplete(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ const IncludeStructure &PreambleInclusions,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ CodeCompleteOptions Opts) {
+ return CodeCompleteFlow(FileName, PreambleInclusions, Opts)
+ .run({FileName, Command, Preamble, Contents, Pos, VFS, PCHs});
}
SignatureHelp signatureHelp(PathRef FileName,
@@ -1205,11 +1219,11 @@ SignatureHelp signatureHelp(PathRef FileName,
Options.IncludeMacros = false;
Options.IncludeCodePatterns = false;
Options.IncludeBriefComments = false;
- std::vector<Inclusion> PreambleInclusions = {}; // Unused for signatureHelp
+ IncludeStructure PreambleInclusions; // Unused for signatureHelp
semaCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
Options,
- {FileName, Command, Preamble, PreambleInclusions, Contents,
- Pos, std::move(VFS), std::move(PCHs)});
+ {FileName, Command, Preamble, Contents, Pos, std::move(VFS),
+ std::move(PCHs)});
return Result;
}
OpenPOWER on IntegriCloud