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 @@ -33,7 +33,9 @@ class ReferencedLocationCrawler : public RecursiveASTVisitor { public: - ReferencedLocationCrawler(ReferencedLocations &Result) : Result(Result) {} + ReferencedLocationCrawler(ReferencedLocations &Result, + const SourceManager &SM) + : Result(Result), SM(SM) {} bool VisitDeclRefExpr(DeclRefExpr *DRE) { add(DRE->getDecl()); @@ -120,6 +122,18 @@ void add(const Decl *D) { if (!D || !isNew(D->getCanonicalDecl())) return; + // If we see a declaration in the mainfile, skip all non-definition decls. + // We only do this for classes because forward declarations are common and + // we don't want to include every header that forward-declares the symbol + // because they're often unrelated. + if (const auto *RD = llvm::dyn_cast(D)) { + const auto *MostRecent = RD->getMostRecentDecl(); + if (SM.isInMainFile(MostRecent->getBeginLoc())) { + if (const auto *Definition = RD->getDefinition()) + Result.insert(Definition->getLocation()); + return; + } + } for (const Decl *Redecl : D->redecls()) Result.insert(Redecl->getLocation()); } @@ -128,6 +142,7 @@ ReferencedLocations &Result; llvm::DenseSet Visited; + const SourceManager &SM; }; // Given a set of referenced FileIDs, determines all the potentially-referenced @@ -253,7 +268,7 @@ ReferencedLocations findReferencedLocations(ParsedAST &AST) { trace::Span Tracer("IncludeCleaner::findReferencedLocations"); ReferencedLocations Result; - ReferencedLocationCrawler Crawler(Result); + ReferencedLocationCrawler Crawler(Result, AST.getSourceManager()); Crawler.TraverseAST(AST.getASTContext()); findReferencedMacros(AST, Result); return Result; diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -39,6 +39,16 @@ "class ^X;", "X *y;", }, + { + "class ^X {}; class ^X;", + "X *y;", + }, + // We already have forward declaration in the main file, the other + // non-definition declarations are not needed. + { + "class ^X {}; class X;", + "class X; X *y;", + }, // TypedefType and UsingDecls { "using ^Integer = int;",