namespace {
struct MissingIncludeInfo {
- SourceLocation SymRefLocation;
+ include_cleaner::SymbolReference SymRef;
include_cleaner::Header Missing;
};
} // namespace
if (!Satisfied && !Providers.empty() &&
Ref.RT == include_cleaner::RefType::Explicit &&
!shouldIgnore(Providers.front()))
- Missing.push_back({Ref.RefLocation, Providers.front()});
+ Missing.push_back({Ref, Providers.front()});
});
std::vector<const include_cleaner::Include *> Unused;
if (auto Replacement =
HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"),
Angled, tooling::IncludeDirective::Include))
- diag(SM->getSpellingLoc(Inc.SymRefLocation),
- "no header providing %0 is directly included")
- << Spelling
+ diag(SM->getSpellingLoc(Inc.SymRef.RefLocation),
+ "no header providing \"%0\" is directly included")
+ << Inc.SymRef.Target.name()
<< FixItHint::CreateInsertion(
SM->getComposedLoc(SM->getMainFileID(),
Replacement->getOffset()),
llvm_unreachable("Unknown header kind");
}
-std::string getSymbolName(const include_cleaner::Symbol &Sym) {
- switch (Sym.kind()) {
- case include_cleaner::Symbol::Macro:
- return Sym.macro().Name->getName().str();
- case include_cleaner::Symbol::Declaration:
- return llvm::dyn_cast<NamedDecl>(&Sym.declaration())
- ->getQualifiedNameAsString();
- }
- llvm_unreachable("Unknown symbol kind");
-}
-
std::vector<Diag> generateMissingIncludeDiagnostics(
ParsedAST &AST, llvm::ArrayRef<MissingIncludeDiagInfo> MissingIncludes,
llvm::StringRef Code, HeaderFilter IgnoreHeaders) {
Diag &D = Result.emplace_back();
D.Message =
llvm::formatv("No header providing \"{0}\" is directly included",
- getSymbolName(SymbolWithMissingInclude.Symbol));
+ SymbolWithMissingInclude.Symbol.name());
D.Name = "missing-includes";
D.Source = Diag::DiagSource::Clangd;
D.File = AST.tuPath();
const Decl &declaration() const { return *std::get<Declaration>(Storage); }
struct Macro macro() const { return std::get<Macro>(Storage); }
+ std::string name() const;
private:
// Order must match Kind enum!
namespace clang::include_cleaner {
+std::string Symbol::name() const {
+ switch (kind()) {
+ case include_cleaner::Symbol::Macro:
+ return macro().Name->getName().str();
+ case include_cleaner::Symbol::Declaration:
+ return llvm::dyn_cast<NamedDecl>(&declaration())
+ ->getQualifiedNameAsString();
+ }
+ llvm_unreachable("Unknown symbol kind");
+}
+
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) {
switch (S.kind()) {
case Symbol::Declaration:
// CHECK-FIXES: {{^}}
int BarResult = bar();
int BazResult = baz();
-// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: no header providing "baz.h" is directly included [misc-include-cleaner]
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: no header providing "baz" is directly included [misc-include-cleaner]
std::string HelloString;
-// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: no header providing <string> is directly included [misc-include-cleaner]
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: no header providing "std::string" is directly included [misc-include-cleaner]
int FooBarResult = foobar();
-// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: no header providing "public.h" is directly included [misc-include-cleaner]
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: no header providing "foobar" is directly included [misc-include-cleaner]