diff options
author | Levente Győző Lénárt <leviiibog@gmail.com> | 2019-07-11 15:45:08 +0200 |
---|---|---|
committer | Kim Gräsman <kim.grasman@gmail.com> | 2019-07-31 16:18:09 +0200 |
commit | bc381437ce1e2d9e9b7dd11d377b3c512a160bcf (patch) | |
tree | 125a85dd62da9d2f8e3038b2006c2046189b734f | |
parent | 4d2bbcc0d98faccfc51d15c6f6a573ec78d7751d (diff) |
Find a decl before the use with --no_fwd_decls
If we find a fwd-decl use with --no_fwd_decls, we see if there is already an
include that provides the decl, and if there is, we keep that include otherwise
we keep the local decl.
-rw-r--r-- | iwyu_output.cc | 30 | ||||
-rw-r--r-- | tests/cxx/no_fwd_decls.cc | 4 |
2 files changed, 27 insertions, 7 deletions
diff --git a/iwyu_output.cc b/iwyu_output.cc index 7ad540d..027e7ec 100644 --- a/iwyu_output.cc +++ b/iwyu_output.cc @@ -1105,13 +1105,29 @@ void ProcessForwardDeclare(OneUse* use, } } - // (A7) If --no_fwd_decls has been passed, recategorize as a full use unless - // the decl is in this file (in which case it must be a self-sufficient decl - // being used, so we can just let IWYU do its work). - if (!use->ignore_use() && - GlobalFlags().no_fwd_decls && - GetFileEntry(use->decl_loc()) != GetFileEntry(use->use_loc())) { - use->set_full_use(); + // (A7) If --no_fwd_decls has been passed, and a decl can be found in one of + // the headers, suggest that header, and recategorize as a full use. If we can + // only find a decl in this file, it must be a self-sufficent decl being used, + // so we can just let IWYU do its work, and there is no need to recategorize. + if (!use->ignore_use() && GlobalFlags().no_fwd_decls) { + bool promote_to_full_use = true; + for (const Decl* decl = use->decl(); decl != nullptr; + decl = decl->getPreviousDecl()) { + if (IsBeforeInSameFile(decl->getLocation(), use->use_loc())) { + promote_to_full_use = false; + } else if (IsBeforeInTranslationUnit(decl->getLocation(), + use->use_loc())) { + // TODO: Choose a redecl that is already provided by a desired include, so we + // don't keep another include that is not necessary. + use->reset_decl(cast<NamedDecl>(decl)); + promote_to_full_use = true; + break; + } + } + + if (promote_to_full_use) { + use->set_full_use(); + } } } diff --git a/tests/cxx/no_fwd_decls.cc b/tests/cxx/no_fwd_decls.cc index b1a6eb2..e85eea6 100644 --- a/tests/cxx/no_fwd_decls.cc +++ b/tests/cxx/no_fwd_decls.cc @@ -29,6 +29,10 @@ IndirectClass* global; class LocalFwd; void ForwardDeclareUse(const LocalFwd*); +// IWYU must not remove the forward declaration of this class even though its +// definition can be found in the same file but after the use +class LocalFwd {}; + // A forward-declare that also exists in an included header can be removed. // Normally IWYU would optimize for fewer includes, but in --no_fwd_decls mode // we optimize for fewer redeclarations instead. |