ioeric updated this revision to Diff 136561.
ioeric marked 2 inline comments as done.
ioeric added a comment.
- Merge with origin/master
- Address review comments.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D43869
Files:
clangd/index/CanonicalIncludes.cpp
clangd/index/CanonicalIncludes.h
clangd/index/SymbolCollector.cpp
unittests/clangd/SymbolCollectorTests.cpp
Index: unittests/clangd/SymbolCollectorTests.cpp
===================================================================
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -547,6 +547,32 @@
}
#endif
+TEST_F(SymbolCollectorTest, STLiosfwd) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ addSystemHeadersMapping(&Includes);
+ CollectorOpts.Includes = &Includes;
+ // Symbols from <iosfwd> should be mapped individually.
+ TestHeaderName = testPath("iosfwd");
+ TestFileName = testPath("iosfwd.cpp");
+ std::string Header = R"(
+ namespace std {
+ class no_map {};
+ class ios {};
+ class ostream {};
+ class filebuf {};
+ } // namespace std
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(
+ QName("std"),
+ AllOf(QName("std::no_map"), IncludeHeader("<iosfwd>")),
+ AllOf(QName("std::ios"), IncludeHeader("<ios>")),
+ AllOf(QName("std::ostream"), IncludeHeader("<ostream>")),
+ AllOf(QName("std::filebuf"), IncludeHeader("<fstream>"))));
+}
+
TEST_F(SymbolCollectorTest, IWYUPragma) {
CollectorOpts.CollectIncludePath = true;
CanonicalIncludes Includes;
Index: clangd/index/SymbolCollector.cpp
===================================================================
--- clangd/index/SymbolCollector.cpp
+++ clangd/index/SymbolCollector.cpp
@@ -154,13 +154,13 @@
/// FIXME: we should handle .inc files whose symbols are expected be exported by
/// their containing headers.
llvm::Optional<std::string>
-getIncludeHeader(const SourceManager &SM, SourceLocation Loc,
- const SymbolCollector::Options &Opts) {
+getIncludeHeader(llvm::StringRef QName, const SourceManager &SM,
+ SourceLocation Loc, const SymbolCollector::Options &Opts) {
llvm::StringRef FilePath = SM.getFilename(Loc);
if (FilePath.empty())
return llvm::None;
if (Opts.Includes) {
- llvm::StringRef Mapped = Opts.Includes->mapHeader(FilePath);
+ llvm::StringRef Mapped = Opts.Includes->mapHeader(FilePath, QName);
if (Mapped != FilePath)
return (Mapped.startswith("<") || Mapped.startswith("\""))
? Mapped.str()
@@ -316,8 +316,8 @@
if (Opts.CollectIncludePath && shouldCollectIncludePath(S.SymInfo.Kind)) {
// Use the expansion location to get the #include header since this is
// where the symbol is exposed.
- if (auto Header =
- getIncludeHeader(SM, SM.getExpansionLoc(ND.getLocation()), Opts))
+ if (auto Header = getIncludeHeader(
+ QName, SM, SM.getExpansionLoc(ND.getLocation()), Opts))
Include = std::move(*Header);
}
S.CompletionFilterText = FilterText;
Index: clangd/index/CanonicalIncludes.h
===================================================================
--- clangd/index/CanonicalIncludes.h
+++ clangd/index/CanonicalIncludes.h
@@ -43,9 +43,17 @@
/// Maps all files matching \p RE to \p CanonicalPath
void addRegexMapping(llvm::StringRef RE, llvm::StringRef CanonicalPath);
+ /// Sets the canonical include for any symbol with \p QualifiedName.
+ /// Symbol mappings take precedence over header mappings.
+ void addSymbolMapping(llvm::StringRef QualifiedName,
+ llvm::StringRef CanonicalPath);
+
/// \return \p Header itself if there is no mapping for it; otherwise, return
/// a canonical header name.
- llvm::StringRef mapHeader(llvm::StringRef Header) const;
+ /// \p QualifiedName of a symbol declared in \p Header can be provided to
+ /// check against the symbol mapping.
+ llvm::StringRef mapHeader(llvm::StringRef Header,
+ llvm::StringRef QualifiedName = "") const;
private:
// A map from header patterns to header names. This needs to be mutable so
@@ -55,6 +63,8 @@
// arbitrary regexes.
mutable std::vector<std::pair<llvm::Regex, std::string>>
RegexHeaderMappingTable;
+ // A map from fully qualified symbol names to header names.
+ llvm::StringMap<std::string> SymbolMapping;
// Guards Regex matching as it's not thread-safe.
mutable std::mutex RegexMutex;
};
@@ -68,8 +78,9 @@
std::unique_ptr<CommentHandler>
collectIWYUHeaderMaps(CanonicalIncludes *Includes);
-/// Adds mapping for system headers. Approximately, the following system headers
-/// are handled:
+/// Adds mapping for system headers and some special symbols (e.g. STL symbols
+/// in <iosfwd> need to be mapped individually). Approximately, the following
+/// system headers are handled:
/// - C++ standard library e.g. bits/basic_string.h$ -> <string>
/// - Posix library e.g. bits/pthreadtypes.h$ -> <pthread.h>
/// - Compiler extensions, e.g. include/avx512bwintrin.h$ -> <immintrin.h>
Index: clangd/index/CanonicalIncludes.cpp
===================================================================
--- clangd/index/CanonicalIncludes.cpp
+++ clangd/index/CanonicalIncludes.cpp
@@ -27,7 +27,19 @@
this->RegexHeaderMappingTable.emplace_back(llvm::Regex(RE), CanonicalPath);
}
-llvm::StringRef CanonicalIncludes::mapHeader(llvm::StringRef Header) const {
+void CanonicalIncludes::addSymbolMapping(llvm::StringRef QualifiedName,
+ llvm::StringRef CanonicalPath) {
+ this->SymbolMapping[QualifiedName] = CanonicalPath;
+}
+
+llvm::StringRef
+CanonicalIncludes::mapHeader(llvm::StringRef Header,
+ llvm::StringRef QualifiedName) const {
+ if (!QualifiedName.empty()) {
+ auto SE = SymbolMapping.find(QualifiedName);
+ if (SE != SymbolMapping.end())
+ return SE->second;
+ }
std::lock_guard<std::mutex> Lock(RegexMutex);
for (auto &Entry : RegexHeaderMappingTable) {
#ifndef NDEBUG
@@ -67,6 +79,53 @@
}
void addSystemHeadersMapping(CanonicalIncludes *Includes) {
+ static const std::vector<std::pair<const char *, const char *>> SymbolMap = {
+ // Map symbols in <iosfwd> to their preferred includes.
+ {"std::basic_filebuf", "<fstream>"},
+ {"std::basic_fstream", "<fstream>"},
+ {"std::basic_ifstream", "<fstream>"},
+ {"std::basic_ofstream", "<fstream>"},
+ {"std::filebuf", "<fstream>"},
+ {"std::fstream", "<fstream>"},
+ {"std::ifstream", "<fstream>"},
+ {"std::ofstream", "<fstream>"},
+ {"std::wfilebuf", "<fstream>"},
+ {"std::wfstream", "<fstream>"},
+ {"std::wifstream", "<fstream>"},
+ {"std::wofstream", "<fstream>"},
+ {"std::basic_ios", "<ios>"},
+ {"std::ios", "<ios>"},
+ {"std::wios", "<ios>"},
+ {"std::basic_iostream", "<iostream>"},
+ {"std::iostream", "<iostream>"},
+ {"std::wiostream", "<iostream>"},
+ {"std::basic_istream", "<istream>"},
+ {"std::istream", "<istream>"},
+ {"std::wistream", "<istream>"},
+ {"std::istreambuf_iterator", "<iterator>"},
+ {"std::ostreambuf_iterator", "<iterator>"},
+ {"std::basic_ostream", "<ostream>"},
+ {"std::ostream", "<ostream>"},
+ {"std::wostream", "<ostream>"},
+ {"std::basic_istringstream", "<sstream>"},
+ {"std::basic_ostringstream", "<sstream>"},
+ {"std::basic_stringbuf", "<sstream>"},
+ {"std::basic_stringstream", "<sstream>"},
+ {"std::istringstream", "<sstream>"},
+ {"std::ostringstream", "<sstream>"},
+ {"std::stringbuf", "<sstream>"},
+ {"std::stringstream", "<sstream>"},
+ {"std::wistringstream", "<sstream>"},
+ {"std::wostringstream", "<sstream>"},
+ {"std::wstringbuf", "<sstream>"},
+ {"std::wstringstream", "<sstream>"},
+ {"std::basic_streambuf", "<streambuf>"},
+ {"std::streambuf", "<streambuf>"},
+ {"std::wstreambuf", "<streambuf>"},
+ };
+ for (const auto &Pair : SymbolMap)
+ Includes->addSymbolMapping(Pair.first, Pair.second);
+
static const std::vector<std::pair<const char *, const char *>>
SystemHeaderMap = {
{"include/__stddef_max_align_t.h$", "<cstddef>"},
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits