diff --git a/clang-tools-extra/clangd/IncludeCleaner.h b/clang-tools-extra/clangd/IncludeCleaner.h --- a/clang-tools-extra/clangd/IncludeCleaner.h +++ b/clang-tools-extra/clangd/IncludeCleaner.h @@ -20,16 +20,20 @@ #include "Headers.h" #include "ParsedAST.h" +#include "clang-include-cleaner/Analysis.h" #include "clang-include-cleaner/Types.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/Registry.h" #include #include namespace clang { namespace clangd { +typedef llvm::Registry IncludeSpellingStrategy; + // Data needed for missing include diagnostics. struct MissingIncludeDiagInfo { include_cleaner::Symbol Symbol; diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -54,13 +54,20 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/Registry.h" #include #include +#include #include #include #include #include +LLVM_INSTANTIATE_REGISTRY(clang::clangd::IncludeSpellingStrategy) +clang::clangd::IncludeSpellingStrategy::Add< + clang::include_cleaner::DefaultIncludeSpeller> + SpellingStrategy("cpp", "Default spelling strategy for C++ includes."); + namespace clang { namespace clangd { @@ -175,8 +182,6 @@ } const SourceManager &SM = AST.getSourceManager(); - const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()); - auto FileStyle = format::getStyle( format::DefaultFormatStyle, AST.tuPath(), format::DefaultFallbackStyle, Code, &SM.getFileManager().getVirtualFileSystem()); @@ -198,7 +203,8 @@ } std::string Spelling = - spellHeader(AST, MainFile, SymbolWithMissingInclude.Providers.front()); + spellHeader(AST, SM.getFileEntryForID(SM.getMainFileID()), + SymbolWithMissingInclude.Providers.front()); llvm::StringRef HeaderRef{Spelling}; bool Angled = HeaderRef.starts_with("<"); // We might suggest insertion of an existing include in edge cases, e.g., @@ -334,17 +340,17 @@ std::string spellHeader(ParsedAST &AST, const FileEntry *MainFile, include_cleaner::Header Provider) { - if (Provider.kind() == include_cleaner::Header::Physical) { - if (auto CanonicalPath = getCanonicalPath(Provider.physical()->getLastRef(), - AST.getSourceManager())) { - std::string SpelledHeader = - llvm::cantFail(URI::includeSpelling(URI::create(*CanonicalPath))); - if (!SpelledHeader.empty()) - return SpelledHeader; - } + for (const auto &Strategy : IncludeSpellingStrategy::entries()) { + std::unique_ptr Speller = + Strategy.instantiate(); + std::string Spelling = include_cleaner::spellHeader( + Provider, AST.getPreprocessor().getHeaderSearchInfo(), + AST.getSourceManager(), *Speller); + if (!Spelling.empty()) + return Spelling; } - return include_cleaner::spellHeader( - Provider, AST.getPreprocessor().getHeaderSearchInfo(), MainFile); + + return ""; } std::vector @@ -564,8 +570,7 @@ } auto Result = std::move(MissingIncludeDiags); - llvm::move(UnusedIncludes, - std::back_inserter(Result)); + llvm::move(UnusedIncludes, std::back_inserter(Result)); return Result; } diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h --- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h +++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h @@ -13,12 +13,13 @@ #include "clang-include-cleaner/Record.h" #include "clang-include-cleaner/Types.h" +#include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" +#include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/MemoryBufferRef.h" -#include +#include namespace clang { class SourceLocation; @@ -75,8 +76,28 @@ std::string fixIncludes(const AnalysisResults &Results, llvm::StringRef Code, const format::FormatStyle &IncludeStyle); +class IncludeSpeller { +public: + virtual ~IncludeSpeller() = default; + + virtual std::string operator()(const Header &H, HeaderSearch &HS, + const SourceManager &SM) const = 0; +}; + +class DefaultIncludeSpeller : public IncludeSpeller { + std::string operator()(const Header &H, HeaderSearch &HS, + const SourceManager &SM) const override { + bool IsSystem = false; + std::string Path = HS.suggestPathToFileForDiagnostics( + H.physical(), + SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName(), + &IsSystem); + return IsSystem ? "<" + Path + ">" : "\"" + Path + "\""; + } +}; + std::string spellHeader(const Header &H, HeaderSearch &HS, - const FileEntry *Main); + const SourceManager &SM, const IncludeSpeller &Spell); /// Gets all the providers for a symbol by traversing each location. /// Returned headers are sorted by relevance, first element is the most @@ -84,7 +105,6 @@ llvm::SmallVector
headersForSymbol(const Symbol &S, const SourceManager &SM, const PragmaIncludes *PI); - } // namespace include_cleaner } // namespace clang diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp --- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp +++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp @@ -28,6 +28,24 @@ namespace clang::include_cleaner { +namespace { + +// TODO(bakalova) move to google3 +// class Google3IncludeSpeller : public clang::include_cleaner::IncludeSpeller { +// std::string operator()(const Header &H, HeaderSearch &HS, const +// SourceManager &SM) { +// if (auto CanonicalPath = getCanonicalPath(H.physical()->getLastRef(), +// SM)) { +// std::string SpelledHeader = +// llvm::cantFail(devtools::c::clangd::SpellInclude(*CanonicalPath)); +// if (!SpelledHeader.empty()) +// return SpelledHeader; +// } +// return ""; +// } +// }; +} // namespace + void walkUsed(llvm::ArrayRef ASTRoots, llvm::ArrayRef MacroRefs, const PragmaIncludes *PI, const SourceManager &SM, @@ -54,14 +72,11 @@ } std::string spellHeader(const Header &H, HeaderSearch &HS, - const FileEntry *Main) { + const SourceManager &SM, + const IncludeSpeller &Spell = DefaultIncludeSpeller{}) { switch (H.kind()) { - case Header::Physical: { - bool IsSystem = false; - std::string Path = HS.suggestPathToFileForDiagnostics( - H.physical(), Main->tryGetRealPathName(), &IsSystem); - return IsSystem ? "<" + Path + ">" : "\"" + Path + "\""; - } + case Header::Physical: + return Spell(H, HS, SM); case Header::Standard: return H.standard().name().str(); case Header::Verbatim: @@ -90,7 +105,7 @@ } if (!Satisfied && !Providers.empty() && Ref.RT == RefType::Explicit) - Missing.insert(spellHeader(Providers.front(), HS, MainFile)); + Missing.insert(spellHeader(Providers.front(), HS, SM)); }); AnalysisResults Results;