Skip to content

Commit

Permalink
Analyze aliased component types
Browse files Browse the repository at this point in the history
This brings several improvements:

- avoiding erroneous consideration of aliased component types
as provided just because their forward declaration is in the other
(internal alias declaring) file;

- avoiding erroneous consideration of aliased template arguments
as provided due to a nested type alias;

- correct handling of aliased types in contexts other than direct
aliased type usage (e. g. when handling function return type);

- recursive handling of nested alias templates similar to `typedef`s;

- avoiding of losing nested `typedef` internals during recursive
collecting their provided types, like `Class` inside such an elaborated
alias: `using AliasedClass = Identity<Class>::Alias;`.
  • Loading branch information
bolshakov-a committed Feb 4, 2024
1 parent d3d5a6a commit 1f53a15
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 18 deletions.
41 changes: 25 additions & 16 deletions iwyu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1450,20 +1450,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {

set<const Type*> GetProvidedTypesForAlias(const Type* underlying_type,
SourceLocation decl_loc) const {
// If the underlying type is itself a typedef, we recurse.
if (const auto* underlying_typedef =
underlying_type->getAs<TypedefType>()) {
if (const auto* underlying_typedef_decl = dyn_cast<TypedefNameDecl>(TypeToDeclAsWritten(underlying_typedef))) {
// TODO(csilvers): if one of the intermediate typedefs
// #includes the necessary definition of the 'final'
// underlying type, do we want to return it here?
return GetProvidedTypesForAlias(
underlying_typedef_decl->getUnderlyingType().getTypePtr(),
GetLocation(underlying_typedef_decl));
}
}
// TODO(bolshakov): handle underlying alias templates.

return GetProvidedTypes(underlying_type, decl_loc);
}

Expand Down Expand Up @@ -2609,8 +2595,31 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
SourceLocation loc) const {
set<const Type*> retval;
for (const Type* component : GetComponentsOfTypeWithoutSubstituted(type)) {
if (!CodeAuthorWantsJustAForwardDeclare(component, loc))
retval.insert(component);
// TODO(csilvers): if one of the intermediate typedefs
// #includes the necessary definition of the 'final'
// underlying type, do we want to return it here?
if (const auto* typedef_type = dyn_cast<TypedefType>(component)) {
InsertAllInto(
GetProvidedTypesForAlias(typedef_type->desugar().getTypePtr(),
GetLocation(typedef_type->getDecl())),
&retval);
continue;
}
if (const auto* tpl_spec_type =
dyn_cast<TemplateSpecializationType>(component)) {
const NamedDecl* decl = TypeToDeclAsWritten(tpl_spec_type);
if (const auto* al_tpl_decl = dyn_cast<TypeAliasTemplateDecl>(decl)) {
const TypeAliasDecl* al_decl = al_tpl_decl->getTemplatedDecl();
InsertAllInto(
GetProvidedTypesForAlias(tpl_spec_type->desugar().getTypePtr(),
GetLocation(al_decl)),
&retval);
continue;
}
}
const Type* canonical = GetCanonicalType(component);
if (!CodeAuthorWantsJustAForwardDeclare(canonical, loc))
retval.insert(canonical);
}
return retval;
}
Expand Down
2 changes: 1 addition & 1 deletion iwyu_ast_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ class TypeEnumeratorWithoutSubstituted
if (IsSubstTemplateTypeParmType(type))
return true;

seen_types_.insert(GetCanonicalType(type));
seen_types_.insert(Desugar(type));

return Base::TraverseType(qual_type);
}
Expand Down
14 changes: 14 additions & 0 deletions tests/cxx/iwyu_stricter_than_cpp-d5.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//===--- iwyu_stricter_than_cpp-d5.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 "iwyu_stricter_than_cpp-i4.h"

// No forward-declaration of 'IndirectClass' here.

IndirectStruct4::IndirectClassNonProvidingTypedef RetNonProvidingTypedef();
5 changes: 5 additions & 0 deletions tests/cxx/iwyu_stricter_than_cpp-i4.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
//
//===----------------------------------------------------------------------===//

