llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang <details> <summary>Changes</summary> …ation When `clang::TypeName::getFullyQualifiedType`/`clang::TypeName::getFullyQualifiedName` encounter a non-dependent type/type alias that is defined under a templated class/struct, it qualifies the type/type alias under a specialization of the templated class, if any was declared. That is, in: ``` template<typename T> class Foo { using Bar = T; } using Baz = Foo<int>; ``` Usages of `Foo::Bar` will be qualified as `Foo<int>::Bar`. When the `using Baz = Foo<int>;` line is removed, as there are would be no specialization encountered in the translation unit, usages of `Foo::Bar` would instead be qualified as `Foo<T>::Bar`. When multiple specializations are present, the one that is chosen is the first one that is encountered; due to the current implementation of the behavior and the fact that iterating the specialization of a `ClassTemplateDecl` respects the order in which the specializations were stored in. That is, if we were to add a reference to some other specialization in the above example, so that it would be parsed before the current `using Baz = Foo<int>;`, say: ``` template<typename T> class Foo { using Bar = T; } using Bat = Foo<double>; using Baz = Foo<int>; ``` Then usages of `Foo::Bar` would be qualified as `Foo<double>::Bar` instead of `Foo<int>::Bar`. Should the same declaration be added, instead, after the `using Baz = Foo<int>;` line, then the qualification would remain consistent with our previous version. To provide a more consistent behavior, that avoids changing the output when relatively unrelated declarations are present in the translation unit, `clang::TypeName::getFullyQualifiedType`/`clang::TypeName::getFullyQualifiedName` will now qualify such types using the original templated declaration instead of one of the specializations. --- Full diff: https://github.com/llvm/llvm-project/pull/67566.diff 2 Files Affected: - (modified) clang/lib/AST/QualTypeNames.cpp (-21) - (modified) clang/unittests/Tooling/QualTypeNamesTest.cpp (+40-43) ``````````diff diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 7557336f0aafa88..32fba2ab887d27c 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -272,27 +272,6 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( const auto *Outer = dyn_cast_or_null<NamedDecl>(DC); const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC); if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { - if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) { - if (ClassTemplateDecl *ClassTempl = - CxxDecl->getDescribedClassTemplate()) { - // We are in the case of a type(def) that was declared in a - // class template but is *not* type dependent. In clang, it - // gets attached to the class template declaration rather than - // any specific class template instantiation. This result in - // 'odd' fully qualified typename: - // - // vector<_Tp,_Alloc>::size_type - // - // Make the situation is 'useable' but looking a bit odd by - // picking a random instance as the declaring context. - if (ClassTempl->spec_begin() != ClassTempl->spec_end()) { - Decl = *(ClassTempl->spec_begin()); - Outer = dyn_cast<NamedDecl>(Decl); - OuterNS = dyn_cast<NamespaceDecl>(Decl); - } - } - } - if (OuterNS) { return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix); } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) { diff --git a/clang/unittests/Tooling/QualTypeNamesTest.cpp b/clang/unittests/Tooling/QualTypeNamesTest.cpp index 686d189cf69eb2f..18286f9e74921dd 100644 --- a/clang/unittests/Tooling/QualTypeNamesTest.cpp +++ b/clang/unittests/Tooling/QualTypeNamesTest.cpp @@ -85,7 +85,7 @@ TEST(QualTypeNameTest, Simple) { // Namespace alias Visitor.ExpectedQualTypeNames["CheckL"] = "A::B::C::MyInt"; Visitor.ExpectedQualTypeNames["non_dependent_type_var"] = - "Foo<X>::non_dependent_type"; + "Foo<T>::non_dependent_type"; Visitor.ExpectedQualTypeNames["AnEnumVar"] = "EnumScopeClass::AnEnum"; Visitor.ExpectedQualTypeNames["AliasTypeVal"] = "A::B::C::InnerAlias<int>"; Visitor.ExpectedQualTypeNames["AliasInnerTypeVal"] = @@ -175,20 +175,19 @@ TEST(QualTypeNameTest, Simple) { TEST(QualTypeNameTest, Complex) { TypeNameVisitor Complex; Complex.ExpectedQualTypeNames["CheckTX"] = "B::TX"; - Complex.runOver( - "namespace A {" - " struct X {};" - "}" - "using A::X;" - "namespace fake_std {" - " template<class... Types > class tuple {};" - "}" - "namespace B {" - " using fake_std::tuple;" - " typedef tuple<X> TX;" - " TX CheckTX;" - " struct A { typedef int X; };" - "}"); + Complex.runOver("namespace A {" + " struct X {};" + "}" + "using A::X;" + "namespace fake_std {" + " template<class... Types > class tuple {};" + "}" + "namespace B {" + " using fake_std::tuple;" + " typedef tuple<X> TX;" + " TX CheckTX;" + " struct A { typedef int X; };" + "}"); } TEST(QualTypeNameTest, DoubleUsing) { @@ -223,33 +222,31 @@ TEST(QualTypeNameTest, GlobalNsPrefix) { GlobalNsPrefix.ExpectedQualTypeNames["GlobalZVal"] = "::Z"; GlobalNsPrefix.ExpectedQualTypeNames["CheckK"] = "D::aStruct"; GlobalNsPrefix.ExpectedQualTypeNames["YZMPtr"] = "::A::B::X ::A::B::Y::Z::*"; - GlobalNsPrefix.runOver( - "namespace A {\n" - " namespace B {\n" - " int IntVal;\n" - " bool BoolVal;\n" - " struct X {};\n" - " X XVal;\n" - " template <typename T> class CCC { };\n" - " template <typename T>\n" - " using Alias = CCC<T>;\n" - " Alias<int> IntAliasVal;\n" - " struct Y { struct Z { X YZIPtr; }; };\n" - " Y::Z ZVal;\n" - " X Y::Z::*YZMPtr;\n" - " }\n" - "}\n" - "struct Z {};\n" - "Z GlobalZVal;\n" - "namespace {\n" - " namespace D {\n" - " namespace {\n" - " class aStruct {};\n" - " aStruct CheckK;\n" - " }\n" - " }\n" - "}\n" - ); + GlobalNsPrefix.runOver("namespace A {\n" + " namespace B {\n" + " int IntVal;\n" + " bool BoolVal;\n" + " struct X {};\n" + " X XVal;\n" + " template <typename T> class CCC { };\n" + " template <typename T>\n" + " using Alias = CCC<T>;\n" + " Alias<int> IntAliasVal;\n" + " struct Y { struct Z { X YZIPtr; }; };\n" + " Y::Z ZVal;\n" + " X Y::Z::*YZMPtr;\n" + " }\n" + "}\n" + "struct Z {};\n" + "Z GlobalZVal;\n" + "namespace {\n" + " namespace D {\n" + " namespace {\n" + " class aStruct {};\n" + " aStruct CheckK;\n" + " }\n" + " }\n" + "}\n"); } TEST(QualTypeNameTest, InlineNamespace) { @@ -297,4 +294,4 @@ TEST(QualTypeNameTest, ConstUsing) { using ::A::S; void foo(const S& param1, const S param2);)"); } -} // end anonymous namespace +} // end anonymous namespace `````````` </details> https://github.com/llvm/llvm-project/pull/67566 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits