diff --git a/clang_delta/CMakeLists.txt b/clang_delta/CMakeLists.txt index 911cd9289..e9af33cb1 100644 --- a/clang_delta/CMakeLists.txt +++ b/clang_delta/CMakeLists.txt @@ -353,6 +353,8 @@ set(SOURCE_FILES "/tests/replace-dependent-typedef/test1.output" "/tests/replace-dependent-typedef/test1.output2" "/tests/replace-dependent-typedef/test1.output3" + "/tests/replace-dependent-typedef/test2.cc" + "/tests/replace-dependent-typedef/test2.output" "/tests/replace-derived-class/replace-derived1.cpp" "/tests/replace-derived-class/replace-derived1.output" "/tests/replace-derived-class/replace-derived2.cpp" diff --git a/clang_delta/ReplaceDependentTypedef.cpp b/clang_delta/ReplaceDependentTypedef.cpp index 6790656cc..14f7d3903 100644 --- a/clang_delta/ReplaceDependentTypedef.cpp +++ b/clang_delta/ReplaceDependentTypedef.cpp @@ -45,11 +45,54 @@ It also tries to reduce the typedef chain, e.g. \n\ static RegisterTransformation Trans("replace-dependent-typedef", DescriptionMsg); +static 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; +} + class ReplaceDependentTypedefCollectionVisitor : public RecursiveASTVisitor { public: - explicit + explicit ReplaceDependentTypedefCollectionVisitor(ReplaceDependentTypedef *Instance) : ConsumerInstance(Instance) { } @@ -61,14 +104,14 @@ class ReplaceDependentTypedefCollectionVisitor : public }; -bool +bool ReplaceDependentTypedefCollectionVisitor::VisitTypedefNameDecl(TypedefNameDecl *D) { ConsumerInstance->handleOneTypedefDecl(D); return true; } -void ReplaceDependentTypedef::Initialize(ASTContext &context) +void ReplaceDependentTypedef::Initialize(ASTContext &context) { Transformation::Initialize(context); CollectionVisitor = new ReplaceDependentTypedefCollectionVisitor(this); @@ -121,7 +164,7 @@ bool ReplaceDependentTypedef::isValidType(const QualType &QT) return ((Keyword == ETK_Typename) || (Keyword == ETK_None)); #endif } - + default: return false; } @@ -137,6 +180,8 @@ void ReplaceDependentTypedef::handleOneTypedefDecl(const TypedefNameDecl *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 000000000..7eeb61417 --- /dev/null +++ b/clang_delta/tests/replace-dependent-typedef/test2.cc @@ -0,0 +1,19 @@ +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; +}; + +typedef C::Bar D; diff --git a/clang_delta/tests/replace-dependent-typedef/test2.output b/clang_delta/tests/replace-dependent-typedef/test2.output new file mode 100644 index 000000000..ac0ac993a --- /dev/null +++ b/clang_delta/tests/replace-dependent-typedef/test2.output @@ -0,0 +1,19 @@ +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; +}; + +typedef B::Inner D; diff --git a/clang_delta/tests/test_clang_delta.py b/clang_delta/tests/test_clang_delta.py index 621af6370..a2f13c551 100644 --- a/clang_delta/tests/test_clang_delta.py +++ b/clang_delta/tests/test_clang_delta.py @@ -1069,6 +1069,17 @@ def test_replace_derived_class_replace_dependent_typedef_1_3(self): 'replace-dependent-typedef/test1.output3', ) + def test_replace_derived_class_replace_dependent_typedef_2(self): + self.check_query_instances( + 'replace-dependent-typedef/test2.cc', + '--query-instances=replace-dependent-typedef', + 'Available transformation instances: 1', + ) + self.check_clang_delta( + 'replace-dependent-typedef/test2.cc', + '--transformation=replace-dependent-typedef --counter=1', + ) + def test_replace_derived_class_replace_derived1(self): self.check_clang_delta( 'replace-derived-class/replace-derived1.cpp',