summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLevente Győző Lénárt <leviiibog@gmail.com>2019-07-11 15:45:08 +0200
committerKim Gräsman <kim.grasman@gmail.com>2019-07-31 16:18:09 +0200
commitbc381437ce1e2d9e9b7dd11d377b3c512a160bcf (patch)
tree125a85dd62da9d2f8e3038b2006c2046189b734f
parent4d2bbcc0d98faccfc51d15c6f6a573ec78d7751d (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.cc30
-rw-r--r--tests/cxx/no_fwd_decls.cc4
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.