diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index ee7fec3372fcf..a2f930911bfe5 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -58,9 +58,9 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, NestedNameSpecifier NNS = std::nullopt; TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); - // ArgTDecl won't be NULL because we asserted that this isn't a - // dependent context very early in the call chain. - assert(ArgTDecl != nullptr); + if (!ArgTDecl) // ArgTDecl can be null in dependent contexts. + return false; + QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName(); if (QTName && @@ -252,6 +252,9 @@ createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl, bool WithGlobalNsPrefix) { assert(Decl); + // Some declaration cannot be qualified. + if (Decl->isTemplateParameter()) + return std::nullopt; const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); const auto *Outer = dyn_cast(DC); const auto *OuterNS = dyn_cast(DC); diff --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt index f27d34e8a0719..3a12a4a06a33a 100644 --- a/clang/unittests/AST/CMakeLists.txt +++ b/clang/unittests/AST/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_unittest(ASTTests ExternalASTSourceTest.cpp NamedDeclPrinterTest.cpp ProfilingTest.cpp + QualTypeNamesTest.cpp RandstructTest.cpp RawCommentForDeclTest.cpp RecursiveASTVisitorTest.cpp diff --git a/clang/unittests/AST/QualTypeNamesTest.cpp b/clang/unittests/AST/QualTypeNamesTest.cpp new file mode 100644 index 0000000000000..5b88391c84d08 --- /dev/null +++ b/clang/unittests/AST/QualTypeNamesTest.cpp @@ -0,0 +1,56 @@ +//===- unittests/AST/QualTypeNamesTest.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains tests for helpers from QualTypeNames.h. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/QualTypeNames.h" +#include "ASTPrint.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/TypeBase.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "gtest/gtest.h" + +namespace clang { +namespace { + +TEST(QualTypeNamesTest, TemplateParameters) { + constexpr llvm::StringLiteral Code = R"cpp( + template class T> struct Foo { + using type_of_interest = T; + }; + )cpp"; + auto AST = tooling::buildASTFromCode(Code); + ASSERT_NE(AST, nullptr); + + auto &Ctx = AST->getASTContext(); + auto FooLR = Ctx.getTranslationUnitDecl()->lookup( + DeclarationName(AST->getPreprocessor().getIdentifierInfo("Foo"))); + ASSERT_TRUE(FooLR.isSingleResult()); + + auto TypeLR = + llvm::cast(FooLR.front()) + ->getTemplatedDecl() + ->lookup(DeclarationName( + AST->getPreprocessor().getIdentifierInfo("type_of_interest"))); + ASSERT_TRUE(TypeLR.isSingleResult()); + + auto Type = cast(TypeLR.front())->getUnderlyingType(); + ASSERT_TRUE(isa(Type)); + + EXPECT_EQ(TypeName::getFullyQualifiedName(Type, Ctx, Ctx.getPrintingPolicy()), + "T"); +} + +} // namespace +} // namespace clang