Upstream-bug: http://code.google.com/p/include-what-you-use/issues/detail?id=110 Index: tests/elaboration-struct.h =================================================================== --- tests/elaboration-struct.h (revision 0) +++ tests/elaboration-struct.h (revision 0) @@ -0,0 +1,10 @@ +//===--- elaboration-struct.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. +// +//===----------------------------------------------------------------------===// + +struct ElaborationStruct {}; Property changes on: tests\elaboration-struct.h ___________________________________________________________________ Added: svn:eol-style + native Index: tests/elaboration.cc =================================================================== --- tests/elaboration.cc (revision 0) +++ tests/elaboration.cc (revision 0) @@ -0,0 +1,79 @@ +//===--- elaboration.cc - 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. +// +//===----------------------------------------------------------------------===// + +// Test that elaborated types are handled correctly. +// +// An elaborated type is a type prefixed by type kind, e.g. 'class Foo', +// 'struct Bar' or 'enum Baz'. +// +// Clang considers namespace-qualified types elaborated as well, even if they +// lack actual elaboration, e.g. 'ns::Foo'. + + +#include "tests/elaboration-enum1.h" // for ElaborationEnum1 +#include "tests/elaboration-enum2.h" // for ElaborationEnum2 + +// Make sure both elaborated and bare enums require the full type. +void bare_enum(ElaborationEnum1 e); +void elaborated_enum(enum ElaborationEnum2 e); + +// For C++ classes, a forward declaration should suffice for +// bare type names and nothing should be necessary for elaborated ones. +#include "tests/elaboration-class.h" + +void bare_class(ElaborationClass* c); +void elaborated_class(class UnknownElaborationClass* c); + +// Structs should work like classes. +#include "tests/elaboration-struct.h" + +void bare_struct(ElaborationStruct* s); +void elaborated_struct(struct UnknownElaborationStruct* s); + +// And unions. +#include "tests/elaboration-union.h" + +void bare_union(ElaborationUnion* u); +void elaborated_union(union UnknownElaborationUnion* u); + +// Namespace-qualified types must be forward-declared even +// if they are represented as elaborated types in Clang's AST. +#include "tests/elaboration-namespace.h" + +void namespace_qualified(Elaboration::Class* c); + +// We can use elaborated types for templates, too, but +// they must also be forward-declared. +struct Elaboration::Template* namespace_qualified_template; + +/**** IWYU_SUMMARY + +tests/elaboration.cc should add these lines: +class ElaborationClass; +namespace Elaboration { class Class; } +namespace Elaboration { template struct Template; } +struct ElaborationStruct; +union ElaborationUnion; + +tests/elaboration.cc should remove these lines: +- #include "tests/elaboration-class.h" // lines XX-XX +- #include "tests/elaboration-namespace.h" // lines XX-XX +- #include "tests/elaboration-struct.h" // lines XX-XX +- #include "tests/elaboration-union.h" // lines XX-XX + +The full include-list for tests/elaboration.cc: +#include "tests/elaboration-enum1.h" // for ElaborationEnum1 +#include "tests/elaboration-enum2.h" // for ElaborationEnum2 +class ElaborationClass; +namespace Elaboration { class Class; } +namespace Elaboration { template struct Template; } +struct ElaborationStruct; +union ElaborationUnion; + +***** IWYU_SUMMARY */ Index: tests/elaboration-enum1.h =================================================================== --- tests/elaboration-enum1.h (revision 0) +++ tests/elaboration-enum1.h (revision 0) @@ -0,0 +1,13 @@ +//===--- elaboration-enum1.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. +// +//===----------------------------------------------------------------------===// + +enum ElaborationEnum1 { + EE1_First, + EE1_Second +}; Property changes on: tests\elaboration-enum1.h ___________________________________________________________________ Added: svn:eol-style + native Index: tests/elaboration-class.h =================================================================== --- tests/elaboration-class.h (revision 0) +++ tests/elaboration-class.h (revision 0) @@ -0,0 +1,10 @@ +//===--- elaboration-class.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. +// +//===----------------------------------------------------------------------===// + +class ElaborationClass {}; Property changes on: tests\elaboration-class.h ___________________________________________________________________ Added: svn:eol-style + native Index: tests/badinc.cc =================================================================== --- tests/badinc.cc (revision 485) +++ tests/badinc.cc (working copy) @@ -317,17 +317,12 @@ // IWYU: I2_Class is...*badinc-i2.h.*for autocast // IWYU: I2_Class needs a declaration const I2_Class& i2, - const class I1_Class& elaborated_i1, - // IWYU: I2_Class is...*badinc-i2.h.*for autocast - const class I2_Class& elaborated_i2, // A subtle c++ point: forward-declaring is ok for i2b, because // you can't do implicit conversion to a non-const reference // (implicit conversion involves creating a temporary, which // doesn't bind to non-const references). // IWYU: I2_Class needs a declaration I2_Class& i2_nonconst, - class I2_Class& elaborated_i2_nonconst, - struct i3_ns1::i3_ns2::i3_ns3::I3_ForwardDeclareNamespaceStruct* i3_forward, // Forward-declaring is ok because we a const reference to a *pointer*. // IWYU: I2_Class needs a declaration I2_Class* const & i2_ptrref, @@ -897,11 +892,6 @@ // IWYU: I3_ForwardDeclareNamespaceTemplateStruct needs a declaration i3_ns1::i3_ns2::i3_ns3::I3_ForwardDeclareNamespaceTemplateStruct* i3_fdtns_struct; -// Even with elaboration, we still need fwd decl. -// IWYU: I3_ForwardDeclareNamespaceTemplateStruct needs a declaration -struct i3_ns1::i3_ns2::i3_ns3::I3_ForwardDeclareNamespaceTemplateStruct* - i3_elaborated_fdtns_struct; // IWYU: I3_UnnamedNamespaceStruct needs a declaration i3_ns1::I3_UnnamedNamespaceStruct* i3_unnamed_namespace_struct; Index: tests/elaboration-enum2.h =================================================================== --- tests/elaboration-enum2.h (revision 0) +++ tests/elaboration-enum2.h (revision 0) @@ -0,0 +1,13 @@ +//===--- elaboration-enum2.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. +// +//===----------------------------------------------------------------------===// + +enum ElaborationEnum2 { + EE2_First, + EE2_Second +}; Property changes on: tests\elaboration-enum2.h ___________________________________________________________________ Added: svn:eol-style + native Index: tests/elaboration-union.h =================================================================== --- tests/elaboration-union.h (revision 0) +++ tests/elaboration-union.h (revision 0) @@ -0,0 +1,10 @@ +//===--- elaboration-union.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. +// +//===----------------------------------------------------------------------===// + +union ElaborationUnion {}; Property changes on: tests\elaboration-union.h ___________________________________________________________________ Added: svn:eol-style + native Index: tests/elaboration-namespace.h =================================================================== --- tests/elaboration-namespace.h (revision 0) +++ tests/elaboration-namespace.h (revision 0) @@ -0,0 +1,18 @@ +//===--- elaboration-namespace.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. +// +//===----------------------------------------------------------------------===// + +namespace Elaboration { + class Class {}; + + template< typename T, typename U > + struct Template { + typedef T FirstType; + typedef U SecondType; + }; +} Property changes on: tests\elaboration-namespace.h ___________________________________________________________________ Added: svn:eol-style + native Index: iwyu.cc =================================================================== --- iwyu.cc (revision 485) +++ iwyu.cc (working copy) @@ -166,6 +166,7 @@ using clang::DeclContext; using clang::DeclRefExpr; using clang::ElaboratedType; +using clang::EnumType; using clang::Expr; using clang::FileEntry; using clang::FriendDecl; @@ -3454,6 +3455,7 @@ preprocessor_info().FileInfoFor(CurrentFileEntry())->AddForwardDeclare( decl_to_fwd_declare, definitely_keep_fwd_decl); } + return Base::VisitTagDecl(decl); } @@ -3562,13 +3564,17 @@ // If we're forward-declarable, then no complicated checking is // needed: just forward-declare. If we're already elaborated // ('class Foo x') but not namespace-qualified ('class ns::Foo x') - // there's no need even to forward-declare! + // or an enum ('enum Foo x') there's no need even to forward-declare! if (CanForwardDeclareType(current_ast_node())) { current_ast_node()->set_in_forward_declare_context(true); + + bool is_enum_type = current_ast_node()->GetAs(); if (!IsElaborationNode(current_ast_node()->parent()) || - IsNamespaceQualifiedNode(current_ast_node()->parent())) { + IsNamespaceQualifiedNode(current_ast_node()->parent()) || + is_enum_type) { ReportDeclForwardDeclareUse(CurrentLoc(), type->getDecl()); } + return Base::VisitTagType(type); }