From 0d8bfad5e96106793c3b014cd80b6424bda7c5fd Mon Sep 17 00:00:00 2001 From: Bolshakov Date: Wed, 4 Sep 2024 17:00:01 +0300 Subject: [PATCH] Consider associated header desired includes The statement that IWYU doesn't change associated headers is clearly wrong. When handling a main file, it should take into account what it suggests to do with its associated headers, not what those headers look like at the moment of the analysis. It is assumed that the desired `#include`s of the associated headers have been calculated before handling the main file, as it was already assumed in the code. This fixes #1142. --- iwyu_output.cc | 16 ++++++++-------- tests/cxx/associated_include-d1.h | 12 ++++++++++++ tests/cxx/associated_include-d2.h | 10 ++++++++++ tests/cxx/associated_include-i2.h | 17 +++++++++++++++++ tests/cxx/associated_include-i3.h | 15 +++++++++++++++ tests/cxx/associated_include.cc | 14 ++++++++++++++ tests/cxx/associated_include.h | 6 ++++++ 7 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 tests/cxx/associated_include-d1.h create mode 100644 tests/cxx/associated_include-d2.h create mode 100644 tests/cxx/associated_include-i2.h create mode 100644 tests/cxx/associated_include-i3.h diff --git a/iwyu_output.cc b/iwyu_output.cc index e227ee2a7..011580429 100644 --- a/iwyu_output.cc +++ b/iwyu_output.cc @@ -828,13 +828,13 @@ bool DeclIsVisibleToUseInSameFile(const Decl* decl, const OneUse& use) { // might be "calculate minimal-ish includes". :-) It populates // each OneUse in uses with the best #include for that use. // direct_includes: this file's direct includes only. -// associated_direct_includes: direct includes for 'associated' +// associated_desired_includes: desired includes for 'associated' // files. For everything but foo.cc, this is empty; for foo.cc it's // foo.h's includes and foo-inl.h's includes. set CalculateMinimalIncludes( const string& use_quoted_include, const set& direct_includes, - const set& associated_direct_includes, + const set& associated_desired_includes, vector* uses) { set desired_headers; @@ -875,9 +875,8 @@ set CalculateMinimalIncludes( // Steps (2): Go through the needed private-includes that map to // more than one public #include. Use the following priority order: // - Ourselves. - // - An include in associated_direct_includes (those are includes - // that are not going away, since we can't change associated - // files). + // - An include in associated_desired_includes (those are includes + // that are not going away, since they should be calculated already). // - Includes in direct_includes that are also already in // desired_headers. // - Includes in desired_headers. @@ -900,7 +899,7 @@ set CalculateMinimalIncludes( for (const string& choice : public_headers) { if (use.has_suggested_header()) break; - if (ContainsKey(associated_direct_includes, choice)) { + if (ContainsKey(associated_desired_includes, choice)) { use.set_suggested_header(choice); desired_headers.insert(use.suggested_header()); LogIncludeMapping("in associated header", use); @@ -1697,8 +1696,9 @@ void IwyuFileInfo::CalculateIwyuViolations(vector* uses) { Union(associated_direct_includes, direct_includes()); // (C2) + (C3) Find the minimal 'set cover' for all symbol uses. + const set& associated_desired_includes = AssociatedDesiredIncludes(); const set desired_set_cover = internal::CalculateMinimalIncludes( - quoted_file_, direct_includes(), associated_direct_includes, uses); + quoted_file_, direct_includes(), associated_desired_includes, uses); // (C4) Remove .cc files from desired-includes unless they're in actual-inc. for (const string& header_name : desired_set_cover) { @@ -1714,7 +1714,7 @@ void IwyuFileInfo::CalculateIwyuViolations(vector* uses) { // NOTE: this depends on our associated headers having had their // iwyu analysis done before us. set effective_desired_includes = desired_includes(); - InsertAllInto(AssociatedDesiredIncludes(), &effective_desired_includes); + InsertAllInto(associated_desired_includes, &effective_desired_includes); // Now that we've figured out desired_includes, figure out iwyu violations. for (OneUse& use : *uses) { diff --git a/tests/cxx/associated_include-d1.h b/tests/cxx/associated_include-d1.h new file mode 100644 index 000000000..5390dbe66 --- /dev/null +++ b/tests/cxx/associated_include-d1.h @@ -0,0 +1,12 @@ +//===--- associated_include-d1.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "tests/cxx/associated_include-i2.h" // IWYU pragma: export + +class ClassFromD1 {}; diff --git a/tests/cxx/associated_include-d2.h b/tests/cxx/associated_include-d2.h new file mode 100644 index 000000000..b64a8dca0 --- /dev/null +++ b/tests/cxx/associated_include-d2.h @@ -0,0 +1,10 @@ +//===--- associated_include-d2.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "tests/cxx/associated_include-i3.h" // IWYU pragma: export diff --git a/tests/cxx/associated_include-i2.h b/tests/cxx/associated_include-i2.h new file mode 100644 index 000000000..56743adf5 --- /dev/null +++ b/tests/cxx/associated_include-i2.h @@ -0,0 +1,17 @@ +//===--- associated_include-i2.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_ASSOCIATED_INCLUDE_I2_H_ +#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_ASSOCIATED_INCLUDE_I2_H_ + +#include "tests/cxx/associated_include-i3.h" + +class ClassExportedThroughD1 {}; + +#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_ASSOCIATED_INCLUDE_I2_H_ diff --git a/tests/cxx/associated_include-i3.h b/tests/cxx/associated_include-i3.h new file mode 100644 index 000000000..5ef81b9d5 --- /dev/null +++ b/tests/cxx/associated_include-i3.h @@ -0,0 +1,15 @@ +//===--- associated_include-i3.h - test input file for iwyu ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef INCLUDE_WHAT_YOU_USE_TESTS_CXX_ASSOCIATED_INCLUDE_I3_H_ +#define INCLUDE_WHAT_YOU_USE_TESTS_CXX_ASSOCIATED_INCLUDE_I3_H_ + +class ClassFromI3 {}; + +#endif // INCLUDE_WHAT_YOU_USE_TESTS_CXX_ASSOCIATED_INCLUDE_I3_H_ diff --git a/tests/cxx/associated_include.cc b/tests/cxx/associated_include.cc index d04f12bd1..ee89d1af4 100644 --- a/tests/cxx/associated_include.cc +++ b/tests/cxx/associated_include.cc @@ -14,10 +14,22 @@ // 'associated' .h file, we don't try to add it to the .cc file. #include "tests/cxx/associated_include.h" +#include "tests/cxx/associated_include-d1.h" +#include "tests/cxx/associated_include-d2.h" IndirectClass ic; AssociatedIncludeClass aic; +// IWYU should not consider "*-i2.h" as being present in the associated header +// (because it should be removed from that), hence the following two types +// should be attributed to "*-d1.h". +ClassExportedThroughD1 aic2; +ClassFromD1 aic3; + +// Despite "*-d2.h" reexports ClassFromI3, IWYU should suggest to remove it +// because it should also suggest to add "*-i3.h" in the associated header. +// IWYU: ClassFromI3 is...*associated_include-i3.h +ClassFromI3 cfi3; /**** IWYU_SUMMARY @@ -25,9 +37,11 @@ tests/cxx/associated_include.cc should add these lines: #include "tests/cxx/indirect.h" tests/cxx/associated_include.cc should remove these lines: +- #include "tests/cxx/associated_include-d2.h" // lines XX-XX The full include-list for tests/cxx/associated_include.cc: #include "tests/cxx/associated_include.h" +#include "tests/cxx/associated_include-d1.h" // for ClassExportedThroughD1, ClassFromD1 #include "tests/cxx/indirect.h" // for IndirectClass ***** IWYU_SUMMARY */ diff --git a/tests/cxx/associated_include.h b/tests/cxx/associated_include.h index 05fdffd17..236495019 100644 --- a/tests/cxx/associated_include.h +++ b/tests/cxx/associated_include.h @@ -9,19 +9,25 @@ #include "tests/cxx/indirect.h" #include "tests/cxx/associated_include-i1.h" +#include "tests/cxx/associated_include-i2.h" namespace hfile { AssociatedIncludeClass aic; +// IWYU: ClassFromI3 is...*associated_include-i3.h +ClassFromI3 cfi3; } /**** IWYU_SUMMARY tests/cxx/associated_include.h should add these lines: +#include "tests/cxx/associated_include-i3.h" tests/cxx/associated_include.h should remove these lines: +- #include "tests/cxx/associated_include-i2.h" // lines XX-XX - #include "tests/cxx/indirect.h" // lines XX-XX The full include-list for tests/cxx/associated_include.h: #include "tests/cxx/associated_include-i1.h" // for AssociatedIncludeClass +#include "tests/cxx/associated_include-i3.h" // for ClassFromI3 ***** IWYU_SUMMARY */