diff --git a/clang_delta/Makefile.am b/clang_delta/Makefile.am index 9e27f9fa..6e0cb497 100644 --- a/clang_delta/Makefile.am +++ b/clang_delta/Makefile.am @@ -419,6 +419,7 @@ EXTRA_DIST = \ tests/rename-fun/test1.h \ tests/rename-param/invalid.c \ tests/rename-var/rename-var.c \ + tests/replace-dependent-typedef/test2.cc \ tests/replace-derived-class/replace-derived1.cpp \ tests/replace-derived-class/replace-derived2.cpp \ tests/replace-derived-class/replace-derived3.cpp \ diff --git a/clang_delta/Makefile.in b/clang_delta/Makefile.in index ffad0f28..db9b308f 100644 --- a/clang_delta/Makefile.in +++ b/clang_delta/Makefile.in @@ -866,6 +866,7 @@ EXTRA_DIST = \ tests/rename-fun/test1.h \ tests/rename-param/invalid.c \ tests/rename-var/rename-var.c \ + tests/replace-dependent-typedef/test2.cc \ tests/replace-derived-class/replace-derived1.cpp \ tests/replace-derived-class/replace-derived2.cpp \ tests/replace-derived-class/replace-derived3.cpp \ diff --git a/clang_delta/ReplaceDependentTypedef.cpp b/clang_delta/ReplaceDependentTypedef.cpp index 148998ea..429685ad 100644 --- a/clang_delta/ReplaceDependentTypedef.cpp +++ b/clang_delta/ReplaceDependentTypedef.cpp @@ -45,6 +45,53 @@ It also tries to reduce the typedef chain, e.g. \n\ static RegisterTransformation Trans("replace-dependent-typedef", DescriptionMsg); +namespace { + +bool DependsOnTypedef(const Type &Ty) { + switch (Ty.getTypeClass()) { + case Type::SubstTemplateTypeParm: { + const SubstTemplateTypeParmType *TP = + dyn_cast(&Ty); + const Type *ReplTy = TP->getReplacementType().getTypePtr(); + return DependsOnTypedef(*ReplTy); + } + + case Type::Elaborated: { + const ElaboratedType *ETy = dyn_cast(&Ty); + const Type *NamedTy = ETy->getNamedType().getTypePtr(); + return DependsOnTypedef(*NamedTy); + } + + case Type::Typedef: { + return true; + } + + case Type::DependentName: { + const DependentNameType *DNT = dyn_cast(&Ty); + const NestedNameSpecifier *Specifier = DNT->getQualifier(); + if (!Specifier) + return false; + const Type *NestedTy = Specifier->getAsType(); + if (!NestedTy) + return false; + return DependsOnTypedef(*NestedTy); + } + + case Type::Record: + case Type::Builtin: { // fall-through + return false; + } + + default: + return false; + } + + TransAssert(0 && "Unreachable code!"); + return false; +} + +} // namespace + class ReplaceDependentTypedefCollectionVisitor : public RecursiveASTVisitor { @@ -137,6 +184,8 @@ void ReplaceDependentTypedef::handleOneTypedefDecl(const TypedefDecl *D) if (!isValidType(D->getUnderlyingType())) return; + if (!DependsOnTypedef(*D->getUnderlyingType())) + return; std::string Str = ""; bool Typename = false; diff --git a/clang_delta/tests/replace-dependent-typedef/test2.cc b/clang_delta/tests/replace-dependent-typedef/test2.cc new file mode 100644 index 00000000..27084aa4 --- /dev/null +++ b/clang_delta/tests/replace-dependent-typedef/test2.cc @@ -0,0 +1,25 @@ +// RUN: %clang_delta --query-instances=replace-dependent-typedef %s 2>&1 | %remove_lit_checks | FileCheck %s --check-prefix=CHECK-CNT +// RUN: %clang_delta --transformation=replace-dependent-typedef --counter=1 %s 2>&1 | %remove_lit_checks | FileCheck %s --check-prefix=CHECK-1 + +template +struct A { + struct Inner; + // This shouldn't be treated as an instance: + typedef A::Inner Foo; +}; + +template struct S { typedef T type; }; + +struct B { + struct Inner; +}; + +template +struct C { + typedef typename S::type::Inner Bar; +}; + +// CHECK-1: typedef B::Inner D; +typedef C::Bar D; + +// CHECK-CNT: Available transformation instances: 1