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 @@ -175,8 +175,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()); @@ -197,8 +195,9 @@ continue; } - std::string Spelling = - spellHeader(AST, MainFile, SymbolWithMissingInclude.Providers.front()); + std::string Spelling = include_cleaner::spellHeader( + SymbolWithMissingInclude.Providers.front(), + AST.getPreprocessor().getHeaderSearchInfo(), AST.getSourceManager()); llvm::StringRef HeaderRef{Spelling}; bool Angled = HeaderRef.starts_with("<"); // We might suggest insertion of an existing include in edge cases, e.g., @@ -318,17 +317,9 @@ 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; - } - } return include_cleaner::spellHeader( - Provider, AST.getPreprocessor().getHeaderSearchInfo(), MainFile); + Provider, AST.getPreprocessor().getHeaderSearchInfo(), + AST.getSourceManager()); } std::vector 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 @@ -18,6 +18,8 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/Registry.h" +#include #include namespace clang { @@ -76,7 +78,7 @@ const format::FormatStyle &IncludeStyle); std::string spellHeader(const Header &H, HeaderSearch &HS, - const FileEntry *Main); + const SourceManager &SM); /// Gets all the providers for a symbol by traversing each location. /// Returned headers are sorted by relevance, first element is the most @@ -85,6 +87,16 @@ const SourceManager &SM, const PragmaIncludes *PI); +class IncludeSpeller { +public: + virtual ~IncludeSpeller() = default; + + virtual std::string spell(const Header &H, HeaderSearch &HS, + const SourceManager &SM) = 0; +}; + +typedef llvm::Registry IncludeSpellingStrategy; + } // 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 @@ -24,10 +24,47 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Registry.h" +#include #include +LLVM_INSTANTIATE_REGISTRY(clang::include_cleaner::IncludeSpellingStrategy) + namespace clang::include_cleaner { +namespace { + +// TODO(bakalova) move to google3 +// class Google3IncludeSpeller : public clang::include_cleaner::IncludeSpeller { +// std::string spell(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 ""; +// } +// }; + +class DefaultIncludeSpeller : public IncludeSpeller { + std::string spell(const Header &H, HeaderSearch &HS, + const SourceManager &SM) override { + bool IsSystem = false; + std::string Path = HS.suggestPathToFileForDiagnostics( + H.physical(), + SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName(), + &IsSystem); + return IsSystem ? "<" + Path + ">" : "\"" + Path + "\""; + } +}; + +IncludeSpellingStrategy::Add + SpellingStrategy("cpp", "Default spelling strategy for C++ includes."); +} // namespace + void walkUsed(llvm::ArrayRef ASTRoots, llvm::ArrayRef MacroRefs, const PragmaIncludes *PI, const SourceManager &SM, @@ -54,13 +91,18 @@ } std::string spellHeader(const Header &H, HeaderSearch &HS, - const FileEntry *Main) { + const SourceManager &SM) { switch (H.kind()) { case Header::Physical: { - bool IsSystem = false; - std::string Path = HS.suggestPathToFileForDiagnostics( - H.physical(), Main->tryGetRealPathName(), &IsSystem); - return IsSystem ? "<" + Path + ">" : "\"" + Path + "\""; + for (const auto &Strategy : + include_cleaner::IncludeSpellingStrategy::entries()) { + std::unique_ptr StrategyInstance = + Strategy.instantiate(); + std::string Spelling = StrategyInstance->spell(H, HS, SM); + if (!Spelling.empty()) + return Spelling; + } + break; } case Header::Standard: return H.standard().name().str(); @@ -90,7 +132,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;