aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra
diff options
context:
space:
mode:
authorDavid Goldman <davg@google.com>2022-12-02 10:04:31 -0500
committerDavid Goldman <davg@google.com>2022-12-06 13:47:07 -0500
commit51f1ae52b0c92a9783e7df328d05b1f95dca74d1 (patch)
tree5d5cb200e80c277dcafaa9b8351a8a7fd0343545 /clang-tools-extra
parent71df24dd39177ecfc440a04cd92fa4845d88347d (diff)
downloadllvm-51f1ae52b0c92a9783e7df328d05b1f95dca74d1.zip
llvm-51f1ae52b0c92a9783e7df328d05b1f95dca74d1.tar.gz
llvm-51f1ae52b0c92a9783e7df328d05b1f95dca74d1.tar.bz2
[clangd] Add new IncludeDirective to IncludeHeaderWithReferences
The IncludeDirective contains both Include (the current behavior) and Import, which we can use in the future to provide #import suggestions for Objective-C files/symbols. Differential Revision: https://reviews.llvm.org/D128457
Diffstat (limited to 'clang-tools-extra')
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp16
-rw-r--r--clang-tools-extra/clangd/Headers.cpp6
-rw-r--r--clang-tools-extra/clangd/Headers.h11
-rw-r--r--clang-tools-extra/clangd/IncludeFixer.cpp9
-rw-r--r--clang-tools-extra/clangd/index/Merge.cpp4
-rw-r--r--clang-tools-extra/clangd/index/Serialization.cpp8
-rw-r--r--clang-tools-extra/clangd/index/Symbol.h28
-rw-r--r--clang-tools-extra/clangd/index/SymbolCollector.cpp55
-rw-r--r--clang-tools-extra/clangd/index/SymbolCollector.h3
-rw-r--r--clang-tools-extra/clangd/index/YAMLSerialization.cpp61
-rw-r--r--clang-tools-extra/clangd/index/remote/Index.proto1
-rw-r--r--clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp9
-rw-r--r--clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idxbin476 -> 474 bytes
-rw-r--r--clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp48
-rw-r--r--clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp8
-rw-r--r--clang-tools-extra/clangd/unittests/IndexTests.cpp8
-rw-r--r--clang-tools-extra/clangd/unittests/SerializationTests.cpp26
17 files changed, 237 insertions, 64 deletions
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 33088e0..32a80ac 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -191,7 +191,7 @@ struct CompletionCandidate {
const CodeCompletionResult *SemaResult = nullptr;
const Symbol *IndexResult = nullptr;
const RawIdentifier *IdentifierResult = nullptr;
- llvm::SmallVector<llvm::StringRef, 1> RankedIncludeHeaders;
+ llvm::SmallVector<SymbolInclude, 1> RankedIncludeHeaders;
// Returns a token identifying the overload set this is part of.
// 0 indicates it's not part of any overload set.
@@ -267,7 +267,11 @@ struct CompletionCandidate {
if (SM.isInMainFile(SM.getExpansionLoc(RD->getBeginLoc())))
return std::nullopt;
}
- return RankedIncludeHeaders[0];
+ for (const auto &Inc : RankedIncludeHeaders)
+ // FIXME: We should support #import directives here.
+ if ((Inc.Directive & clang::clangd::Symbol::Include) != 0)
+ return Inc.Header;
+ return None;
}
using Bundle = llvm::SmallVector<CompletionCandidate, 4>;
@@ -383,7 +387,11 @@ struct CodeCompletionBuilder {
bool ShouldInsert = C.headerToInsertIfAllowed(Opts).has_value();
// Calculate include paths and edits for all possible headers.
for (const auto &Inc : C.RankedIncludeHeaders) {
- if (auto ToInclude = Inserted(Inc)) {
+ // FIXME: We should support #import directives here.
+ if ((Inc.Directive & clang::clangd::Symbol::Include) == 0)
+ continue;
+
+ if (auto ToInclude = Inserted(Inc.Header)) {
CodeCompletion::IncludeCandidate Include;
Include.Header = ToInclude->first;
if (ToInclude->second && ShouldInsert)
@@ -392,7 +400,7 @@ struct CodeCompletionBuilder {
} else
log("Failed to generate include insertion edits for adding header "
"(FileURI='{0}', IncludeHeader='{1}') into {2}: {3}",
- C.IndexResult->CanonicalDeclaration.FileURI, Inc, FileName,
+ C.IndexResult->CanonicalDeclaration.FileURI, Inc.Header, FileName,
ToInclude.takeError());
}
// Prefer includes that do not need edits (i.e. already exist).
diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp
index a531197..9581389 100644
--- a/clang-tools-extra/clangd/Headers.cpp
+++ b/clang-tools-extra/clangd/Headers.cpp
@@ -211,7 +211,7 @@ llvm::Expected<HeaderFile> toHeaderFile(llvm::StringRef Header,
return HeaderFile{std::move(*Resolved), /*Verbatim=*/false};
}
-llvm::SmallVector<llvm::StringRef, 1> getRankedIncludes(const Symbol &Sym) {
+llvm::SmallVector<SymbolInclude, 1> getRankedIncludes(const Symbol &Sym) {
auto Includes = Sym.IncludeHeaders;
// Sort in descending order by reference count and header length.
llvm::sort(Includes, [](const Symbol::IncludeHeaderWithReferences &LHS,
@@ -220,9 +220,9 @@ llvm::SmallVector<llvm::StringRef, 1> getRankedIncludes(const Symbol &Sym) {
return LHS.IncludeHeader.size() < RHS.IncludeHeader.size();
return LHS.References > RHS.References;
});
- llvm::SmallVector<llvm::StringRef, 1> Headers;
+ llvm::SmallVector<SymbolInclude, 1> Headers;
for (const auto &Include : Includes)
- Headers.push_back(Include.IncludeHeader);
+ Headers.push_back({Include.IncludeHeader, Include.supportedDirectives()});
return Headers;
}
diff --git a/clang-tools-extra/clangd/Headers.h b/clang-tools-extra/clangd/Headers.h
index 72a75de..0901a23f 100644
--- a/clang-tools-extra/clangd/Headers.h
+++ b/clang-tools-extra/clangd/Headers.h
@@ -45,6 +45,15 @@ struct HeaderFile {
bool valid() const;
};
+/// A header and directives as stored in a Symbol.
+struct SymbolInclude {
+ /// The header to include. This is either a URI or a verbatim include which is
+ /// quoted with <> or "".
+ llvm::StringRef Header;
+ /// The include directive to use, e.g. #import or #include.
+ Symbol::IncludeDirective Directive;
+};
+
/// Creates a `HeaderFile` from \p Header which can be either a URI or a literal
/// include.
llvm::Expected<HeaderFile> toHeaderFile(llvm::StringRef Header,
@@ -52,7 +61,7 @@ llvm::Expected<HeaderFile> toHeaderFile(llvm::StringRef Header,
// Returns include headers for \p Sym sorted by popularity. If two headers are
// equally popular, prefer the shorter one.
-llvm::SmallVector<llvm::StringRef, 1> getRankedIncludes(const Symbol &Sym);
+llvm::SmallVector<SymbolInclude, 1> getRankedIncludes(const Symbol &Sym);
// An #include directive that we found in the main file.
struct Inclusion {
diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp
index 4332768..5ba5a4e 100644
--- a/clang-tools-extra/clangd/IncludeFixer.cpp
+++ b/clang-tools-extra/clangd/IncludeFixer.cpp
@@ -317,7 +317,10 @@ std::vector<Fix> IncludeFixer::fixesForSymbols(const SymbolSlab &Syms) const {
llvm::StringSet<> InsertedHeaders;
for (const auto &Sym : Syms) {
for (const auto &Inc : getRankedIncludes(Sym)) {
- if (auto ToInclude = Inserted(Sym, Inc)) {
+ // FIXME: We should support #import directives here.
+ if ((Inc.Directive & clang::clangd::Symbol::Include) == 0)
+ continue;
+ if (auto ToInclude = Inserted(Sym, Inc.Header)) {
if (ToInclude->second) {
if (!InsertedHeaders.try_emplace(ToInclude->first).second)
continue;
@@ -326,8 +329,8 @@ std::vector<Fix> IncludeFixer::fixesForSymbols(const SymbolSlab &Syms) const {
Fixes.push_back(std::move(*Fix));
}
} else {
- vlog("Failed to calculate include insertion for {0} into {1}: {2}", Inc,
- File, ToInclude.takeError());
+ vlog("Failed to calculate include insertion for {0} into {1}: {2}",
+ Inc.Header, File, ToInclude.takeError());
}
}
}
diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp
index 0d15dfc..9687b36 100644
--- a/clang-tools-extra/clangd/index/Merge.cpp
+++ b/clang-tools-extra/clangd/index/Merge.cpp
@@ -248,11 +248,13 @@ Symbol mergeSymbol(const Symbol &L, const Symbol &R) {
if (SI.IncludeHeader == OI.IncludeHeader) {
Found = true;
SI.References += OI.References;
+ SI.SupportedDirectives |= OI.SupportedDirectives;
break;
}
}
if (!Found && MergeIncludes)
- S.IncludeHeaders.emplace_back(OI.IncludeHeader, OI.References);
+ S.IncludeHeaders.emplace_back(OI.IncludeHeader, OI.References,
+ OI.supportedDirectives());
}
S.Origin |= O.Origin | SymbolOrigin::Merge;
diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp
index 5a00fbf..aaa1d51 100644
--- a/clang-tools-extra/clangd/index/Serialization.cpp
+++ b/clang-tools-extra/clangd/index/Serialization.cpp
@@ -331,7 +331,7 @@ void writeSymbol(const Symbol &Sym, const StringTableOut &Strings,
auto WriteInclude = [&](const Symbol::IncludeHeaderWithReferences &Include) {
writeVar(Strings.index(Include.IncludeHeader), OS);
- writeVar(Include.References, OS);
+ writeVar((Include.References << 2) | Include.SupportedDirectives, OS);
};
writeVar(Sym.IncludeHeaders.size(), OS);
for (const auto &Include : Sym.IncludeHeaders)
@@ -361,7 +361,9 @@ Symbol readSymbol(Reader &Data, llvm::ArrayRef<llvm::StringRef> Strings,
return Sym;
for (auto &I : Sym.IncludeHeaders) {
I.IncludeHeader = Data.consumeString(Strings);
- I.References = Data.consumeVar();
+ uint32_t RefsWithDirectives = Data.consumeVar();
+ I.References = RefsWithDirectives >> 2;
+ I.SupportedDirectives = RefsWithDirectives & 0x3;
}
return Sym;
}
@@ -455,7 +457,7 @@ readCompileCommand(Reader CmdReader, llvm::ArrayRef<llvm::StringRef> Strings) {
// The current versioning scheme is simple - non-current versions are rejected.
// If you make a breaking change, bump this version number to invalidate stored
// data. Later we may want to support some backward compatibility.
-constexpr static uint32_t Version = 17;
+constexpr static uint32_t Version = 18;
llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data,
SymbolOrigin Origin) {
diff --git a/clang-tools-extra/clangd/index/Symbol.h b/clang-tools-extra/clangd/index/Symbol.h
index a8333a8..1aa5265 100644
--- a/clang-tools-extra/clangd/index/Symbol.h
+++ b/clang-tools-extra/clangd/index/Symbol.h
@@ -13,12 +13,15 @@
#include "index/SymbolLocation.h"
#include "index/SymbolOrigin.h"
#include "clang/Index/IndexSymbol.h"
+#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/StringSaver.h"
namespace clang {
namespace clangd {
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
/// The class presents a C++ symbol, e.g. class, function.
///
/// WARNING: Symbols do not own much of their underlying data - typically
@@ -84,12 +87,24 @@ struct Symbol {
/// Only set when the symbol is indexed for completion.
llvm::StringRef Type;
+ enum IncludeDirective : uint8_t {
+ Invalid = 0,
+ /// `#include "header.h"`
+ Include = 1,
+ /// `#import "header.h"`
+ Import = 2,
+
+ LLVM_MARK_AS_BITMASK_ENUM(Import)
+ };
+
struct IncludeHeaderWithReferences {
IncludeHeaderWithReferences() = default;
IncludeHeaderWithReferences(llvm::StringRef IncludeHeader,
- unsigned References)
- : IncludeHeader(IncludeHeader), References(References) {}
+ uint32_t References,
+ IncludeDirective SupportedDirectives)
+ : IncludeHeader(IncludeHeader), References(References),
+ SupportedDirectives(SupportedDirectives) {}
/// This can be either a URI of the header to be #include'd
/// for this symbol, or a literal header quoted with <> or "" that is
@@ -101,7 +116,14 @@ struct Symbol {
llvm::StringRef IncludeHeader = "";
/// The number of translation units that reference this symbol and include
/// this header. This number is only meaningful if aggregated in an index.
- unsigned References = 0;
+ uint32_t References : 30;
+ /// Bitfield of supported directives (IncludeDirective) that can be used
+ /// when including this header.
+ uint32_t SupportedDirectives : 2;
+
+ IncludeDirective supportedDirectives() const {
+ return static_cast<IncludeDirective>(SupportedDirectives);
+ }
};
/// One Symbol can potentially be included via different headers.
/// - If we haven't seen a definition, this covers all declarations.
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 54dfde4..362959d 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -76,7 +76,7 @@ bool isPrivateProtoDecl(const NamedDecl &ND) {
// We only collect #include paths for symbols that are suitable for global code
// completion, except for namespaces since #include path for a namespace is hard
// to define.
-bool shouldCollectIncludePath(index::SymbolKind Kind) {
+Symbol::IncludeDirective shouldCollectIncludePath(index::SymbolKind Kind) {
using SK = index::SymbolKind;
switch (Kind) {
case SK::Macro:
@@ -90,9 +90,11 @@ bool shouldCollectIncludePath(index::SymbolKind Kind) {
case SK::Variable:
case SK::EnumConstant:
case SK::Concept:
- return true;
+ return Symbol::Include | Symbol::Import;
+ case SK::Protocol:
+ return Symbol::Import;
default:
- return false;
+ return Symbol::Invalid;
}
}
@@ -805,12 +807,12 @@ void SymbolCollector::processRelations(
}
void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation Loc) {
- if (Opts.CollectIncludePath)
- if (shouldCollectIncludePath(S.SymInfo.Kind))
- // Use the expansion location to get the #include header since this is
- // where the symbol is exposed.
- IncludeFiles[S.ID] =
- PP->getSourceManager().getDecomposedExpansionLoc(Loc).first;
+ if (Opts.CollectIncludePath &&
+ shouldCollectIncludePath(S.SymInfo.Kind) != Symbol::Invalid)
+ // Use the expansion location to get the #include header since this is
+ // where the symbol is exposed.
+ IncludeFiles[S.ID] =
+ PP->getSourceManager().getDecomposedExpansionLoc(Loc).first;
}
void SymbolCollector::finish() {
@@ -835,11 +837,12 @@ void SymbolCollector::finish() {
Symbols.erase(ID);
}
}
+ llvm::DenseMap<FileID, bool> FileToContainsImportsOrObjC;
// Fill in IncludeHeaders.
// We delay this until end of TU so header guards are all resolved.
llvm::SmallString<128> QName;
- for (const auto &Entry : IncludeFiles) {
- if (const Symbol *S = Symbols.find(Entry.first)) {
+ for (const auto &[SID, FID] : IncludeFiles) {
+ if (const Symbol *S = Symbols.find(SID)) {
llvm::StringRef IncludeHeader;
// Look for an overridden include header for this symbol specifically.
if (Opts.Includes) {
@@ -856,19 +859,36 @@ void SymbolCollector::finish() {
}
// Otherwise find the approprate include header for the defining file.
if (IncludeHeader.empty())
- IncludeHeader = HeaderFileURIs->getIncludeHeader(Entry.second);
+ IncludeHeader = HeaderFileURIs->getIncludeHeader(FID);
// Symbols in slabs aren't mutable, insert() has to walk all the strings
if (!IncludeHeader.empty()) {
- Symbol NewSym = *S;
- NewSym.IncludeHeaders.push_back({IncludeHeader, 1});
- Symbols.insert(NewSym);
+ Symbol::IncludeDirective Directives = Symbol::Invalid;
+ auto CollectDirectives = shouldCollectIncludePath(S->SymInfo.Kind);
+ if ((CollectDirectives & Symbol::Include) != 0)
+ Directives |= Symbol::Include;
+ // Only allow #import for symbols from ObjC-like files.
+ if ((CollectDirectives & Symbol::Import) != 0) {
+ auto [It, Inserted] = FileToContainsImportsOrObjC.try_emplace(FID);
+ if (Inserted)
+ It->second = FilesWithObjCConstructs.contains(FID) ||
+ tooling::codeContainsImports(
+ ASTCtx->getSourceManager().getBufferData(FID));
+ if (It->second)
+ Directives |= Symbol::Import;
+ }
+ if (Directives != Symbol::Invalid) {
+ Symbol NewSym = *S;
+ NewSym.IncludeHeaders.push_back({IncludeHeader, 1, Directives});
+ Symbols.insert(NewSym);
+ }
}
}
}
ReferencedSymbols.clear();
IncludeFiles.clear();
+ FilesWithObjCConstructs.clear();
}
const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID,
@@ -896,7 +916,8 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID,
auto Loc = nameLocation(ND, SM);
assert(Loc.isValid() && "Invalid source location for NamedDecl");
// FIXME: use the result to filter out symbols.
- shouldIndexFile(SM.getFileID(Loc));
+ auto FID = SM.getFileID(Loc);
+ shouldIndexFile(FID);
if (auto DeclLoc = getTokenLocation(Loc))
S.CanonicalDeclaration = *DeclLoc;
@@ -940,6 +961,8 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID,
Symbols.insert(S);
setIncludeLocation(S, ND.getLocation());
+ if (S.SymInfo.Lang == index::SymbolLanguage::ObjC)
+ FilesWithObjCConstructs.insert(FID);
return Symbols.find(S.ID);
}
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h
index 1c6205a..6e2998f 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.h
+++ b/clang-tools-extra/clangd/index/SymbolCollector.h
@@ -153,6 +153,9 @@ private:
// File IDs for Symbol.IncludeHeaders.
// The final spelling is calculated in finish().
llvm::DenseMap<SymbolID, FileID> IncludeFiles;
+ // Files which contain ObjC symbols.
+ // This is finalized and used in finish().
+ llvm::DenseSet<FileID> FilesWithObjCConstructs;
void setIncludeLocation(const Symbol &S, SourceLocation);
// Indexed macros, to be erased if they turned out to be include guards.
llvm::DenseSet<const IdentifierInfo *> IndexedMacros;
diff --git a/clang-tools-extra/clangd/index/YAMLSerialization.cpp b/clang-tools-extra/clangd/index/YAMLSerialization.cpp
index 1ac7433..593ce30 100644
--- a/clang-tools-extra/clangd/index/YAMLSerialization.cpp
+++ b/clang-tools-extra/clangd/index/YAMLSerialization.cpp
@@ -28,8 +28,13 @@
#include "llvm/Support/raw_ostream.h"
#include <cstdint>
+namespace {
+struct YIncludeHeaderWithReferences;
+}
+
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref)
+LLVM_YAML_IS_SEQUENCE_VECTOR(YIncludeHeaderWithReferences)
namespace {
using RefBundle =
@@ -48,6 +53,21 @@ struct YPosition {
uint32_t Line;
uint32_t Column;
};
+// A class helps YAML to serialize the IncludeHeaderWithReferences as YAMLIO
+// can't directly map bitfields.
+struct YIncludeHeaderWithReferences {
+ llvm::StringRef IncludeHeader;
+ uint32_t References;
+ clang::clangd::Symbol::IncludeDirective SupportedDirectives;
+
+ YIncludeHeaderWithReferences() = default;
+
+ YIncludeHeaderWithReferences(
+ llvm::StringRef IncludeHeader, uint32_t References,
+ clang::clangd::Symbol::IncludeDirective SupportedDirectives)
+ : IncludeHeader(IncludeHeader), References(References),
+ SupportedDirectives(SupportedDirectives) {}
+};
// avoid ODR violation of specialization for non-owned CompileCommand
struct CompileCommandYAML : clang::tooling::CompileCommand {};
@@ -165,13 +185,40 @@ template <> struct MappingTraits<SymbolInfo> {
}
};
-template <>
-struct MappingTraits<clang::clangd::Symbol::IncludeHeaderWithReferences> {
- static void mapping(IO &IO,
- clang::clangd::Symbol::IncludeHeaderWithReferences &Inc) {
+template <> struct ScalarBitSetTraits<clang::clangd::Symbol::IncludeDirective> {
+ static void bitset(IO &IO, clang::clangd::Symbol::IncludeDirective &Value) {
+ IO.bitSetCase(Value, "Include", clang::clangd::Symbol::Include);
+ IO.bitSetCase(Value, "Import", clang::clangd::Symbol::Import);
+ }
+};
+
+template <> struct MappingTraits<YIncludeHeaderWithReferences> {
+ static void mapping(IO &IO, YIncludeHeaderWithReferences &Inc) {
IO.mapRequired("Header", Inc.IncludeHeader);
IO.mapRequired("References", Inc.References);
+ IO.mapOptional("Directives", Inc.SupportedDirectives,
+ clang::clangd::Symbol::Include);
+ }
+};
+
+struct NormalizedIncludeHeaders {
+ using IncludeHeader = clang::clangd::Symbol::IncludeHeaderWithReferences;
+ NormalizedIncludeHeaders(IO &) {}
+ NormalizedIncludeHeaders(
+ IO &, const llvm::SmallVector<IncludeHeader, 1> &IncludeHeaders) {
+ for (auto &I : IncludeHeaders) {
+ Headers.emplace_back(I.IncludeHeader, I.References,
+ I.supportedDirectives());
+ }
+ }
+
+ llvm::SmallVector<IncludeHeader, 1> denormalize(IO &) {
+ llvm::SmallVector<IncludeHeader, 1> Result;
+ for (auto &H : Headers)
+ Result.emplace_back(H.IncludeHeader, H.References, H.SupportedDirectives);
+ return Result;
}
+ llvm::SmallVector<YIncludeHeaderWithReferences, 1> Headers;
};
template <> struct MappingTraits<Symbol> {
@@ -179,6 +226,10 @@ template <> struct MappingTraits<Symbol> {
MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);
MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag(
IO, Sym.Flags);
+ MappingNormalization<
+ NormalizedIncludeHeaders,
+ llvm::SmallVector<Symbol::IncludeHeaderWithReferences, 1>>
+ NIncludeHeaders(IO, Sym.IncludeHeaders);
IO.mapRequired("ID", NSymbolID->HexString);
IO.mapRequired("Name", Sym.Name);
IO.mapRequired("Scope", Sym.Scope);
@@ -195,7 +246,7 @@ template <> struct MappingTraits<Symbol> {
IO.mapOptional("Documentation", Sym.Documentation);
IO.mapOptional("ReturnType", Sym.ReturnType);
IO.mapOptional("Type", Sym.Type);
- IO.mapOptional("IncludeHeaders", Sym.IncludeHeaders);
+ IO.mapOptional("IncludeHeaders", NIncludeHeaders->Headers);
}
};
diff --git a/clang-tools-extra/clangd/index/remote/Index.proto b/clang-tools-extra/clangd/index/remote/Index.proto
index 062feaf..3072299 100644
--- a/clang-tools-extra/clangd/index/remote/Index.proto
+++ b/clang-tools-extra/clangd/index/remote/Index.proto
@@ -107,6 +107,7 @@ message Position {
message HeaderWithReferences {
optional string header = 1;
optional uint32 references = 2;
+ optional uint32 supported_directives = 3;
}
message RelationsRequest {
diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp
index 4271fd7..7e31ada 100644
--- a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp
+++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp
@@ -406,6 +406,7 @@ llvm::Expected<HeaderWithReferences> Marshaller::toProtobuf(
const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader) {
HeaderWithReferences Result;
Result.set_references(IncludeHeader.References);
+ Result.set_supported_directives(IncludeHeader.SupportedDirectives);
const std::string Header = IncludeHeader.IncludeHeader.str();
if (isLiteralInclude(Header)) {
Result.set_header(Header);
@@ -427,8 +428,12 @@ Marshaller::fromProtobuf(const HeaderWithReferences &Message) {
return URIString.takeError();
Header = *URIString;
}
- return clangd::Symbol::IncludeHeaderWithReferences{Strings.save(Header),
- Message.references()};
+ auto Directives = clangd::Symbol::IncludeDirective::Include;
+ if (Message.has_supported_directives())
+ Directives = static_cast<clangd::Symbol::IncludeDirective>(
+ Message.supported_directives());
+ return clangd::Symbol::IncludeHeaderWithReferences{
+ Strings.save(Header), Message.references(), Directives};
}
} // namespace remote
diff --git a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx
index 91e9e5f..b598494 100644
--- a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx
+++ b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx
Binary files differ
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index a7ae111..7c1a2d3 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -79,6 +79,10 @@ MATCHER_P(insertInclude, IncludeHeader, "") {
return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader &&
bool(arg.Includes[0].Insertion);
}
+MATCHER_P(insertIncludeText, InsertedText, "") {
+ return !arg.Includes.empty() && arg.Includes[0].Insertion &&
+ arg.Includes[0].Insertion->newText == InsertedText;
+}
MATCHER(insertInclude, "") {
return !arg.Includes.empty() && bool(arg.Includes[0].Insertion);
}
@@ -812,7 +816,7 @@ TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
Symbol Sym = cls("ns::X");
Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
- Sym.IncludeHeaders.emplace_back(BarURI, 1);
+ Sym.IncludeHeaders.emplace_back(BarURI, 1, Symbol::Include);
// Shorten include path based on search directory and insert.
Annotations Test("int main() { ns::^ }");
TU.Code = Test.code().str();
@@ -843,8 +847,8 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
auto BarURI = URI::create(BarHeader).toString();
SymX.CanonicalDeclaration.FileURI = BarURI.c_str();
SymY.CanonicalDeclaration.FileURI = BarURI.c_str();
- SymX.IncludeHeaders.emplace_back("<bar>", 1);
- SymY.IncludeHeaders.emplace_back("<bar>", 1);
+ SymX.IncludeHeaders.emplace_back("<bar>", 1, Symbol::Include);
+ SymY.IncludeHeaders.emplace_back("<bar>", 1, Symbol::Include);
// Shorten include path based on search directory and insert.
auto Results = completions(R"cpp(
namespace ns {
@@ -1867,7 +1871,7 @@ TEST(CompletionTest, OverloadBundling) {
// Differences in header-to-insert suppress bundling.
std::string DeclFile = URI::create(testPath("foo")).toString();
NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile.c_str();
- NoArgsGFunc.IncludeHeaders.emplace_back("<foo>", 1);
+ NoArgsGFunc.IncludeHeaders.emplace_back("<foo>", 1, Symbol::Include);
EXPECT_THAT(
completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
UnorderedElementsAre(AllOf(named("GFuncC"), insertInclude("<foo>")),
@@ -1901,8 +1905,8 @@ TEST(CompletionTest, OverloadBundlingSameFileDifferentURI) {
SymX.CanonicalDeclaration.FileURI = BarURI.c_str();
SymY.CanonicalDeclaration.FileURI = BarURI.c_str();
// The include header is different, but really it's the same file.
- SymX.IncludeHeaders.emplace_back("\"bar.h\"", 1);
- SymY.IncludeHeaders.emplace_back(BarURI.c_str(), 1);
+ SymX.IncludeHeaders.emplace_back("\"bar.h\"", 1, Symbol::Include);
+ SymY.IncludeHeaders.emplace_back(BarURI.c_str(), 1, Symbol::Include);
auto Results = completions("void f() { ::ns::^ }", {SymX, SymY}, Opts);
// Expect both results are bundled, despite the different-but-same
@@ -2699,8 +2703,8 @@ TEST(CompletionTest, InsertTheMostPopularHeader) {
std::string DeclFile = URI::create(testPath("foo")).toString();
Symbol Sym = func("Func");
Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
- Sym.IncludeHeaders.emplace_back("\"foo.h\"", 2);
- Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000);
+ Sym.IncludeHeaders.emplace_back("\"foo.h\"", 2, Symbol::Include);
+ Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000, Symbol::Include);
auto Results = completions("Fun^", {Sym}).Completions;
assert(!Results.empty());
@@ -2708,6 +2712,30 @@ TEST(CompletionTest, InsertTheMostPopularHeader) {
EXPECT_EQ(Results[0].Includes.size(), 2u);
}
+TEST(CompletionTest, InsertIncludeOrImport) {
+ std::string DeclFile = URI::create(testPath("foo")).toString();
+ Symbol Sym = func("Func");
+ Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
+ Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000,
+ Symbol::Include | Symbol::Import);
+
+ auto Results = completions("Fun^", {Sym}).Completions;
+ assert(!Results.empty());
+ EXPECT_THAT(Results[0],
+ AllOf(named("Func"), insertIncludeText("#include \"bar.h\"\n")));
+
+ Results = completions("Fun^", {Sym}, {}, "Foo.m").Completions;
+ assert(!Results.empty());
+ // TODO: Once #import integration support is done this should be #import.
+ EXPECT_THAT(Results[0],
+ AllOf(named("Func"), insertIncludeText("#include \"bar.h\"\n")));
+
+ Sym.IncludeHeaders[0].SupportedDirectives = Symbol::Import;
+ Results = completions("Fun^", {Sym}).Completions;
+ assert(!Results.empty());
+ EXPECT_THAT(Results[0], AllOf(named("Func"), Not(insertInclude())));
+}
+
TEST(CompletionTest, NoInsertIncludeIfOnePresent) {
Annotations Test(R"cpp(
#include "foo.h"
@@ -2719,8 +2747,8 @@ TEST(CompletionTest, NoInsertIncludeIfOnePresent) {
std::string DeclFile = URI::create(testPath("foo")).toString();
Symbol Sym = func("Func");
Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
- Sym.IncludeHeaders.emplace_back("\"foo.h\"", 2);
- Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000);
+ Sym.IncludeHeaders.emplace_back("\"foo.h\"", 2, Symbol::Include);
+ Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000, Symbol::Include);
EXPECT_THAT(completions(TU, Test.point(), {Sym}).Completions,
UnorderedElementsAre(AllOf(named("Func"), hasInclude("\"foo.h\""),
diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
index 0727fff..2b52714 100644
--- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -1071,7 +1071,7 @@ buildIndexWithSymbol(llvm::ArrayRef<SymbolWithHeader> Syms) {
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.CanonicalDeclaration.FileURI = S.DeclaringFile.c_str();
Sym.Definition.FileURI = S.DeclaringFile.c_str();
- Sym.IncludeHeaders.emplace_back(S.IncludeHeader, 1);
+ Sym.IncludeHeaders.emplace_back(S.IncludeHeader, 1, Symbol::Include);
Slab.insert(Sym);
}
return MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab());
@@ -1129,7 +1129,7 @@ TEST(IncludeFixerTest, IncompleteEnum) {
Symbol Sym = enm("X");
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.CanonicalDeclaration.FileURI = Sym.Definition.FileURI = "unittest:///x.h";
- Sym.IncludeHeaders.emplace_back("\"x.h\"", 1);
+ Sym.IncludeHeaders.emplace_back("\"x.h\"", 1, Symbol::Include);
SymbolSlab::Builder Slab;
Slab.insert(Sym);
auto Index =
@@ -1172,7 +1172,7 @@ int main() {
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.CanonicalDeclaration.FileURI = "unittest:///x.h";
Sym.Definition.FileURI = "unittest:///x.cc";
- Sym.IncludeHeaders.emplace_back("\"x.h\"", 1);
+ Sym.IncludeHeaders.emplace_back("\"x.h\"", 1, Symbol::Include);
SymbolSlab::Builder Slab;
Slab.insert(Sym);
@@ -1503,7 +1503,7 @@ TEST(IncludeFixerTest, CImplicitFunctionDecl) {
Symbol Sym = func("foo");
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.CanonicalDeclaration.FileURI = "unittest:///foo.h";
- Sym.IncludeHeaders.emplace_back("\"foo.h\"", 1);
+ Sym.IncludeHeaders.emplace_back("\"foo.h\"", 1, Symbol::Include);
SymbolSlab::Builder Slab;
Slab.insert(Sym);
diff --git a/clang-tools-extra/clangd/unittests/IndexTests.cpp b/clang-tools-extra/clangd/unittests/IndexTests.cpp
index 5b9b360..658b4e2 100644
--- a/clang-tools-extra/clangd/unittests/IndexTests.cpp
+++ b/clang-tools-extra/clangd/unittests/IndexTests.cpp
@@ -567,9 +567,9 @@ TEST(MergeTest, MergeIncludesOnDifferentDefinitions) {
L.Name = "left";
R.Name = "right";
L.ID = R.ID = SymbolID("hello");
- L.IncludeHeaders.emplace_back("common", 1);
- R.IncludeHeaders.emplace_back("common", 1);
- R.IncludeHeaders.emplace_back("new", 1);
+ L.IncludeHeaders.emplace_back("common", 1, Symbol::Include);
+ R.IncludeHeaders.emplace_back("common", 1, Symbol::Include);
+ R.IncludeHeaders.emplace_back("new", 1, Symbol::Include);
// Both have no definition.
Symbol M = mergeSymbol(L, R);
@@ -615,7 +615,7 @@ TEST(MergeIndexTest, IncludeHeadersMerged) {
std::move(DynData), DynSize);
SymbolSlab::Builder StaticB;
- S.IncludeHeaders.push_back({"<header>", 0});
+ S.IncludeHeaders.push_back({"<header>", 0, Symbol::Include});
StaticB.insert(S);
auto StaticIndex =
MemIndex::build(std::move(StaticB).build(), RefSlab(), RelationSlab());
diff --git a/clang-tools-extra/clangd/unittests/SerializationTests.cpp b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
index ae1914f..38e8612 100644
--- a/clang-tools-extra/clangd/unittests/SerializationTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
@@ -53,8 +53,16 @@ ReturnType: 'int'
IncludeHeaders:
- Header: 'include1'
References: 7
+ Directives: [ Include ]
- Header: 'include2'
References: 3
+ Directives: [ Import ]
+ - Header: 'include3'
+ References: 2
+ Directives: [ Include, Import ]
+ - Header: 'include4'
+ References: 1
+ Directives: [ ]
...
---
!Symbol
@@ -114,8 +122,11 @@ DirectIncludes:
MATCHER_P(id, I, "") { return arg.ID == cantFail(SymbolID::fromStr(I)); }
MATCHER_P(qName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
-MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") {
- return (arg.IncludeHeader == IncludeHeader) && (arg.References == References);
+MATCHER_P3(IncludeHeaderWithRefAndDirectives, IncludeHeader, References,
+ SupportedDirectives, "") {
+ return (arg.IncludeHeader == IncludeHeader) &&
+ (arg.References == References) &&
+ (arg.SupportedDirectives == SupportedDirectives);
}
auto readIndexFile(llvm::StringRef Text) {
@@ -148,9 +159,14 @@ TEST(SerializationTest, YAMLConversions) {
EXPECT_EQ(static_cast<uint8_t>(Sym1.Flags), 129);
EXPECT_TRUE(Sym1.Flags & Symbol::IndexedForCodeCompletion);
EXPECT_FALSE(Sym1.Flags & Symbol::Deprecated);
- EXPECT_THAT(Sym1.IncludeHeaders,
- UnorderedElementsAre(IncludeHeaderWithRef("include1", 7u),
- IncludeHeaderWithRef("include2", 3u)));
+ EXPECT_THAT(
+ Sym1.IncludeHeaders,
+ UnorderedElementsAre(
+ IncludeHeaderWithRefAndDirectives("include1", 7u, Symbol::Include),
+ IncludeHeaderWithRefAndDirectives("include2", 3u, Symbol::Import),
+ IncludeHeaderWithRefAndDirectives("include3", 2u,
+ Symbol::Include | Symbol::Import),
+ IncludeHeaderWithRefAndDirectives("include4", 1u, Symbol::Invalid)));
EXPECT_THAT(Sym2, qName("clang::Foo2"));
EXPECT_EQ(Sym2.Signature, "-sig");