#ifndef IWYU_STRICTER_THAN_CPP_I4_H_
#define IWYU_STRICTER_THAN_CPP_I4_H_

class IndirectClass;

struct IndirectStruct4 {
typedef IndirectClass IndirectClassNonProvidingTypedef;

using IndirectClassNonProvidingAl = IndirectClass;
};

#endif // IWYU_STRICTER_THAN_CPP_I4_H_
5 changes: 5 additions & 0 deletions tests/cxx/iwyu_stricter_than_cpp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "tests/cxx/iwyu_stricter_than_cpp-autocast2.h"
#include "tests/cxx/iwyu_stricter_than_cpp-d2.h"
#include "tests/cxx/iwyu_stricter_than_cpp-d3.h"
#include "tests/cxx/iwyu_stricter_than_cpp-d5.h"

template <typename T>
void UsingFn() {
Expand Down Expand Up @@ -449,6 +450,9 @@ void TestFunctionReturn() {
using Alias = TplIndirectStruct3<IndirectStruct2, IndirectStruct2>;

Call<Alias, TplAllForwardDeclaredFn>();

// IWYU: IndirectClass is...*indirect.h
RetNonProvidingTypedef();
}

void TestDefaultTplArgs() {
Expand Down Expand Up @@ -493,6 +497,7 @@ The full include-list for tests/cxx/iwyu_stricter_than_cpp.cc:
#include "tests/cxx/indirect.h" // for IndirectClass
#include "tests/cxx/iwyu_stricter_than_cpp-autocast.h" // for FnRefs, FnValues, HeaderDefinedFnRefs, HeaderDefinedTplFnRefs, TplFnRefs, TplFnValues
#include "tests/cxx/iwyu_stricter_than_cpp-d3.h" // for IndirectStruct3ProvidingAl, IndirectStruct3ProvidingTypedef, IndirectStruct4ProvidingAl, IndirectStruct4ProvidingTypedef
#include "tests/cxx/iwyu_stricter_than_cpp-d5.h" // for RetNonProvidingTypedef
#include "tests/cxx/iwyu_stricter_than_cpp-def_tpl_arg.h" // for TplWithDefaultArgs
#include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h" // for DoesEverythingRightFn, DoesNotForwardDeclareAndIncludesFn, DoesNotForwardDeclareFn, DoesNotForwardDeclareProperlyFn, IncludesFn, TplAllForwardDeclaredFn, TplAllNeededTypesProvidedFn, TplDoesEverythingRightAgainFn, TplDoesEverythingRightFn, TplDoesNotForwardDeclareAndIncludesFn, TplDoesNotForwardDeclareFn, TplDoesNotForwardDeclareProperlyFn, TplIncludesFn, TplOnlyArgumentTypeProvidedFn, TplOnlyTemplateProvidedFn
#include "tests/cxx/iwyu_stricter_than_cpp-i2.h" // for IndirectStruct2, TplIndirectStruct2
Expand Down
30 changes: 30 additions & 0 deletions tests/cxx/typedef_chain_in_template-d5.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===--- typedef_chain_in_template-d5.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/typedef_chain_in_template-i1.h"
#include "tests/cxx/typedef_chain_in_template-i2.h"

template <typename T>
struct IdentityStructComplex {
using Type = typename TypedefWrapper<T>::value_type;
};

template <typename T>
using IdentityAlias = T;

template <typename T>
using IdentityAliasComplex = IdentityAlias<T>;

template <typename T>
struct Tpl {
static constexpr auto s = sizeof(T);
};

using TplWithNonProvidedAliased1 = Tpl<NonProvidingAlias>;
using TplWithNonProvidedAliased2 = Tpl<NonProvidingAliasTpl<1>>;
5 changes: 5 additions & 0 deletions tests/cxx/typedef_chain_in_template-i1.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@

// This header mimics ext/alloc_traits.h in libstdc++.

#ifndef TYPEDEF_CHAIN_IN_TEMPLATE_I1_H_
#define TYPEDEF_CHAIN_IN_TEMPLATE_I1_H_

template<typename T>
struct TypedefWrapper {
typedef T value_type;
typedef value_type& reference;
};

#endif // TYPEDEF_CHAIN_IN_TEMPLATE_I1_H_
15 changes: 15 additions & 0 deletions tests/cxx/typedef_chain_in_template-i2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//===--- typedef_chain_in_template-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.
//
//===----------------------------------------------------------------------===//

class TypedefChainClass;

using NonProvidingAlias = TypedefChainClass;

template <int>
using NonProvidingAliasTpl = TypedefChainClass;
21 changes: 21 additions & 0 deletions tests/cxx/typedef_chain_in_template.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "tests/cxx/typedef_chain_in_template-d2.h"
#include "tests/cxx/typedef_chain_in_template-d3.h"
#include "tests/cxx/typedef_chain_in_template-d4.h"
#include "tests/cxx/typedef_chain_in_template-d5.h"

void UsageAsWithLibstdcpp() {
// IWYU: TypedefChainClass needs a declaration
Expand Down Expand Up @@ -56,6 +57,25 @@ void UsageWithLongerTypedefChain() {
c.GetContent2().Method();
}

void Fn() {
// IWYU: TypedefChainClass needs a declaration
// IWYU: TypedefChainClass is...*typedef_chain_class.h
IdentityStructComplex<TypedefChainClass>::Type isc;
// IWYU: TypedefChainClass is...*typedef_chain_class.h
isc.Method();

// IWYU: TypedefChainClass needs a declaration
// IWYU: TypedefChainClass is...*typedef_chain_class.h
IdentityAliasComplex<TypedefChainClass> iac;
// IWYU: TypedefChainClass is...*typedef_chain_class.h
iac.Method();

// IWYU: TypedefChainClass is...*typedef_chain_class.h
(void)sizeof(TplWithNonProvidedAliased1);
// IWYU: TypedefChainClass is...*typedef_chain_class.h
(void)sizeof(TplWithNonProvidedAliased2);
}

/**** IWYU_SUMMARY
tests/cxx/typedef_chain_in_template.cc should add these lines:
Expand All @@ -69,5 +89,6 @@ The full include-list for tests/cxx/typedef_chain_in_template.cc:
#include "tests/cxx/typedef_chain_in_template-d2.h" // for ContainerAsLibcpp
#include "tests/cxx/typedef_chain_in_template-d3.h" // for ContainerShortTypedefChain
#include "tests/cxx/typedef_chain_in_template-d4.h" // for ContainerLongTypedefChain
#include "tests/cxx/typedef_chain_in_template-d5.h" // for IdentityAliasComplex, IdentityStructComplex, TplWithNonProvidedAliased1, TplWithNonProvidedAliased2
***** IWYU_SUMMARY */
7 changes: 7 additions & 0 deletions tests/cxx/typedef_chain_no_follow-d4.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ template <typename T>
using IdentityAlias = T;

using ProvidingWithAliasTpl = IdentityAlias<TypedefChainClass>;

template <typename T>
struct IdentityStruct {
using Type = T;
};

using ProvidingWithStructTpl = IdentityStruct<TypedefChainClass>::Type;
5 changes: 4 additions & 1 deletion tests/cxx/typedef_chain_no_follow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ void TypedefDeclaredInGlobalNamespace() {

ProvidingWithAliasTpl pwat;
pwat.Method();

ProvidingWithStructTpl pwst;
pwst.Method();
}

// Tests how we handle a typedef declared in a class. Main purpose is to make
Expand Down Expand Up @@ -54,6 +57,6 @@ The full include-list for tests/cxx/typedef_chain_no_follow.cc:
#include "tests/cxx/typedef_chain_no_follow-d1.h" // for TypedefChainTypedef
#include "tests/cxx/typedef_chain_no_follow-d2.h" // for NonContainer1
#include "tests/cxx/typedef_chain_no_follow-d3.h" // for NonContainer2
#include "tests/cxx/typedef_chain_no_follow-d4.h" // for ProvidingWithAliasTpl
#include "tests/cxx/typedef_chain_no_follow-d4.h" // for ProvidingWithAliasTpl, ProvidingWithStructTpl
***** IWYU_SUMMARY */

0 comments on commit 1f53a15

Please sign in to comment.