[PATCH] D114949: [clangd] IncludeCleaner: Do not require forward declarations of RecordDecls when definition is available
Kirill Bobyrev via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 2 05:42:20 PST 2021
kbobyrev created this revision.
kbobyrev added a reviewer: kadircet.
Herald added subscribers: usaxena95, arphaman.
kbobyrev requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.
This makes IncludeCleaner more useful in the presense of a large number of
forward declarations. If the definition is already in the Translation Unit and
visible to the Main File, forward declarations have no effect.
The original patch D112707 <https://reviews.llvm.org/D112707> was split in two: D114864 <https://reviews.llvm.org/D114864> and this one.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D114949
Files:
clang-tools-extra/clangd/IncludeCleaner.cpp
clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -39,10 +39,10 @@
"class ^X;",
"X *y;",
},
- // FIXME(kirillbobyrev): When definition is available, we don't need to
- // mark forward declarations as used.
+ // When definition is available, we don't need to mark forward
+ // declarations as used.
{
- "class ^X {}; class ^X;",
+ "class ^X {}; class X;",
"X *y;",
},
// We already have forward declaration in the main file, the other
@@ -51,13 +51,20 @@
"class ^X {}; class X;",
"class X; X *y;",
},
+ // Nested class definition can occur outside of the parent class
+ // definition. Bar declaration should be visible to its definition but
+ // it will always be because we will mark Foo definition as used.
+ {
+ "class ^Foo { class Bar; };",
+ "class Foo::Bar {};",
+ },
// TypedefType and UsingDecls
{
"using ^Integer = int;",
"Integer x;",
},
{
- "namespace ns { struct ^X; struct ^X {}; }",
+ "namespace ns { struct X; struct ^X {}; }",
"using ns::X;",
},
{
@@ -88,8 +95,8 @@
},
// Redecls
{
- "class ^X; class ^X{}; class ^X;",
- "X *y;",
+ "void ^foo(); void ^foo() {} void ^foo();",
+ "void bar() { foo(); }",
},
// Constructor
{
Index: clang-tools-extra/clangd/IncludeCleaner.cpp
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.cpp
+++ clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -122,13 +122,33 @@
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.
+ // Handle RecordDecls separately: classes and structs are often
+ // forward-declared and we don't want to include every header that
+ // forward-declares the symbol because they're often unrelated. Also, if
+ // definition is available, we can safely skip forward declarations because
+ // they have no effect. The only exception is symbols that require their
+ // original declaration because of the scope specifier, e.g. nested
+ // classes:
+ //
+ // Foo.h:
+ // class Foo { class Bar; }
+ //
+ // Foo.cpp
+ // class Foo::Bar {};
+ //
+ // Here, Foo::Bar definition will require the original declaration inside
+ // Foo, but it will be available because we will still mark Foo definition
+ // as used.
if (const auto *RD = llvm::dyn_cast<RecordDecl>(D)) {
- if (SM.isInMainFile(RD->getMostRecentDecl()->getBeginLoc())) {
- if (const auto *Definition = RD->getMostRecentDecl()->getDefinition())
+ const auto *Definition = RD->getDefinition();
+ if (Definition) {
+ Result.insert(Definition->getLocation());
+ return;
+ }
+ // If we see a declaration in the mainfile, skip all non-definition
+ // decls.
+ if (SM.isInMainFile(RD->getMostRecentDecl()->getLocation())) {
+ if (Definition)
Result.insert(Definition->getLocation());
return;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D114949.391290.patch
Type: text/x-patch
Size: 3689 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20211202/31657e92/attachment.bin>
More information about the cfe-commits
mailing list