From 526827957b856c1823ef3832555aa075d0595527 Mon Sep 17 00:00:00 2001 From: Bolshakov Date: Sat, 9 Jul 2022 21:21:17 +0300 Subject: [PATCH] Fix template instantiation reporting Full template specialization type use requires full information about its template-argument-dependent fields and nested typedefs. But earlier, it wasn't reported in many cases when template specialization type isn't written explicitly in non-fwd-decl context. --- iwyu.cc | 25 +++++++++++++++++++++++++ tests/cxx/badinc.cc | 6 +++--- tests/cxx/placement_new.cc | 1 + 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/iwyu.cc b/iwyu.cc index 7eba191..c9dc3e3 100644 --- a/iwyu.cc +++ b/iwyu.cc @@ -1665,6 +1665,10 @@ class IwyuBaseAstVisitor : public BaseAstVisitor { comment); } } else { + if (const auto* template_spec_type = + dyn_cast(Desugar(type))) { + this->getDerived().ReportTplSpecComponentTypes(template_spec_type); + } if (const NamedDecl* decl = TypeToDeclAsWritten(type)) { decl = GetDefinitionAsWritten(decl); VERRS(6) << "(For type " << PrintableType(type) << "):\n"; @@ -2670,6 +2674,17 @@ class IwyuBaseAstVisitor : public BaseAstVisitor { visitor_state_->processed_overload_locs.insert(loc); } + // Report types needed for template instantiation in cases when template + // specialization type isn't explicitly written in a source code + // in a non-fwd-declarable context (otherwise, they should be reported from + // VisitTemplateSpecializationType), e.g.: + // template struct S { T t; }; + // void fn(const S& s) { // Forward declarations are sufficient here. + // (void)s.t; // Full 'Class' type is needed due to template instantiation. + // } + void ReportTplSpecComponentTypes(const TemplateSpecializationType*) { + } + // Do not add any variables here! If you do, they will not be shared // between the normal iwyu ast visitor and the // template-instantiation visitor, which is almost always a mistake. @@ -4197,6 +4212,16 @@ class IwyuAstConsumer return true; } + // --- Handler declared in IwyuBaseASTVisitor. + + void ReportTplSpecComponentTypes(const TemplateSpecializationType* type) { + const map resugar_map = + GetTplTypeResugarMapForClass(type); + ASTNode node(type); + node.SetParent(current_ast_node()); + instantiated_template_visitor_.ScanInstantiatedType(&node, resugar_map); + } + private: // Class we call to handle instantiated template functions and classes. InstantiatedTemplateVisitor instantiated_template_visitor_; diff --git a/tests/cxx/badinc.cc b/tests/cxx/badinc.cc index f5272c4..d116ec1 100644 --- a/tests/cxx/badinc.cc +++ b/tests/cxx/badinc.cc @@ -1565,17 +1565,17 @@ int main() { // IWYU: i1_ns::I1_NamespaceClass is...*badinc-i1.h I1_Class* i1_class_tpl_ctor = new I1_Class(&i1_namespace_class, 1); - // TODO(csilvers): IWYU: I2_Class needs a declaration + // IWYU: I2_Class is...*badinc-i2.h // IWYU: I2_Class::~I2_Class is...*badinc-i2-inl.h // IWYU: I1_Struct is...*badinc-i1.h // IWYU: I1_TemplateClass is...*badinc-i1.h delete newed_i1_template_class; - // TODO(csilvers): IWYU: I2_Class needs a declaration + // IWYU: I2_Class is...*badinc-i2.h // IWYU: I2_Class::~I2_Class is...*badinc-i2-inl.h // IWYU: I1_Struct is...*badinc-i1.h // IWYU: I1_TemplateClass is...*badinc-i1.h delete[] newed_i1_template_class_array; - // TODO(csilvers): IWYU: I2_Class needs a declaration + // IWYU: I2_Class is...*badinc-i2.h // IWYU: I2_Class::~I2_Class is...*badinc-i2-inl.h // IWYU: I1_Struct is...*badinc-i1.h // IWYU: I1_TemplateClass is...*badinc-i1.h diff --git a/tests/cxx/placement_new.cc b/tests/cxx/placement_new.cc index c760308..3eb4f3a 100644 --- a/tests/cxx/placement_new.cc +++ b/tests/cxx/placement_new.cc @@ -90,6 +90,7 @@ void PlacementNewOfTemplate() { // Make sure we handle it right when we explicitly call the dtor, as well. // IWYU: ClassTemplate is...*placement_new-i1.h + // IWYU: IndirectClass is...*indirect.h placement_newed_template->~ClassTemplate(); }