Report only explicit typedefs
Previously, ReportDeclUse was called for TypedefDecl when TypedefType is passed to ReportTypeUse. This change short-circuits that path. But an underlying type should still be reported if the typedef doesn't "provide" it. Hence, corresponding logic is moved into ReportTypeUse. So ReportDeclUse reports typedef declarations and ReportTypeUse reports typedef underlying types now.
This commit is contained in:
parent
8a6009f587
commit
971a300bb9
73
iwyu.cc
73
iwyu.cc
|
@ -1604,34 +1604,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
|
|||
preprocessor_info().FileInfoFor(used_in)->ReportUsingDeclUse(
|
||||
used_loc, using_decl, use_flags, "(for using decl)");
|
||||
}
|
||||
|
||||
// For typedefs, the user of the type is sometimes the one
|
||||
// responsible for the underlying type. We check if that is the
|
||||
// case here, since we might be using a typedef type from
|
||||
// anywhere. ('autocast' is similar, but is handled in
|
||||
// VisitCastExpr; 'fn-return-type' is also similar and is
|
||||
// handled in HandleFunctionCall.)
|
||||
if (const TypedefNameDecl* typedef_decl = DynCastFrom(target_decl)) {
|
||||
// One exception: if this TypedefType is being used in another
|
||||
// typedef (that is, 'typedef MyTypedef OtherTypdef'), then the
|
||||
// user -- the other typedef -- is never responsible for the
|
||||
// underlying type. Instead, users of that typedef are.
|
||||
const ASTNode* ast_node = MostElaboratedAncestor(current_ast_node());
|
||||
if (!ast_node->ParentIsA<TypedefNameDecl>()) {
|
||||
const set<const Type*>& underlying_types =
|
||||
GetCallerResponsibleTypesForTypedef(typedef_decl);
|
||||
if (!underlying_types.empty()) {
|
||||
VERRS(6) << "User, not author, of typedef "
|
||||
<< typedef_decl->getQualifiedNameAsString()
|
||||
<< " owns the underlying type:\n";
|
||||
// If any of the used types are themselves typedefs, this will
|
||||
// result in a recursive expansion. Note we are careful to
|
||||
// recurse inside this class, and not go back to subclasses.
|
||||
for (const Type* type : underlying_types)
|
||||
IwyuBaseAstVisitor<Derived>::ReportTypeUse(used_loc, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The comment, if not nullptr, is extra text that is included along
|
||||
|
@ -1699,6 +1671,36 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
|
|||
if (IsPointerOrReferenceAsWritten(type))
|
||||
return;
|
||||
|
||||
// For typedefs, the user of the type is sometimes the one
|
||||
// responsible for the underlying type. We check if that is the
|
||||
// case here, since we might be using a typedef type from
|
||||
// anywhere. ('autocast' is similar, but is handled in
|
||||
// VisitCastExpr; 'fn-return-type' is also similar and is
|
||||
// handled in HandleFunctionCall.)
|
||||
if (const auto* typedef_type = type->getAs<TypedefType>()) {
|
||||
// One exception: if this TypedefType is being used in another
|
||||
// typedef (that is, 'typedef MyTypedef OtherTypdef'), then the
|
||||
// user -- the other typedef -- is never responsible for the
|
||||
// underlying type. Instead, users of that typedef are.
|
||||
const ASTNode* ast_node = MostElaboratedAncestor(current_ast_node());
|
||||
if (!ast_node->ParentIsA<TypedefNameDecl>()) {
|
||||
const TypedefNameDecl* typedef_decl = typedef_type->getDecl();
|
||||
const set<const Type*>& underlying_types =
|
||||
GetCallerResponsibleTypesForTypedef(typedef_decl);
|
||||
if (!underlying_types.empty()) {
|
||||
VERRS(6) << "User, not author, of typedef "
|
||||
<< typedef_decl->getQualifiedNameAsString()
|
||||
<< " owns the underlying type:\n";
|
||||
// If any of the used types are themselves typedefs, this will
|
||||
// result in a recursive expansion. Note we are careful to
|
||||
// recurse inside this class, and not go back to subclasses.
|
||||
for (const Type* type : underlying_types)
|
||||
IwyuBaseAstVisitor<Derived>::ReportTypeUse(used_loc, type);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Map private types like __normal_iterator to their public counterpart.
|
||||
type = MapPrivateTypeToPublicType(type);
|
||||
// For the below, we want to be careful to call *our*
|
||||
|
@ -4123,11 +4125,9 @@ class IwyuAstConsumer
|
|||
if (CanIgnoreCurrentASTNode())
|
||||
return true;
|
||||
// TypedefType::getDecl() returns the place where the typedef is defined.
|
||||
if (CanForwardDeclareType(current_ast_node())) {
|
||||
ReportDeclForwardDeclareUse(CurrentLoc(), type->getDecl());
|
||||
} else {
|
||||
ReportDeclUse(CurrentLoc(), type->getDecl());
|
||||
}
|
||||
ReportDeclUse(CurrentLoc(), type->getDecl());
|
||||
if (!CanForwardDeclareType(current_ast_node()))
|
||||
ReportTypeUse(CurrentLoc(), type);
|
||||
return Base::VisitTypedefType(type);
|
||||
}
|
||||
|
||||
|
@ -4135,11 +4135,16 @@ class IwyuAstConsumer
|
|||
if (CanIgnoreCurrentASTNode())
|
||||
return true;
|
||||
|
||||
// UsingType is similar to TypedefType, so treat it the same.
|
||||
if (CanForwardDeclareType(current_ast_node())) {
|
||||
ReportDeclForwardDeclareUse(CurrentLoc(), type->getFoundDecl());
|
||||
} else {
|
||||
ReportDeclUse(CurrentLoc(), type->getFoundDecl());
|
||||
|
||||
// If UsingType refers to a typedef, report the underlying type of that
|
||||
// typedef if needed (which is determined in ReportTypeUse).
|
||||
const Type* underlying_type = type->getUnderlyingType().getTypePtr();
|
||||
if (isa<TypedefType>(underlying_type))
|
||||
ReportTypeUse(CurrentLoc(), underlying_type);
|
||||
}
|
||||
|
||||
return Base::VisitUsingType(type);
|
||||
|
|
|
@ -1111,7 +1111,8 @@ int main() {
|
|||
// a() returns a FOO, which in this case is I2_Enum.
|
||||
local_d1_template_class.a();
|
||||
(void)(local_i1_enum);
|
||||
// IWYU: I1_UnnamedStruct is...*badinc-i1.h
|
||||
// Typedef of unnamed type always provides that type, and it should be
|
||||
// included due to variable declaration.
|
||||
(void)(local_i1_unnamed_struct.a);
|
||||
local_d1_subclass.a();
|
||||
(void)(local_i2_class_ptr);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//===--- no_implicit_typedef_reporting-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/no_implicit_typedef_reporting-i1.h"
|
|
@ -0,0 +1,28 @@
|
|||
//===--- no_implicit_typedef_reporting-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/no_implicit_typedef_reporting-d1.h"
|
||||
|
||||
struct Struct {
|
||||
// IWYU: Int is...*no_implicit_typedef_reporting-i1.h
|
||||
Int typedefed;
|
||||
};
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting-d2.h should add these lines:
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-i1.h"
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting-d2.h should remove these lines:
|
||||
- #include "tests/cxx/no_implicit_typedef_reporting-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/no_implicit_typedef_reporting-d2.h:
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-i1.h" // for Int
|
||||
|
||||
***** IWYU_SUMMARY */
|
|
@ -0,0 +1,10 @@
|
|||
//===--- no_implicit_typedef_reporting-i1.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef int Int;
|
|
@ -0,0 +1,48 @@
|
|||
//===--- no_implicit_typedef_reporting.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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// IWYU_ARGS: -I . \
|
||||
// -Xiwyu --check_also="tests/cxx/no_implicit_typedef_reporting-d2.h"
|
||||
|
||||
// Tests that IWYU doesn't suggest to include typedef-containing header due to
|
||||
// implicit-only use of the typedef, i.e. when it is not explicitly written
|
||||
// in a source.
|
||||
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d1.h"
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d2.h"
|
||||
|
||||
template <class T1, class T2>
|
||||
struct Template {
|
||||
T1 t1;
|
||||
decltype(T2::typedefed) t2;
|
||||
};
|
||||
|
||||
void Fn() {
|
||||
// Test use in unary expression.
|
||||
(void)sizeof(Struct::typedefed);
|
||||
|
||||
Struct s;
|
||||
// Test use for pointer arithmetic.
|
||||
void* p = &s.typedefed + 10;
|
||||
|
||||
// Test use in instantiated template.
|
||||
Template<decltype(Struct::typedefed), Struct> tpl;
|
||||
}
|
||||
|
||||
/**** IWYU_SUMMARY
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting.cc should add these lines:
|
||||
|
||||
tests/cxx/no_implicit_typedef_reporting.cc should remove these lines:
|
||||
- #include "tests/cxx/no_implicit_typedef_reporting-d1.h" // lines XX-XX
|
||||
|
||||
The full include-list for tests/cxx/no_implicit_typedef_reporting.cc:
|
||||
#include "tests/cxx/no_implicit_typedef_reporting-d2.h" // for Struct
|
||||
|
||||
***** IWYU_SUMMARY */
|
Loading…
Reference in New Issue