[clang] [clang-tools-extra] [lldb] [clang][AST][NFC] Tree-wide removal of deprecated `getQualifiedNameAsString()` (PR #218264)

Shengxin Pei via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 23 11:10:15 PDT 2026


https://github.com/TPPPP72 updated https://github.com/llvm/llvm-project/pull/218264

>From a7af431dab348433d63a05fc8af98554ea706798 Mon Sep 17 00:00:00 2001
From: Shengxin Pei <TPPPP72 at outlook.com>
Date: Mon, 24 Aug 2026 02:09:55 +0800
Subject: [PATCH] [clang][AST][NFC] Tree-wide removal of deprecated
 getQualifiedNameAsString()

---
 .../ChangeNamespace.cpp                       | 107 ++++++++++++++----
 clang-tools-extra/clang-doc/Serialize.cpp     |  82 +++++++++-----
 clang-tools-extra/clang-move/Move.cpp         |   7 +-
 .../CapturingThisInMemberVariableCheck.cpp    |   4 +-
 .../bugprone/DanglingHandleCheck.cpp          |   2 +-
 .../DerivedMethodShadowingBaseMethodCheck.cpp |   2 +-
 .../bugprone/StandaloneEmptyCheck.cpp         |   4 +-
 .../bugprone/VirtualNearMissCheck.cpp         |   3 +-
 .../fuchsia/TemporaryObjectsCheck.cpp         |   8 +-
 .../clang-tidy/modernize/AvoidBindCheck.cpp   |   7 +-
 .../clang-tidy/modernize/LoopConvertCheck.cpp |  18 +--
 .../MinMaxUseInitializerListCheck.cpp         |  13 ++-
 .../clang-tidy/modernize/UseAutoCheck.cpp     |  16 ++-
 .../clang-tidy/modernize/UseEmplaceCheck.cpp  |  17 ++-
 .../readability/EnumInitialValueCheck.cpp     |   5 +-
 .../readability/NamedParameterCheck.cpp       |  21 +++-
 clang-tools-extra/clang-tidy/utils/Matchers.h |  21 +++-
 clang-tools-extra/clangd/refactor/Rename.cpp  |  11 +-
 .../clangd/refactor/tweaks/DefineOutline.cpp  |  22 ++--
 .../unittests/HeaderSourceSwitchTests.cpp     |  10 +-
 .../clangd/unittests/IncludeCleanerTests.cpp  |  12 +-
 .../clangd/unittests/QualityTests.cpp         |  36 ++++--
 .../clangd/unittests/XRefsTests.cpp           |  10 +-
 .../include-cleaner/lib/Types.cpp             |  15 ++-
 clang/include/clang/AST/Decl.h                |   3 -
 clang/include/clang/AST/StmtDataCollectors.td |  22 ++--
 clang/include/clang/ASTMatchers/ASTMatchers.h |   8 +-
 .../Analysis/Analyses/ThreadSafetyTraverse.h  |   4 +-
 .../StaticAnalyzer/Checkers/SValExplainer.h   |  76 ++++++++-----
 clang/lib/AST/ASTDiagnostic.cpp               |  24 +++-
 clang/lib/AST/ByteCode/Function.h             |   6 +-
 clang/lib/AST/Decl.cpp                        |  28 +++--
 clang/lib/AST/DeclPrinter.cpp                 |   4 +-
 clang/lib/AST/VTableBuilder.cpp               |  17 ++-
 clang/lib/Analysis/AnalysisDeclContext.cpp    |   4 +-
 clang/lib/Analysis/CFG.cpp                    |   4 +-
 clang/lib/Analysis/IssueHash.cpp              |  38 ++++---
 clang/lib/Analysis/LifetimeSafety/Facts.cpp   |   7 +-
 .../LifetimeSafety/LifetimeSafety.cpp         |  27 +++--
 clang/lib/Analysis/ProgramPoint.cpp           |  17 +--
 clang/lib/CodeGen/CGClass.cpp                 |  25 +++-
 clang/lib/CodeGen/CGOpenMPRuntime.cpp         |  14 ++-
 clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp |   9 +-
 clang/lib/Frontend/ASTConsumers.cpp           |   8 +-
 .../Interpreter/InterpreterValuePrinter.cpp   |   9 +-
 clang/lib/Parse/ParseDeclCXX.cpp              |  22 ++--
 clang/lib/Sema/AnalysisBasedWarnings.cpp      |  13 +--
 clang/lib/Sema/SemaAccess.cpp                 |   3 +-
 clang/lib/Sema/SemaBoundsSafety.cpp           |  14 +--
 clang/lib/Sema/SemaChecking.cpp               |  14 ++-
 clang/lib/Sema/SemaExpr.cpp                   |   3 +-
 clang/lib/Sema/SemaOverload.cpp               |  13 ++-
 clang/lib/Sema/SemaTemplate.cpp               |  10 +-
 .../Checkers/AnalysisOrderChecker.cpp         |  22 +++-
 .../StaticAnalyzer/Checkers/MallocChecker.cpp |  15 ++-
 .../StaticAnalyzer/Checkers/MoveChecker.cpp   |  24 ++--
 .../Checkers/NoOwnershipChangeVisitor.cpp     |   8 +-
 .../RetainCountDiagnostics.cpp                |   8 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp   |  12 +-
 clang/lib/StaticAnalyzer/Core/SVals.cpp       |   2 +-
 .../Frontend/AnalysisConsumer.cpp             |  13 ++-
 clang/lib/Tooling/ASTDiff/ASTDiff.cpp         |  55 +++++----
 clang/lib/Tooling/Refactoring/Lookup.cpp      |  23 +++-
 .../Tooling/Refactoring/Rename/USRFinder.cpp  |  17 ++-
 clang/unittests/AST/ASTImporterTest.cpp       |   7 +-
 clang/unittests/AST/DeclTest.cpp              |  16 ---
 .../unittests/Frontend/FrontendActionTest.cpp |  10 +-
 clang/unittests/Index/IndexTests.cpp          |  12 +-
 .../unittests/Interpreter/InterpreterTest.cpp |  27 ++++-
 clang/unittests/Sema/CodeCompleteTest.cpp     |  15 ++-
 clang/unittests/Tooling/LookupTest.cpp        |  21 +++-
 clang/unittests/Tooling/QualTypeNamesTest.cpp |   7 +-
 ...ecursiveASTVisitorTestPostOrderVisitor.cpp |  24 +++-
 .../CXXMemberCall.cpp                         |   8 +-
 .../Clang/CxxModuleHandler.cpp                |  14 ++-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |   7 +-
 .../NativePDB/PdbAstBuilderClang.cpp          |  24 ++--
 .../Expression/ClangExpressionDeclMapTest.cpp |   9 +-
 .../unittests/Symbol/TestClangASTImporter.cpp |  68 +++++++++--
 79 files changed, 940 insertions(+), 427 deletions(-)

diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
index 471ca45fb5a53..0db8dbae4ff9d 100644
--- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
@@ -748,25 +748,45 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
     // Note that `FromDecl` must not be defined in the old namespace (according
     // to `DeclMatcher`), so its fully-qualified name will not change after
     // changing the namespace.
-    addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
+    SmallString<128> FromDeclNameBuf;
+    {
+      llvm::raw_svector_ostream OS(FromDeclNameBuf);
+      FromDecl->printQualifiedName(OS);
+    }
+    addReplacementOrDie(Start, End, FromDeclNameBuf.str(),
                         *Result.SourceManager, &FileToReplacements);
     return;
   }
   const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
+
   // Calculate the name of the `NsDecl` after it is moved to new namespace.
-  std::string OldNs = NsDecl->getQualifiedNameAsString();
-  llvm::StringRef Postfix = OldNs;
+  SmallString<128> OldNsBuf;
+  {
+    llvm::raw_svector_ostream OS(OldNsBuf);
+    NsDecl->printQualifiedName(OS);
+  }
+  llvm::StringRef Postfix = OldNsBuf.str();
   bool Consumed = Postfix.consume_front(OldNamespace);
   assert(Consumed && "Expect OldNS to start with OldNamespace.");
   (void)Consumed;
-  const std::string NewNs = (NewNamespace + Postfix).str();
+  SmallString<128> NewNsBuf;
+  {
+    llvm::raw_svector_ostream OS(NewNsBuf);
+    OS << NewNamespace << Postfix;
+  }
+  llvm::StringRef NewNs = NewNsBuf.str();
 
   llvm::StringRef NestedName = Lexer::getSourceText(
       CharSourceRange::getTokenRange(
           Result.SourceManager->getSpellingLoc(Start),
           Result.SourceManager->getSpellingLoc(End)),
       *Result.SourceManager, Result.Context->getLangOpts());
-  std::string FromDeclName = FromDecl->getQualifiedNameAsString();
+  SmallString<128> FromDeclNameBuf;
+  {
+    llvm::raw_svector_ostream OS(FromDeclNameBuf);
+    FromDecl->printQualifiedName(OS);
+  }
+  llvm::StringRef FromDeclName = FromDeclNameBuf.str();
   for (llvm::Regex &RE : AllowedSymbolRegexes)
     if (RE.match(FromDeclName))
       return;
@@ -778,9 +798,13 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
     if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
                                  Start))
       continue;
-    StringRef FromDeclNameRef = FromDeclName;
-    if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
-                                          ->getQualifiedNameAsString())) {
+    llvm::StringRef FromDeclNameRef = FromDeclName;
+    SmallString<128> NominatedNsBuf;
+    {
+      llvm::raw_svector_ostream OS(NominatedNsBuf);
+      UsingNamespace->getNominatedNamespace()->printQualifiedName(OS);
+    }
+    if (FromDeclNameRef.consume_front(NominatedNsBuf.str())) {
       FromDeclNameRef = FromDeclNameRef.drop_front(2);
       if (FromDeclNameRef.size() < ReplaceName.size())
         ReplaceName = std::string(FromDeclNameRef);
@@ -792,28 +816,41 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
     if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
                                  Start))
       continue;
-    StringRef FromDeclNameRef = FromDeclName;
-    if (FromDeclNameRef.consume_front(
-            NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
-            "::")) {
+    llvm::StringRef FromDeclNameRef = FromDeclName;
+    SmallString<128> AliasNsBuf;
+    {
+      llvm::raw_svector_ostream OS(AliasNsBuf);
+      NamespaceAlias->getNamespace()->printQualifiedName(OS);
+    }
+    AliasNsBuf.append("::");
+    if (FromDeclNameRef.consume_front(AliasNsBuf.str())) {
       std::string AliasName = NamespaceAlias->getNameAsString();
-      std::string AliasQualifiedName =
-          NamespaceAlias->getQualifiedNameAsString();
+      SmallString<128> AliasQualifiedNameBuf;
+      {
+        llvm::raw_svector_ostream OS(AliasQualifiedNameBuf);
+        NamespaceAlias->printQualifiedName(OS);
+      }
+      llvm::StringRef AliasQualifiedName = AliasQualifiedNameBuf.str();
       // We only consider namespace aliases define in the global namespace or
       // in namespaces that are directly visible from the reference, i.e.
       // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
       // but not visible in the new namespace is filtered out by
       // "IsVisibleInNewNs" matcher.
       if (AliasQualifiedName != AliasName) {
-        // The alias is defined in some namespace.
-        assert(StringRef(AliasQualifiedName).ends_with("::" + AliasName));
+        assert(AliasQualifiedName.ends_with(AliasName) &&
+               AliasQualifiedName.drop_back(AliasName.size()).ends_with("::"));
         llvm::StringRef AliasNs =
-            StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
-        if (!llvm::StringRef(OldNs).starts_with(AliasNs))
+            AliasQualifiedName.drop_back(AliasName.size() + 2);
+        if (!OldNsBuf.str().starts_with(AliasNs))
           continue;
       }
+      SmallString<128> NameWithAliasNamespaceBuf;
+      {
+        llvm::raw_svector_ostream OS(NameWithAliasNamespaceBuf);
+        OS << AliasName << "::" << FromDeclNameRef;
+      }
       std::string NameWithAliasNamespace =
-          (AliasName + "::" + FromDeclNameRef).str();
+          NameWithAliasNamespaceBuf.str().str();
       if (NameWithAliasNamespace.size() < ReplaceName.size())
         ReplaceName = NameWithAliasNamespace;
     }
@@ -827,8 +864,16 @@ void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
     if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
       for (const auto *UsingShadow : Using->shadows()) {
         const auto *TargetDecl = UsingShadow->getTargetDecl();
-        if (TargetDecl->getQualifiedNameAsString() ==
-            FromDecl->getQualifiedNameAsString()) {
+
+        SmallString<128> TargetDeclNameBuf, FromDeclNameCheckBuf;
+        {
+          llvm::raw_svector_ostream OS1(TargetDeclNameBuf);
+          TargetDecl->printQualifiedName(OS1);
+          llvm::raw_svector_ostream OS2(FromDeclNameCheckBuf);
+          FromDecl->printQualifiedName(OS2);
+        }
+
+        if (TargetDeclNameBuf.str() == FromDeclNameCheckBuf.str()) {
           ReplaceName = FromDecl->getNameAsString();
           Matched = true;
           break;
@@ -869,7 +914,12 @@ void ChangeNamespaceTool::fixTypeLoc(
   // `hasDeclaration` gives underlying declaration, but if the type is
   // a typedef type, we need to use the typedef type instead.
   auto IsInMovedNs = [&](const NamedDecl *D) {
-    if (!llvm::StringRef(D->getQualifiedNameAsString())
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      D->printQualifiedName(OS);
+    }
+    if (!llvm::StringRef(QualifiedNameBuf.str())
              .starts_with(OldNamespace + "::"))
       return false;
     auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
@@ -912,12 +962,19 @@ void ChangeNamespaceTool::fixUsingShadowDecl(
   // FIXME: it might not be always accurate to use the first using-decl.
   const NamedDecl *TargetDecl =
       UsingDeclaration->shadow_begin()->getTargetDecl();
-  std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
+
+  SmallString<128> ReplacementBuf;
+  {
+    llvm::raw_svector_ostream OS(ReplacementBuf);
+    OS << "using ::";
+    TargetDecl->printQualifiedName(OS);
+  }
+
   // FIXME: check if target_decl_name is in moved ns, which doesn't make much
   // sense. If this happens, we need to use name with the new namespace.
   // Use fully qualified name in UsingDecl for now.
-  addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
-                      *Result.SourceManager, &FileToReplacements);
+  addReplacementOrDie(Start, End, ReplacementBuf.str(), *Result.SourceManager,
+                      &FileToReplacements);
 }
 
 void ChangeNamespaceTool::fixDeclRefExpr(
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index e490ae1d08bfb..546bbec374aae 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -648,24 +648,36 @@ void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D) {
       const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
       LocalParents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
                                 InfoType::IT_record, B.getType().getAsString());
-    } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
-      LocalParents.emplace_back(
-          getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
-          P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
-    else
+    } else if (const RecordDecl *P = getRecordDeclForType(B.getType())) {
+      SmallString<128> QualifiedNameBuf;
+      {
+        llvm::raw_svector_ostream OS(QualifiedNameBuf);
+        P->printQualifiedName(OS);
+      }
+      LocalParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
+                                InfoType::IT_record, QualifiedNameBuf.str(),
+                                internString(getInfoRelativePath(P)));
+    } else {
       LocalParents.emplace_back(SymbolID(), B.getType().getAsString());
+    }
   }
   if (!LocalParents.empty())
     I.Parents = allocateArray<Reference>(LocalParents, getTransientArena());
 
   llvm::SmallVector<Reference, 4> LocalVirtualParents;
   for (const CXXBaseSpecifier &B : D->vbases()) {
-    if (const RecordDecl *P = getRecordDeclForType(B.getType()))
+    if (const RecordDecl *P = getRecordDeclForType(B.getType())) {
+      SmallString<128> QualifiedNameBuf;
+      {
+        llvm::raw_svector_ostream OS(QualifiedNameBuf);
+        P->printQualifiedName(OS);
+      }
       LocalVirtualParents.emplace_back(
           getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
-          P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
-    else
+          QualifiedNameBuf.str(), internString(getInfoRelativePath(P)));
+    } else {
       LocalVirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
+    }
   }
   if (!LocalVirtualParents.empty())
     I.VirtualParents =
@@ -678,27 +690,34 @@ void Serializer::populateParentNamespaces(
     bool &IsInAnonymousNamespace) {
   const DeclContext *DC = D->getDeclContext();
   do {
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      if (const auto *N = dyn_cast<NamedDecl>(DC))
+        N->printQualifiedName(OS);
+    }
+    llvm::StringRef QualifiedName = QualifiedNameBuf.str();
+
     if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
       std::string Namespace;
       if (N->isAnonymousNamespace()) {
         Namespace = "@nonymous_namespace";
         IsInAnonymousNamespace = true;
-      } else
+      } else {
         Namespace = N->getNameAsString();
+      }
       Namespaces.emplace_back(getUSRForDecl(N), Namespace,
-                              InfoType::IT_namespace,
-                              N->getQualifiedNameAsString());
-    } else if (const auto *N = dyn_cast<RecordDecl>(DC))
+                              InfoType::IT_namespace, QualifiedName);
+    } else if (const auto *N = dyn_cast<RecordDecl>(DC)) {
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_record,
-                              N->getQualifiedNameAsString());
-    else if (const auto *N = dyn_cast<FunctionDecl>(DC))
+                              InfoType::IT_record, QualifiedName);
+    } else if (const auto *N = dyn_cast<FunctionDecl>(DC)) {
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_function,
-                              N->getQualifiedNameAsString());
-    else if (const auto *N = dyn_cast<EnumDecl>(DC))
+                              InfoType::IT_function, QualifiedName);
+    } else if (const auto *N = dyn_cast<EnumDecl>(DC)) {
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_enum, N->getQualifiedNameAsString());
+                              InfoType::IT_enum, QualifiedName);
+    }
   } while ((DC = DC->getParent()));
   // The global namespace should be added to the list of namespaces if the decl
   // corresponds to a Record and if it doesn't have any namespace (because this
@@ -1064,10 +1083,15 @@ void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
                                         FuncDecl->getLangOpts());
     }
 
-    F.Ref =
-        Reference(getUSRForDecl(ActualDecl), ActualDecl->getNameAsString(),
-                  InfoType::IT_default, ActualDecl->getQualifiedNameAsString(),
-                  getInfoRelativePath(ActualDecl));
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      ActualDecl->printQualifiedName(OS);
+    }
+
+    F.Ref = Reference(getUSRForDecl(ActualDecl), ActualDecl->getNameAsString(),
+                      InfoType::IT_default, QualifiedNameBuf.str(),
+                      getInfoRelativePath(ActualDecl));
 
     populateMemberTypeInfo(F, ActualDecl);
     LocalFriends.push_back(std::move(F));
@@ -1195,9 +1219,15 @@ std::pair<Info *, Info *> Serializer::emitInfo(const CXXMethodDecl *D,
     Parent = D->getParent();
 
   SymbolID ParentUSR = getUSRForDecl(Parent);
-  Func->Parent =
-      Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record,
-                Parent->getQualifiedNameAsString()};
+
+  SmallString<128> QualifiedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(QualifiedNameBuf);
+    Parent->printQualifiedName(OS);
+  }
+
+  Func->Parent = Reference{ParentUSR, Parent->getNameAsString(),
+                           InfoType::IT_record, QualifiedNameBuf.str()};
   Func->Access = D->getAccess();
 
   // Info is wrapped in its parent scope so is returned in the second position.
diff --git a/clang-tools-extra/clang-move/Move.cpp b/clang-tools-extra/clang-move/Move.cpp
index 1f966b3119620..58801e7058b8c 100644
--- a/clang-tools-extra/clang-move/Move.cpp
+++ b/clang-tools-extra/clang-move/Move.cpp
@@ -882,7 +882,12 @@ void ClangMoveTool::onEndOfTranslationUnit() {
     for (const auto *Decl : UnremovedDeclsInOldHeader) {
       auto Kind = Decl->getKind();
       bool Templated = Decl->isTemplated();
-      const std::string QualifiedName = Decl->getQualifiedNameAsString();
+      SmallString<128> QualifiedNameBuf;
+      {
+        llvm::raw_svector_ostream OS(QualifiedNameBuf);
+        Decl->printQualifiedName(OS);
+      }
+      llvm::StringRef QualifiedName = QualifiedNameBuf.str();
       if (Kind == Decl::Kind::Var)
         Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
       else if (Kind == Decl::Kind::Function ||
diff --git a/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp
index a78af8aa2fea3..9b8ff04707b12 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/CapturingThisInMemberVariableCheck.cpp
@@ -133,7 +133,7 @@ void CapturingThisInMemberVariableCheck::check(
          "'this' captured by a '%0' call and stored in a class member "
          "variable; disable implicit class copying/moving to prevent potential "
          "use-after-free")
-        << Callee->getQualifiedNameAsString();
+        << Callee;
   }
 
   const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field");
@@ -142,7 +142,7 @@ void CapturingThisInMemberVariableCheck::check(
   diag(Field->getLocation(),
        "class member of type '%0' that stores captured 'this'",
        DiagnosticIDs::Note)
-      << Field->getType().getAsString();
+      << Field->getType();
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp
index c95ad2beed3a9..00d16a4b025e1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp
@@ -172,7 +172,7 @@ void DanglingHandleCheck::check(const MatchFinder::MatchResult &Result) {
   auto *Handle = Result.Nodes.getNodeAs<CXXRecordDecl>("handle");
   diag(Result.Nodes.getNodeAs<Stmt>("bad_stmt")->getBeginLoc(),
        "%0 outlives its value")
-      << Handle->getQualifiedNameAsString();
+      << Handle;
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/DerivedMethodShadowingBaseMethodCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DerivedMethodShadowingBaseMethodCheck.cpp
index 904685cb8416d..bb861bb810f81 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DerivedMethodShadowingBaseMethodCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DerivedMethodShadowingBaseMethodCheck.cpp
@@ -121,7 +121,7 @@ void DerivedMethodShadowingBaseMethodCheck::check(
 
   diag(ShadowingMethod->getBeginLoc(),
        "'%0' shadows method with the same name in class %1")
-      << ShadowingMethod->getQualifiedNameAsString() << BaseMethod->getParent();
+      << ShadowingMethod << BaseMethod->getParent();
   diag(BaseMethod->getBeginLoc(), "previous definition of %0 is here",
        DiagnosticIDs::Note)
       << ShadowingMethod;
diff --git a/clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.cpp
index 1d72f3e9f387b..4fcb8b84c7444 100644
--- a/clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.cpp
@@ -200,15 +200,13 @@ void StandaloneEmptyCheck::check(const MatchFinder::MatchResult &Result) {
         diag(NonMemberLoc,
              "ignoring the result of '%0'; did you mean 'clear()'?")
             << dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl())
-                   ->getQualifiedNameAsString()
             << FixItHint::CreateReplacement(ReplacementRange, ReplacementText);
         return;
       }
     }
 
     diag(NonMemberLoc, "ignoring the result of '%0'")
-        << dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl())
-               ->getQualifiedNameAsString();
+        << dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl());
   }
 }
 
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
index 07dc77b5dee0a..fa9d213f546ef 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
@@ -253,8 +253,7 @@ void VirtualNearMissCheck::check(const MatchFinder::MatchResult &Result) {
               diag(DerivedMD->getBeginLoc(),
                    "method '%0' has a similar name and the same signature as "
                    "virtual method '%1'; did you mean to override it?")
-              << DerivedMD->getQualifiedNameAsString()
-              << BaseMD->getQualifiedNameAsString();
+              << DerivedMD << BaseMD;
           if (ApplyFix)
             Diag << FixItHint::CreateReplacement(Range, BaseMD->getName());
         }
diff --git a/clang-tools-extra/clang-tidy/fuchsia/TemporaryObjectsCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/TemporaryObjectsCheck.cpp
index a29eda7289aa2..b0d9e4626e728 100644
--- a/clang-tools-extra/clang-tidy/fuchsia/TemporaryObjectsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/fuchsia/TemporaryObjectsCheck.cpp
@@ -20,8 +20,12 @@ namespace clang::tidy::fuchsia {
 namespace {
 
 AST_MATCHER_P(CXXRecordDecl, matchesAnyName, ArrayRef<StringRef>, Names) {
-  const std::string QualifiedName = Node.getQualifiedNameAsString();
-  return llvm::is_contained(Names, QualifiedName);
+  SmallString<128> QualifiedName;
+  {
+    llvm::raw_svector_ostream OS(QualifiedName);
+    Node.printQualifiedName(OS);
+  }
+  return llvm::is_contained(Names, QualifiedName.str());
 }
 
 } // namespace
diff --git a/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp b/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp
index 3cf0173aaa002..f3c309a1c5a00 100644
--- a/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp
@@ -147,7 +147,12 @@ static bool isCallExprNamed(const Expr *E, StringRef Name) {
   const auto *ND = dyn_cast<NamedDecl>(CE->getCalleeDecl());
   if (!ND)
     return false;
-  return ND->getQualifiedNameAsString() == Name;
+  SmallString<128> QName;
+  {
+    llvm::raw_svector_ostream OS(QName);
+    ND->printQualifiedName(OS);
+  }
+  return QName.str() == Name;
 }
 
 static void
diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
index 75bf2a7325900..a25ab6b7f19a1 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -382,21 +382,25 @@ static std::optional<ContainerCall> getContainerExpr(const Expr *Call) {
     if (TheCall->getNumArgs() != 1)
       return std::nullopt;
 
+    const FunctionDecl *Callee = TheCall->getDirectCallee();
+    if (!Callee)
+      return std::nullopt;
+
     if (TheCall->usesADL()) {
-      if (TheCall->getDirectCallee() == nullptr ||
-          !ADLNames.contains(TheCall->getDirectCallee()->getName()))
+      if (!ADLNames.contains(Callee->getName()))
         return std::nullopt;
       CallKind = IteratorCallKind::ICK_ADL;
     } else {
-      if (!StdNames.contains(
-              TheCall->getDirectCallee()->getQualifiedNameAsString()))
+      SmallString<128> QName;
+      {
+        llvm::raw_svector_ostream OS(QName);
+        Callee->printQualifiedName(OS);
+      }
+      if (!StdNames.contains(QName.str()))
         return std::nullopt;
       CallKind = IteratorCallKind::ICK_Std;
     }
 
-    if (TheCall->getDirectCallee() == nullptr)
-      return std::nullopt;
-
     return ContainerCall{TheCall->getArg(0),
                          TheCall->getDirectCallee()->getName(), false,
                          CallKind};
diff --git a/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp
index 55f0886d12dee..a3b2e7c473ad2 100644
--- a/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp
@@ -133,9 +133,16 @@ generateReplacements(const MatchFinder::MatchResult &Match,
       continue;
     }
 
-    // if the nested call is not the same as the top call
-    if (InnerCall->getDirectCallee()->getQualifiedNameAsString() !=
-        TopCall->getDirectCallee()->getQualifiedNameAsString())
+    SmallString<128> InnerName, TopName;
+    {
+      llvm::raw_svector_ostream InnerOS(InnerName);
+      InnerCall->getDirectCallee()->printQualifiedName(InnerOS);
+
+      llvm::raw_svector_ostream TopOS(TopName);
+      TopCall->getDirectCallee()->printQualifiedName(TopOS);
+    }
+
+    if (InnerName.str() != TopName.str())
       continue;
 
     const FindArgsResult InnerResult = findArgs(InnerCall);
diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
index 6c873e3f80004..8d211b39b52f6 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
@@ -432,11 +432,17 @@ void UseAutoCheck::replaceExpr(
   const StringRef Auto = ShouldReplenishVariableName
                              ? (RemoveStars ? "auto " : "auto *")
                              : (RemoveStars ? "auto " : "auto");
-  const std::string ReplenishedVariableName =
-      ShouldReplenishVariableName ? FirstDecl->getQualifiedNameAsString() : "";
-  const std::string Replacement =
-      (Auto + StringRef{ReplenishedVariableName}).str();
-  Diag << FixItHint::CreateReplacement(Range, Replacement) << StarRemovals;
+
+  SmallString<128> Replacement;
+  {
+    llvm::raw_svector_ostream OS(Replacement);
+    OS << Auto;
+    if (ShouldReplenishVariableName)
+      FirstDecl->printQualifiedName(OS);
+  }
+
+  Diag << FixItHint::CreateReplacement(Range, Replacement.str())
+       << StarRemovals;
 }
 
 void UseAutoCheck::check(const MatchFinder::MatchResult &Result) {
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
index 8ec123fc476ff..bb685b6569498 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
@@ -23,20 +23,25 @@ AST_MATCHER_P(InitListExpr, initCountLeq, unsigned, N) {
 // containers.
 AST_MATCHER_P(NamedDecl, hasAnyNameIgnoringTemplates, std::vector<StringRef>,
               Names) {
-  const std::string FullName = "::" + Node.getQualifiedNameAsString();
+  SmallString<128> FullName;
+  {
+    llvm::raw_svector_ostream OS(FullName);
+    OS << "::";
+    Node.printQualifiedName(OS);
+  }
 
   // This loop removes template specifiers by only keeping characters not within
   // template brackets. We keep a depth count to handle nested templates. For
   // example, it'll transform a::b<c<d>>::e<f> to simply a::b::e.
-  std::string FullNameTrimmed;
+  SmallString<128> FullNameTrimmed;
   int Depth = 0;
-  for (const auto &Character : FullName)
-    if (Character == '<')
+  for (char C : FullName)
+    if (C == '<')
       ++Depth;
-    else if (Character == '>')
+    else if (C == '>')
       --Depth;
     else if (Depth == 0)
-      FullNameTrimmed.append(1, Character);
+      FullNameTrimmed.push_back(C);
 
   // This loop is taken from HasNameMatcher::matchesNodeFullSlow in
   // clang/lib/ASTMatchers/ASTMatchersInternal.cpp and checks whether
diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp
index 620c5bece4eba..2b97c813c72b9 100644
--- a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp
@@ -153,7 +153,10 @@ static std::string getName(const EnumDecl *Decl) {
   if (!Decl->getDeclName())
     return "<unnamed>";
 
-  return Decl->getQualifiedNameAsString();
+  SmallString<128> Name;
+  llvm::raw_svector_ostream OS(Name);
+  Decl->printQualifiedName(OS);
+  return std::string(Name.str());
 }
 
 EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name,
diff --git a/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp b/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp
index 07d1bbeccbc16..0195e174003ef 100644
--- a/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp
@@ -100,10 +100,15 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
       continue;
 
     // Skip gmock testing::Unused parameters.
-    if (const auto *Typedef = Parm->getType()->getAs<TypedefType>();
-        Typedef &&
-        Typedef->getDecl()->getQualifiedNameAsString() == "testing::Unused")
-      continue;
+    if (const auto *Typedef = Parm->getType()->getAs<TypedefType>()) {
+      SmallString<64> TypedefQName;
+      {
+        llvm::raw_svector_ostream OS(TypedefQName);
+        Typedef->getDecl()->printQualifiedName(OS);
+      }
+      if (TypedefQName.str() == "testing::Unused")
+        continue;
+    }
 
     // Skip std::nullptr_t.
     if (Parm->getType().getCanonicalType()->isNullPtrType())
@@ -113,8 +118,12 @@ void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
     // tag dispatch types).
     if (const auto *Record =
             Parm->getType().getCanonicalType()->getAsCXXRecordDecl()) {
-      const std::string QName = Record->getQualifiedNameAsString();
-      if (llvm::is_contained(IgnoredTypes, QName))
+      SmallString<128> QName;
+      {
+        llvm::raw_svector_ostream OS(QName);
+        Record->printQualifiedName(OS);
+      }
+      if (llvm::is_contained(IgnoredTypes, QName.str()))
         continue;
     }
 
diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h
index e04da47322623..2e37d03cb31f4 100644
--- a/clang-tools-extra/clang-tidy/utils/Matchers.h
+++ b/clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -107,10 +107,23 @@ class MatchesAnyListedRegexNameMatcher
 
     bool match(const NamedDecl &ND) const {
       switch (Mode) {
-      case MatchMode::MatchQualified:
-        return Regex.match(ND.getQualifiedNameAsString());
-      case MatchMode::MatchFullyQualified:
-        return Regex.match("::" + ND.getQualifiedNameAsString());
+      case MatchMode::MatchQualified: {
+        SmallString<128> QName;
+        {
+          llvm::raw_svector_ostream OS(QName);
+          ND.printQualifiedName(OS);
+        }
+        return Regex.match(QName.str());
+      }
+      case MatchMode::MatchFullyQualified: {
+        SmallString<128> QName;
+        {
+          llvm::raw_svector_ostream OS(QName);
+          OS << "::";
+          ND.printQualifiedName(OS);
+        }
+        return Regex.match(QName.str());
+      }
       default:
         if (const IdentifierInfo *II = ND.getIdentifier())
           return Regex.match(II->getName());
diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp
index c56375b1a98d3..cccdc73b055ae 100644
--- a/clang-tools-extra/clangd/refactor/Rename.cpp
+++ b/clang-tools-extra/clangd/refactor/Rename.cpp
@@ -898,9 +898,14 @@ findOccurrencesOutsideFile(const NamedDecl &RenameDecl,
   if (AffectedFiles.size() >= MaxLimitFiles)
     return error("The number of affected files exceeds the max limit {0}",
                  MaxLimitFiles);
-  if (HasMore)
-    return error("The symbol {0} has too many occurrences",
-                 RenameDecl.getQualifiedNameAsString());
+  if (HasMore) {
+    SmallString<128> QName;
+    {
+      llvm::raw_svector_ostream OS(QName);
+      RenameDecl.printQualifiedName(OS);
+    }
+    return error("The symbol {0} has too many occurrences", QName.str());
+  }
   // Sort and deduplicate the results, in case that index returns duplications.
   for (auto &FileAndOccurrences : AffectedFiles) {
     auto &Ranges = FileAndOccurrences.getValue();
diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
index dcc417b5f7d8c..613e0d2cb039c 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -84,13 +84,14 @@ findContextForNS(llvm::StringRef TargetNS, const DeclContext *CurContext) {
   }
   // Otherwise we need to drop any trailing namespaces from CurContext until
   // we reach TargetNS.
-  std::string TargetContextNS =
-      CurContext->isNamespace()
-          ? llvm::cast<NamespaceDecl>(CurContext)->getQualifiedNameAsString()
-          : "";
-  TargetContextNS.append("::");
+  SmallString<128> TargetContextNSBuf;
+  if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(CurContext)) {
+    llvm::raw_svector_ostream OS(TargetContextNSBuf);
+    NS->printQualifiedName(OS);
+  }
+  TargetContextNSBuf.append("::");
 
-  llvm::StringRef CurrentContextNS(TargetContextNS);
+  llvm::StringRef CurrentContextNS(TargetContextNSBuf.str());
   // If TargetNS is not a prefix of CurrentContext, there's no way to reach
   // it.
   if (!CurrentContextNS.starts_with(TargetNS))
@@ -600,8 +601,13 @@ class DefineOutline : public Tweak {
       Offset = P->Offset;
       EnclosingNamespace = P->EnclosingNamespace;
     } else {
-      auto Region = getEligiblePoints(
-          Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts());
+      SmallString<128> SourceQName;
+      {
+        llvm::raw_svector_ostream OS(SourceQName);
+        Source->printQualifiedName(OS);
+      }
+      auto Region = getEligiblePoints(Contents, SourceQName.str(),
+                                      Sel.AST->getLangOpts());
       assert(!Region.EligiblePoints.empty());
       EnclosingNamespaceName = Region.EnclosingNamespace;
       InsertionPos = Region.EligiblePoints.back();
diff --git a/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp b/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp
index 782e3aacba538..7a8e0dd1dc050 100644
--- a/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp
@@ -132,9 +132,15 @@ TEST(HeaderSourceSwitchTest, ModuleInterfaces) {
 }
 
 MATCHER_P(declNamed, Name, "") {
-  if (const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
-    if (ND->getQualifiedNameAsString() == Name)
+  if (const NamedDecl *ND = dyn_cast<NamedDecl>(arg)) {
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      ND->printQualifiedName(OS);
+    }
+    if (QualifiedNameBuf.str() == Name)
       return true;
+  }
   return false;
 }
 
diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
index 5b9db8af33f12..7b31ad46dcc89 100644
--- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -200,8 +200,16 @@ TEST(IncludeCleaner, ComputeMissingHeaders) {
   const NamedDecl *BDecl = nullptr;
   for (Decl *D : AST.getASTContext().getTranslationUnitDecl()->decls()) {
     const NamedDecl *CandidateDecl = llvm::dyn_cast<NamedDecl>(D);
-    std::string Name = CandidateDecl->getQualifiedNameAsString();
-    if (Name != "b")
+    if (!CandidateDecl)
+      continue;
+
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      CandidateDecl->printQualifiedName(OS);
+    }
+
+    if (QualifiedNameBuf.str() != "b")
       continue;
     BDecl = CandidateDecl;
   }
diff --git a/clang-tools-extra/clangd/unittests/QualityTests.cpp b/clang-tools-extra/clangd/unittests/QualityTests.cpp
index 879a1793128c0..20d3050270be4 100644
--- a/clang-tools-extra/clangd/unittests/QualityTests.cpp
+++ b/clang-tools-extra/clangd/unittests/QualityTests.cpp
@@ -144,10 +144,17 @@ TEST(QualityTests, SymbolRelevanceSignalExtraction) {
   auto ConstructShadowDeclCompletionResult = [&](const std::string DeclName) {
     auto *Shadow =
         *dyn_cast<UsingDecl>(&findDecl(AST, [&](const NamedDecl &ND) {
-           if (const UsingDecl *Using = dyn_cast<UsingDecl>(&ND))
-             if (Using->shadow_size() &&
-                 Using->getQualifiedNameAsString() == DeclName)
-               return true;
+           if (const UsingDecl *Using = dyn_cast<UsingDecl>(&ND)) {
+             if (Using->shadow_size()) {
+               SmallString<128> QualifiedNameBuf;
+               {
+                 llvm::raw_svector_ostream OS(QualifiedNameBuf);
+                 Using->printQualifiedName(OS);
+               }
+               if (QualifiedNameBuf.str() == DeclName)
+                 return true;
+             }
+           }
            return false;
          }))->shadow_begin();
     CodeCompletionResult Result(Shadow->getTargetDecl(), 42);
@@ -374,7 +381,12 @@ TEST(QualityTests, NoBoostForClassConstructor) {
   Cls.merge(CodeCompletionResult(Foo, /*Priority=*/0));
 
   const NamedDecl *CtorDecl = &findDecl(AST, [](const NamedDecl &ND) {
-    return (ND.getQualifiedNameAsString() == "Foo::Foo") &&
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      ND.printQualifiedName(OS);
+    }
+    return (QualifiedNameBuf.str() == "Foo::Foo") &&
            isa<CXXConstructorDecl>(&ND);
   });
   SymbolRelevanceSignals Ctor;
@@ -437,11 +449,21 @@ TEST(QualityTests, ConstructorDestructor) {
   auto AST = Header.build();
 
   const NamedDecl *CtorDecl = &findDecl(AST, [](const NamedDecl &ND) {
-    return (ND.getQualifiedNameAsString() == "Foo::Foo") &&
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      ND.printQualifiedName(OS);
+    }
+    return (QualifiedNameBuf.str() == "Foo::Foo") &&
            isa<CXXConstructorDecl>(&ND);
   });
   const NamedDecl *DtorDecl = &findDecl(AST, [](const NamedDecl &ND) {
-    return (ND.getQualifiedNameAsString() == "Foo::~Foo") &&
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      ND.printQualifiedName(OS);
+    }
+    return (QualifiedNameBuf.str() == "Foo::~Foo") &&
            isa<CXXDestructorDecl>(&ND);
   });
 
diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index dce033af73c1a..f2ac540493ad4 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -3081,8 +3081,14 @@ TEST(GetNonLocalDeclRefs, All) {
     auto NonLocalDeclRefs = getNonLocalDeclRefs(AST, FD);
     std::vector<std::string> Names;
     for (const Decl *D : NonLocalDeclRefs) {
-      if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
-        Names.push_back(ND->getQualifiedNameAsString());
+      if (const auto *ND = llvm::dyn_cast<NamedDecl>(D)) {
+        SmallString<128> QualifiedNameBuf;
+        {
+          llvm::raw_svector_ostream OS(QualifiedNameBuf);
+          ND->printQualifiedName(OS);
+        }
+        Names.push_back(std::string(QualifiedNameBuf.str()));
+      }
     }
     EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
         << File.code();
diff --git a/clang-tools-extra/include-cleaner/lib/Types.cpp b/clang-tools-extra/include-cleaner/lib/Types.cpp
index d7635c258e522..715d9d2a631b0 100644
--- a/clang-tools-extra/include-cleaner/lib/Types.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Types.cpp
@@ -25,9 +25,12 @@ std::string Symbol::name() const {
   switch (kind()) {
   case include_cleaner::Symbol::Macro:
     return macro().Name->getName().str();
-  case include_cleaner::Symbol::Declaration:
-    return llvm::dyn_cast<NamedDecl>(&declaration())
-        ->getQualifiedNameAsString();
+  case include_cleaner::Symbol::Declaration: {
+    SmallString<128> Name;
+    llvm::raw_svector_ostream OS(Name);
+    llvm::cast<NamedDecl>(&declaration())->printQualifiedName(OS);
+    return std::string(Name.str());
+  }
   }
   llvm_unreachable("Unknown symbol kind");
 }
@@ -35,8 +38,10 @@ std::string Symbol::name() const {
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) {
   switch (S.kind()) {
   case Symbol::Declaration:
-    if (const auto *ND = llvm::dyn_cast<NamedDecl>(&S.declaration()))
-      return OS << ND->getQualifiedNameAsString();
+    if (const auto *ND = llvm::dyn_cast<NamedDecl>(&S.declaration())) {
+      ND->printQualifiedName(OS);
+      return OS;
+    }
     return OS << S.declaration().getDeclKindName();
   case Symbol::Macro:
     return OS << S.macro().Name->getName();
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 92050d635e2e0..bfdafb32a9306 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -361,9 +361,6 @@ class NamedDecl : public Decl {
   void printNestedNameSpecifier(raw_ostream &OS,
                                 const PrintingPolicy &Policy) const;
 
-  // FIXME: Remove string version.
-  std::string getQualifiedNameAsString() const;
-
   /// Appends a human-readable name for this declaration into the given stream.
   ///
   /// This is the method invoked by Sema when displaying a NamedDecl
diff --git a/clang/include/clang/AST/StmtDataCollectors.td b/clang/include/clang/AST/StmtDataCollectors.td
index abf4b5f34d349..ce6e20b0629c7 100644
--- a/clang/include/clang/AST/StmtDataCollectors.td
+++ b/clang/include/clang/AST/StmtDataCollectors.td
@@ -46,19 +46,22 @@ class CallExpr {
       // If the function is a template specialization, we also need to handle
       // the template arguments as they are not included in the qualified name.
       if (auto Args = D->getTemplateSpecializationArgs()) {
-        std::string ArgString;
-
-        // Print all template arguments into ArgString
-        llvm::raw_string_ostream OS(ArgString);
+        SmallString<256> ArgString;
+        llvm::raw_svector_ostream OS(ArgString);
         for (unsigned i = 0; i < Args->size(); ++i) {
           Args->get(i).print(Context.getLangOpts(), OS, /*IncludeType*/ true);
           // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'.
           OS << '\n';
         }
 
-        addData(ArgString);
+        addData(ArgString.str());
+      }
+      SmallString<128> QualName;
+      {
+        llvm::raw_svector_ostream OS(QualName);
+        D->printQualifiedName(OS);
       }
-      addData(D->getQualifiedNameAsString());
+      addData(QualName.str());
     }
   }];
 }
@@ -66,7 +69,12 @@ class CallExpr {
 //--- Value references ---------------------------------------------------//
 class DeclRefExpr {
   code Code = [{
-    addData(S->getDecl()->getQualifiedNameAsString());
+    SmallString<128> QualName;
+    {
+      llvm::raw_svector_ostream OS(QualName);
+      S->getDecl()->printQualifiedName(OS);
+    }
+    addData(QualName.str());
   }];
 }
 class MemberExpr {
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 43cbeb3b40eac..39140dd657bb4 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -58,7 +58,6 @@
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/LambdaCapture.h"
-#include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/OpenMPClause.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/ParentMapContext.h"
@@ -76,7 +75,6 @@
 #include "clang/Basic/AttrKinds.h"
 #include "clang/Basic/BuiltinTraits.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
-#include "clang/Basic/FileManager.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceManager.h"
@@ -86,7 +84,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
-#include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Regex.h"
 #include <cassert>
@@ -3247,7 +3244,10 @@ extern const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
 ///   namespace foo { namespace bar { class X; } }
 /// \endcode
 AST_MATCHER_REGEX(NamedDecl, matchesName, RegExp) {
-  std::string FullNameString = "::" + Node.getQualifiedNameAsString();
+  SmallString<128> FullNameString;
+  llvm::raw_svector_ostream OS(FullNameString);
+  OS << "::";
+  Node.printQualifiedName(OS);
   return RegExp->match(FullNameString);
 }
 
diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
index 3c14716ff7156..160f906ab024e 100644
--- a/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
+++ b/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
@@ -22,9 +22,7 @@
 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Casting.h"
 #include <cstdint>
-#include <ostream>
 
 namespace clang {
 namespace threadSafety {
@@ -659,7 +657,7 @@ class PrettyPrinter {
       if (isa<Wildcard>(E->record())) {
         // handle existentials
         SS << "&";
-        SS << E->clangDecl()->getQualifiedNameAsString();
+        E->clangDecl()->printQualifiedName(SS);
         return;
       }
     }
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 6c1025ecc7f4d..a8223276cb3e2 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -114,9 +114,15 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
   std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
     const MemRegion *R = S->getRegion();
     // Special handling for argument values.
-    if (auto V = dyn_cast<VarRegion>(R))
-      if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
-        return "argument '" + D->getQualifiedNameAsString() + "'";
+    if (const auto *V = dyn_cast<VarRegion>(R)) {
+      if (const auto *D = dyn_cast<ParmVarDecl>(V->getDecl())) {
+        SmallString<128> QualName;
+        llvm::raw_svector_ostream OS(QualName);
+        D->printQualifiedName(OS);
+        return "argument '" + std::string(QualName.str()) + "'";
+      }
+    }
+
     return "initial value of " + Visit(R);
   }
 
@@ -216,19 +222,20 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
 
   std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
     const VarDecl *VD = R->getDecl();
-    std::string Name = VD->getQualifiedNameAsString();
+    SmallString<128> QualName;
+    llvm::raw_svector_ostream OS(QualName);
+    VD->printQualifiedName(OS);
     if (isa<ParmVarDecl>(VD))
-      return "parameter '" + Name + "'";
-    else if (VD->hasAttr<BlocksAttr>())
-      return "block variable '" + Name + "'";
-    else if (VD->hasLocalStorage())
-      return "local variable '" + Name + "'";
-    else if (VD->isStaticLocal())
-      return "static local variable '" + Name + "'";
-    else if (VD->hasGlobalStorage())
-      return "global variable '" + Name + "'";
-    else
-      llvm_unreachable("A variable is either local or global");
+      return "parameter '" + std::string(QualName.str()) + "'";
+    if (VD->hasAttr<BlocksAttr>())
+      return "block variable '" + std::string(QualName.str()) + "'";
+    if (VD->hasLocalStorage())
+      return "local variable '" + std::string(QualName.str()) + "'";
+    if (VD->isStaticLocal())
+      return "static local variable '" + std::string(QualName.str()) + "'";
+    if (VD->hasGlobalStorage())
+      return "global variable '" + std::string(QualName.str()) + "'";
+    llvm_unreachable("A variable is either local or global");
   }
 
   std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
@@ -247,8 +254,11 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
   }
 
   std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
-    return "base object '" + R->getDecl()->getQualifiedNameAsString() +
-           "' inside " + Visit(R->getSuperRegion());
+    SmallString<128> QualName;
+    llvm::raw_svector_ostream OS(QualName);
+    R->getDecl()->printQualifiedName(OS);
+    return "base object '" + std::string(QualName) + "' inside " +
+           Visit(R->getSuperRegion());
   }
 
   std::string VisitParamVarRegion(const ParamVarRegion *R) {
@@ -256,24 +266,30 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
     llvm::raw_string_ostream OS(Str);
 
     const ParmVarDecl *PVD = R->getDecl();
-    std::string Name = PVD->getQualifiedNameAsString();
-    if (!Name.empty()) {
-      OS << "parameter '" << Name << "'";
-      return std::string(OS.str());
+    if (!PVD->getDeclName().isEmpty()) {
+      SmallString<64> Str;
+      llvm::raw_svector_ostream OS(Str);
+      OS << "parameter '";
+      PVD->printQualifiedName(OS);
+      OS << "'";
+      return std::string(Str);
     }
 
     unsigned Index = R->getIndex() + 1;
     OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
     const Decl *Parent = R->getStackFrame()->getDecl();
-    if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
-      OS << "function '" << FD->getQualifiedNameAsString() << "()'";
-    else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
-      OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
-    else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
-      if (MD->isClassMethod())
-        OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
-      else
-        OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
+    if (const auto *FD = dyn_cast<FunctionDecl>(Parent)) {
+      OS << "function '";
+      FD->printQualifiedName(OS);
+      OS << "()'";
+    } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent)) {
+      OS << "C++ constructor '";
+      CD->printQualifiedName(OS);
+      OS << "()'";
+    } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
+      OS << "Objective-C method '" << (MD->isClassMethod() ? '+' : '-');
+      MD->printQualifiedName(OS);
+      OS << "'";
     } else if (isa<BlockDecl>(Parent)) {
       if (cast<BlockDecl>(Parent)->isConversionFromLambda())
         OS << "lambda";
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 0925fbdcbaeb7..66228956e92ff 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -1805,12 +1805,26 @@ class TemplateDiff {
                              bool FromDefault, bool ToDefault, bool Same) {
     assert((FromTD || ToTD) && "Only one template argument may be missing.");
 
-    std::string FromName =
-        std::string(FromTD ? FromTD->getName() : "(no argument)");
-    std::string ToName = std::string(ToTD ? ToTD->getName() : "(no argument)");
+    SmallString<128> FromNameBuffer, ToNameBuffer;
+    StringRef FromName = "(no argument)";
+    StringRef ToName = "(no argument)";
+
+    if (FromTD)
+      FromName = FromTD->getName();
+    if (ToTD)
+      ToName = ToTD->getName();
+
     if (FromTD && ToTD && FromName == ToName) {
-      FromName = FromTD->getQualifiedNameAsString();
-      ToName = ToTD->getQualifiedNameAsString();
+      {
+        llvm::raw_svector_ostream OS(FromNameBuffer);
+        FromTD->printQualifiedName(OS);
+      }
+      {
+        llvm::raw_svector_ostream OS(ToNameBuffer);
+        ToTD->printQualifiedName(OS);
+      }
+      FromName = FromNameBuffer;
+      ToName = ToNameBuffer;
     }
 
     if (Same) {
diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h
index 9742a16b50f2c..1b0739fdd7a39 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -144,7 +144,11 @@ class Function final {
     if (!Source || !getDecl())
       return "<<expr>>";
 
-    return getDecl()->getQualifiedNameAsString();
+    SmallString<128> Buffer;
+    llvm::raw_svector_ostream OS(Buffer);
+    getDecl()->printQualifiedName(OS);
+
+    return std::string(Buffer.str());
   }
 
   /// Returns a parameter descriptor.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 0894097333d73..814fe8731f5ec 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1681,13 +1681,6 @@ void NamedDecl::printName(raw_ostream &OS) const {
   printName(OS, getASTContext().getPrintingPolicy());
 }
 
-std::string NamedDecl::getQualifiedNameAsString() const {
-  std::string QualName;
-  llvm::raw_string_ostream OS(QualName);
-  printQualifiedName(OS, getASTContext().getPrintingPolicy());
-  return QualName;
-}
-
 void NamedDecl::printQualifiedName(raw_ostream &OS) const {
   printQualifiedName(OS, getASTContext().getPrintingPolicy());
 }
@@ -5446,21 +5439,32 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
   else if (NoSanitizeList.containsLocation(EnabledAsanMask, getLocation(),
                                            "field-padding"))
     ReasonToReject = 6;  // is in an excluded file.
-  else if (NoSanitizeList.containsType(
-               EnabledAsanMask, getQualifiedNameAsString(), "field-padding"))
-    ReasonToReject = 7;  // The type is excluded.
+
+  SmallString<128> QualifiedName;
+  auto getQualName = [this, &QualifiedName]() -> StringRef {
+    if (QualifiedName.empty()) {
+      llvm::raw_svector_ostream OS(QualifiedName);
+      printQualifiedName(OS);
+    }
+    return QualifiedName;
+  };
+
+  if (ReasonToReject < 0 &&
+      NoSanitizeList.containsType(EnabledAsanMask, getQualName(),
+                                  "field-padding"))
+    ReasonToReject = 7; // The type is excluded.
 
   if (EmitRemark) {
     if (ReasonToReject >= 0)
       Context.getDiagnostics().Report(
           getLocation(),
           diag::remark_sanitize_address_insert_extra_padding_rejected)
-          << getQualifiedNameAsString() << ReasonToReject;
+          << getQualName() << ReasonToReject;
     else
       Context.getDiagnostics().Report(
           getLocation(),
           diag::remark_sanitize_address_insert_extra_padding_accepted)
-          << getQualifiedNameAsString();
+          << getQualName();
   }
   return ReasonToReject < 0;
 }
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 1312ffd080342..14c45ab00c808 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -716,10 +716,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
   SubPolicy.SuppressSpecifiers = false;
   std::string Proto;
 
+  llvm::raw_string_ostream OS(Proto);
   if (Policy.FullyQualifiedName) {
-    Proto += D->getQualifiedNameAsString();
+    D->printQualifiedName(OS, SubPolicy);
   } else {
-    llvm::raw_string_ostream OS(Proto);
     if (!Policy.SuppressScope)
       D->getQualifier().print(OS, Policy);
     D->getNameInfo().printName(OS, Policy);
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 3c05d4b22b03e..c9d9f0a6fbeda 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -2132,7 +2132,13 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
           assert(I.second.getBaseOffset() == BaseOffset &&
                  "Invalid base offset!");
           const CXXRecordDecl *RD = I.second.getBase();
-          ClassNames.insert(RD->getQualifiedNameAsString());
+
+          SmallString<128> NameBuffer;
+          {
+            llvm::raw_svector_ostream OS(NameBuffer);
+            RD->printQualifiedName(OS);
+          }
+          ClassNames.emplace(NameBuffer.str());
         }
 
         for (const std::string &Name : ClassNames) {
@@ -2154,9 +2160,12 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
 
     std::map<std::string, CharUnits> ClassNamesAndOffsets;
     for (const auto &I : VBaseOffsetOffsets) {
-      std::string ClassName = I.first->getQualifiedNameAsString();
-      CharUnits OffsetOffset = I.second;
-      ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
+      SmallString<128> ClassNameBuffer;
+      {
+        llvm::raw_svector_ostream OS(ClassNameBuffer);
+        I.first->printQualifiedName(OS);
+      }
+      ClassNamesAndOffsets.emplace(ClassNameBuffer.str(), I.second);
     }
 
     Out << "Virtual base offset offsets for '";
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index 649035c46d019..17dd7a3d6f411 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -340,7 +340,7 @@ std::string AnalysisDeclContext::getFunctionName(const Decl *D) {
   const ASTContext &Ctx = D->getASTContext();
 
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
-    OS << FD->getQualifiedNameAsString();
+    FD->printQualifiedName(OS);
 
     // In C++, there are overloads.
 
@@ -474,7 +474,7 @@ void StackFrame::printJson(
         << "{ \"lctx_id\": " << SF.getID() << ", \"location_context\": \"";
     Out << '#' << Idx << " Call\", \"calling\": \"";
     if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl()))
-      Out << D->getQualifiedNameAsString();
+      D->printQualifiedName(Out, PP);
     else
       Out << "anonymous code";
 
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 5263114ebca28..ce80c4951bc45 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -6116,14 +6116,14 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
   case CFGElement::Kind::ScopeBegin:
     OS << "CFGScopeBegin(";
     if (const VarDecl *VD = E.castAs<CFGScopeBegin>().getVarDecl())
-      OS << VD->getQualifiedNameAsString();
+      VD->printQualifiedName(OS);
     OS << ")";
     break;
 
   case CFGElement::Kind::ScopeEnd:
     OS << "CFGScopeEnd(";
     if (const VarDecl *VD = E.castAs<CFGScopeEnd>().getVarDecl())
-      OS << VD->getQualifiedNameAsString();
+      VD->printQualifiedName(OS);
     OS << ")";
     break;
 
diff --git a/clang/lib/Analysis/IssueHash.cpp b/clang/lib/Analysis/IssueHash.cpp
index 6f97b1964550f..a3d9f49ff4d74 100644
--- a/clang/lib/Analysis/IssueHash.cpp
+++ b/clang/lib/Analysis/IssueHash.cpp
@@ -29,6 +29,7 @@ static std::string GetSignature(const FunctionDecl *Target) {
   if (!Target)
     return "";
   std::string Signature;
+  llvm::raw_string_ostream OS(Signature);
 
   // When a flow sensitive bug happens in templated code we should not generate
   // distinct hash value for every instantiation. Use the signature from the
@@ -38,19 +39,25 @@ static std::string GetSignature(const FunctionDecl *Target) {
     Target = InstantiatedFrom;
 
   if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
-      !isa<CXXConversionDecl>(Target))
-    Signature.append(Target->getReturnType().getAsString()).append(" ");
-  Signature.append(Target->getQualifiedNameAsString()).append("(");
+      !isa<CXXConversionDecl>(Target)) {
+    Target->getReturnType().print(
+        OS, PrintingPolicy(Target->getASTContext().getLangOpts()));
+    OS << ' ';
+  }
+
+  Target->printQualifiedName(OS);
+  OS << '(';
 
   for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) {
     if (i)
-      Signature.append(", ");
-    Signature.append(Target->getParamDecl(i)->getType().getAsString());
+      OS << ", ";
+    Target->getParamDecl(i)->getType().print(
+        OS, PrintingPolicy(Target->getASTContext().getLangOpts()));
   }
 
   if (Target->isVariadic())
-    Signature.append(", ...");
-  Signature.append(")");
+    OS << ", ...";
+  OS << ')';
 
   const auto *TargetT =
       llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
@@ -59,20 +66,20 @@ static std::string GetSignature(const FunctionDecl *Target) {
     return Signature;
 
   if (TargetT->isConst())
-    Signature.append(" const");
+    OS << " const";
   if (TargetT->isVolatile())
-    Signature.append(" volatile");
+    OS << " volatile";
   if (TargetT->isRestrict())
-    Signature.append(" restrict");
+    OS << " restrict";
 
   if (const auto *TargetPT =
           dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
     switch (TargetPT->getRefQualifier()) {
     case RQ_LValue:
-      Signature.append(" &");
+      OS << " &";
       break;
     case RQ_RValue:
-      Signature.append(" &&");
+      OS << " &&";
       break;
     default:
       break;
@@ -87,7 +94,12 @@ static std::string GetEnclosingDeclContextSignature(const Decl *EnclosingDecl) {
     if (const auto *FD = dyn_cast<FunctionDecl>(ND))
       // To distinguish overloads we need to use the signature.
       return GetSignature(FD);
-    return ND->getQualifiedNameAsString();
+    SmallString<128> QualName;
+    {
+      llvm::raw_svector_ostream OS(QualName);
+      ND->printQualifiedName(OS);
+    }
+    return std::string(QualName.str());
   }
   return "";
 }
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index a56774327731c..bacce14a61f30 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -213,8 +213,11 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC,
   llvm::dbgs() << "       Lifetime Analysis Facts:\n";
   llvm::dbgs() << "==========================================\n";
   if (const Decl *D = AC.getDecl())
-    if (const auto *ND = dyn_cast<NamedDecl>(D))
-      llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n";
+    if (const auto *ND = dyn_cast<NamedDecl>(D)) {
+      llvm::dbgs() << "Function: ";
+      ND->printQualifiedName(llvm::dbgs());
+      llvm::dbgs() << "\n";
+    }
   // Print blocks in the order as they appear in code for a stable ordering.
   for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) {
     llvm::dbgs() << "  Block B" << B->getBlockID() << ":\n";
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 798812327d3ab..8fce2c8a0cad2 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -37,11 +37,14 @@ namespace internal {
 static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg,
                               FactManager &FactMgr,
                               const LoanPropagationAnalysis *LPA) {
-  std::string Name;
+  SmallString<128> Name;
   if (const Decl *D = AC.getDecl()) {
-    if (const auto *ND = dyn_cast<NamedDecl>(D))
-      Name = ND->getQualifiedNameAsString();
-  };
+    if (const auto *ND = dyn_cast<NamedDecl>(D)) {
+      llvm::raw_svector_ostream OS(Name);
+      ND->printQualifiedName(OS);
+    }
+  }
+
   DEBUG_WITH_TYPE(Name.c_str(), AC.getDecl()->dumpColor());
   DEBUG_WITH_TYPE(Name.c_str(), Cfg.dump(AC.getASTContext().getLangOpts(),
                                          /*ShowColors=*/true));
@@ -60,13 +63,15 @@ void LifetimeSafetyAnalysis::run() {
   const CFG &Cfg = *AC.getCFG();
   if (LSOpts.MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > LSOpts.MaxCFGBlocks) {
     DEBUG_WITH_TYPE(
-        "LifetimeSafety", std::string FuncName = "<unknown>";
-        if (const Decl *D = AC.getDecl()) if (const auto *ND =
-                                                  dyn_cast<NamedDecl>(D))
-            FuncName = ND->getQualifiedNameAsString();
-        llvm::dbgs() << "LifetimeSafety: Skipping function " << FuncName
-                     << "due to large CFG: " << Cfg.getNumBlockIDs()
-                     << " blocks (threshold: " << LSOpts.MaxCFGBlocks << ")\n");
+        "LifetimeSafety", llvm::dbgs() << "LifetimeSafety: Skipping function ";
+        if (const Decl *D = AC.getDecl()) {
+          if (const auto *ND = dyn_cast<NamedDecl>(D))
+            ND->printQualifiedName(llvm::dbgs());
+          else
+            llvm::dbgs() << "<unknown>";
+        } else { llvm::dbgs() << "<unknown>"; } llvm::dbgs()
+        << " due to large CFG: " << Cfg.getNumBlockIDs()
+        << " blocks (threshold: " << LSOpts.MaxCFGBlocks << ")\n");
     return;
   }
 
diff --git a/clang/lib/Analysis/ProgramPoint.cpp b/clang/lib/Analysis/ProgramPoint.cpp
index bca2581d923b6..6acae66564700 100644
--- a/clang/lib/Analysis/ProgramPoint.cpp
+++ b/clang/lib/Analysis/ProgramPoint.cpp
@@ -224,24 +224,25 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
     break;
 
   case ProgramPoint::LifetimeEndKind:
-    Out << "LifetimeEnd\", \"var\": \""
-        << castAs<LifetimeEnd>().getDecl()->getNameAsString() << '\"';
+    Out << "LifetimeEnd\", \"var\": \"";
+    castAs<LifetimeEnd>().getDecl()->printName(Out);
+    Out << '\"';
     break;
 
   case ProgramPoint::PreImplicitCallKind: {
     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
-    Out << "PreCall\", \"decl\": \""
-        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
-        << "\", \"location\": ";
+    Out << "PreCall\", \"decl\": \"";
+    PC.getDecl()->getAsFunction()->printQualifiedName(Out, PP);
+    Out << "\", \"location\": ";
     printSourceLocationAsJson(Out, PC.getLocation(), SM);
     break;
   }
 
   case ProgramPoint::PostImplicitCallKind: {
     ImplicitCallPoint PC = castAs<ImplicitCallPoint>();
-    Out << "PostCall\", \"decl\": \""
-        << PC.getDecl()->getAsFunction()->getQualifiedNameAsString()
-        << "\", \"location\": ";
+    Out << "PostCall\", \"decl\": \"";
+    PC.getDecl()->getAsFunction()->printQualifiedName(Out, PP);
+    Out << "\", \"location\": ";
     printSourceLocationAsJson(Out, PC.getLocation(), SM);
     break;
   }
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 9c0c1cbdeb219..946e5860474c5 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -3033,9 +3033,14 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
 
   auto [M, SSK] = SanitizerInfoFromCFICheckKind(TCK);
 
-  std::string TypeName = RD->getQualifiedNameAsString();
+  SmallString<128> TypeName;
+  {
+    llvm::raw_svector_ostream OS(TypeName);
+    RD->printQualifiedName(OS);
+  }
+
   if (getContext().getNoSanitizeList().containsType(
-          SanitizerMask::bitPosToMask(M), TypeName))
+          SanitizerMask::bitPosToMask(M), TypeName.str()))
     return;
 
   EmitSanitizerStatReport(SSK);
@@ -3087,9 +3092,13 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
       !CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall))
     return false;
 
-  std::string TypeName = RD->getQualifiedNameAsString();
+  SmallString<128> TypeName;
+  {
+    llvm::raw_svector_ostream OS(TypeName);
+    RD->printQualifiedName(OS);
+  }
   return !getContext().getNoSanitizeList().containsType(SanitizerKind::CFIVCall,
-                                                        TypeName);
+                                                        TypeName.str());
 }
 
 llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
@@ -3114,10 +3123,14 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
 
   llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
 
-  std::string TypeName = RD->getQualifiedNameAsString();
+  SmallString<128> TypeName;
+  {
+    llvm::raw_svector_ostream OS(TypeName);
+    RD->printQualifiedName(OS);
+  }
   if (SanOpts.has(SanitizerKind::CFIVCall) &&
       !getContext().getNoSanitizeList().containsType(SanitizerKind::CFIVCall,
-                                                     TypeName)) {
+                                                     TypeName.str())) {
     EmitCheck(std::make_pair(CheckResult, CheckOrdinal), CheckHandler, {}, {});
   }
 
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 26aaef9d331c0..7235f23bfa35e 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -1376,7 +1376,7 @@ static StringRef getIdentStringFromSourceLocation(CodeGenFunction &CGF,
     OS << PLoc.getFilename();
   OS << ";";
   if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
-    OS << FD->getQualifiedNameAsString();
+    FD->printQualifiedName(OS);
   OS << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
   return OS.str();
 }
@@ -1391,15 +1391,19 @@ llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF,
       Loc.isInvalid()) {
     SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
   } else {
-    std::string FunctionName;
-    std::string FileName;
-    if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl))
-      FunctionName = FD->getQualifiedNameAsString();
+    SmallString<128> FunctionName;
+    if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) {
+      llvm::raw_svector_ostream OS(FunctionName);
+      FD->printQualifiedName(OS);
+    }
+
     PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
+    std::string FileName;
     if (auto *DbgInfo = CGF.getDebugInfo())
       FileName = DbgInfo->remapDIPath(PLoc.getFilename());
     else
       FileName = PLoc.getFilename();
+
     unsigned Line = PLoc.getLine();
     unsigned Column = PLoc.getColumn();
     SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line,
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
index b09fc4c91df2a..c7b660fb8d2ec 100644
--- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
@@ -96,8 +96,13 @@ HLSLBufferLayoutBuilder::layOutStruct(const RecordType *RT,
   // Create the layout struct type; anonymous structs have empty name but
   // non-empty qualified name
   const auto *Decl = RT->castAsCXXRecordDecl();
-  std::string Name =
-      Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
+  SmallString<64> Name;
+  if (Decl->getName().empty()) {
+    Name = "anon";
+  } else {
+    llvm::raw_svector_ostream OS(Name);
+    Decl->printQualifiedName(OS);
+  }
 
   llvm::StructType *NewTy = llvm::StructType::create(Layout, Name,
                                                      /*isPacked=*/true);
diff --git a/clang/lib/Frontend/ASTConsumers.cpp b/clang/lib/Frontend/ASTConsumers.cpp
index 40995e32b67fa..adb9b766b10a8 100644
--- a/clang/lib/Frontend/ASTConsumers.cpp
+++ b/clang/lib/Frontend/ASTConsumers.cpp
@@ -79,8 +79,12 @@ namespace {
 
   private:
     std::string getName(Decl *D) {
-      if (isa<NamedDecl>(D))
-        return cast<NamedDecl>(D)->getQualifiedNameAsString();
+      if (auto *ND = dyn_cast_or_null<NamedDecl>(D)) {
+        SmallString<64> Name;
+        llvm::raw_svector_ostream OS(Name);
+        ND->printQualifiedName(OS);
+        return std::string(Name.str());
+      }
       return "";
     }
     bool filterMatches(Decl *D) {
diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 79f1e2b6571c6..b9bb100e07de9 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -21,14 +21,11 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Sema.h"
-
 #include "llvm/Support/Error.h"
 #include "llvm/Support/raw_ostream.h"
-
 #include <cassert>
 #include <cmath>
 #include <cstdarg>
-#include <sstream>
 #include <string>
 
 #define DEBUG_TYPE "interp-value"
@@ -40,7 +37,7 @@ static std::string DeclTypeToString(const QualType &QT, NamedDecl *D) {
   llvm::raw_string_ostream SS(Str);
   if (QT.hasQualifiers())
     SS << QT.getQualifiers().getAsString() << " ";
-  SS << D->getQualifiedNameAsString();
+  D->printQualifiedName(SS);
   return Str;
 }
 
@@ -109,7 +106,9 @@ static std::string EnumToString(const Value &V) {
     if (I->getInitVal() == AP) {
       if (!IsFirst)
         SS << " ? ";
-      SS << "(" + I->getQualifiedNameAsString() << ")";
+      SS << "(";
+      I->printQualifiedName(SS);
+      SS << ")";
       IsFirst = false;
     }
   }
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 0bdea354c2406..ed55c0efc72f1 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -3510,11 +3510,15 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
           TagType == DeclSpec::TST_union || TagType == DeclSpec::TST_class) &&
          "Invalid TagType!");
 
-  llvm::TimeTraceScope TimeScope("ParseClass", [&]() {
-    if (auto *TD = dyn_cast_or_null<NamedDecl>(TagDecl))
-      return TD->getQualifiedNameAsString();
-    return std::string("<anonymous>");
-  });
+  SmallString<128> NameBuf;
+  if (auto *TD = dyn_cast_or_null<NamedDecl>(TagDecl)) {
+    llvm::raw_svector_ostream OS(NameBuf);
+    TD->printQualifiedName(OS);
+  } else {
+    NameBuf = "<anonymous>";
+  }
+
+  llvm::TimeTraceScope TimeScope("ParseClass", NameBuf);
 
   PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
                                       "parsing struct/union/class body");
@@ -3529,13 +3533,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
         NonNestedClass = false;
 
         // The Microsoft extension __interface does not permit nested classes.
-        if (getCurrentClass().IsInterface) {
+        if (getCurrentClass().IsInterface)
           Diag(RecordLoc, diag::err_invalid_member_in_interface)
-              << /*ErrorType=*/6
-              << (isa<NamedDecl>(TagDecl)
-                      ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
-                      : "(anonymous)");
-        }
+              << /*ErrorType=*/6 << dyn_cast_or_null<NamedDecl>(TagDecl);
         break;
       }
 
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index d0500a6defd64..afa18ad632d7b 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -14,7 +14,6 @@
 
 #include "clang/Sema/AnalysisBasedWarnings.h"
 #include "SemaLifetimeSafety.h"
-#include "TypeLocBuilder.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
@@ -47,7 +46,6 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/SemaInternal.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/DenseMap.h"
@@ -2595,14 +2593,11 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
     Loc = CtorExpr->getLocation();
     Range = CtorExpr->getSourceRange();
 
-    std::string ContainerName = "std::span";
-    if (auto *TD = CtorExpr->getConstructor()->getParent()) {
-      // This will provide "std::span" if it's in the std namespace
-      ContainerName = TD->getQualifiedNameAsString();
-    }
-
     // FIX: Pass the container name to fill the %0 parameter
-    S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container) << ContainerName;
+    if (const auto *TD = CtorExpr->getConstructor()->getParent())
+      S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container) << TD;
+    else
+      S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container) << "std::span";
 
     if (IsRelatedToDecl) {
       assert(!SuggestSuggestions &&
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index cc2af8feb3794..acf2ba04b2b06 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1876,8 +1876,7 @@ static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
           (OrigDecl->getAccess() == AS_public ||
            OrigDecl->getAccess() == AS_protected)) {
         S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
-            << UD->getQualifiedNameAsString()
-            << OrigDecl->getQualifiedNameAsString();
+            << UD << OrigDecl;
         return true;
       }
     }
diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp
index 066dab2f0bef2..7dc80b8b35037 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -320,17 +320,17 @@ static bool CheckAssignmentToCountAttrPtrWithIncompletePointeeTy(
   if (!CATy)
     return true;
 
-  std::string AssigneeStr;
+  SmallString<64> AssigneeBuf;
   if (Assignee) {
-    if (ShowFullyQualifiedAssigneeName) {
-      AssigneeStr = Assignee->getQualifiedNameAsString();
-    } else {
-      AssigneeStr = Assignee->getNameAsString();
-    }
+    llvm::raw_svector_ostream OS(AssigneeBuf);
+    if (ShowFullyQualifiedAssigneeName)
+      Assignee->printQualifiedName(OS);
+    else
+      Assignee->printName(OS);
   }
 
   S.Diag(Loc, diag::err_counted_by_on_incomplete_type_on_assign)
-      << static_cast<int>(Action) << AssigneeStr << (AssigneeStr.size() > 0)
+      << static_cast<int>(Action) << AssigneeBuf << !AssigneeBuf.empty()
       << isa<ImplicitValueInitExpr>(RHSExpr) << LHSTy
       << CATy->getAttributeName(/*WithMacroPrefix=*/true) << PointeeTy
       << CATy->isOrNull() << RHSExpr->getSourceRange();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7f3ccea82e8af..30568c4da03ca 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11578,8 +11578,14 @@ void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName,
 } // namespace
 
 void Sema::CheckFreeArguments(const CallExpr *E) {
-  const std::string CalleeName =
-      cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString();
+  const auto *FD = cast<FunctionDecl>(E->getCalleeDecl());
+
+  SmallString<64> CalleeNameBuf;
+  {
+    llvm::raw_svector_ostream OS(CalleeNameBuf);
+    FD->printQualifiedName(OS);
+  }
+  std::string CalleeName = CalleeNameBuf.str().str();
 
   { // Prefer something that doesn't involve a cast to make things simpler.
     const Expr *Arg = E->getArg(0)->IgnoreParenCasts();
@@ -11599,13 +11605,13 @@ void Sema::CheckFreeArguments(const CallExpr *E) {
 
     if (const auto *Label = dyn_cast<AddrLabelExpr>(Arg)) {
       Diag(Label->getBeginLoc(), diag::warn_free_nonheap_object)
-          << CalleeName << 0 /*object: */ << Label->getLabel()->getIdentifier();
+          << FD << 0 /*object: */ << Label->getLabel()->getIdentifier();
       return;
     }
 
     if (isa<BlockExpr>(Arg)) {
       Diag(Arg->getBeginLoc(), diag::warn_free_nonheap_object)
-          << CalleeName << 1 /*object: block*/;
+          << FD << 1 /*object: block*/;
       return;
     }
   }
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2b524a956ecc4..0d5aed12544ee 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6760,8 +6760,7 @@ static void DiagnosedUnqualifiedCallsToStdFunctions(Sema &S,
     return;
 
   S.Diag(DRE->getLocation(), diag::warn_unqualified_call_to_std_cast_function)
-      << FD->getQualifiedNameAsString()
-      << FixItHint::CreateInsertion(DRE->getLocation(), "std::");
+      << FD << FixItHint::CreateInsertion(DRE->getLocation(), "std::");
 }
 
 ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 81bc6c68f377d..80b0ae6c08f0d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12,7 +12,6 @@
 
 #include "CheckExprLifetime.h"
 #include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
@@ -14681,9 +14680,15 @@ static bool DiagnoseTwoPhaseLookup(
           // Never suggest declaring a function within a namespace with a
           // reserved name, like __gnu_cxx.
           NamespaceDecl *NS = dyn_cast<NamespaceDecl>(*it);
-          if (NS &&
-              NS->getQualifiedNameAsString().find("__") != std::string::npos)
-            continue;
+          if (NS) {
+            SmallString<64> QualName;
+            {
+              llvm::raw_svector_ostream OS(QualName);
+              NS->printQualifiedName(OS);
+            }
+            if (QualName.str().contains("__"))
+              continue;
+          }
 
           SuggestedNamespaces.insert(*it);
         }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 67289855685db..512052c0f3d96 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3379,11 +3379,15 @@ static bool isInVkNamespace(const RecordType *RT) {
   if (!DC)
     return false;
 
-  NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
-  if (!ND)
+  const auto *VkND = dyn_cast<NamespaceDecl>(DC);
+  if (!VkND || VkND->getName() != "vk")
     return false;
 
-  return ND->getQualifiedNameAsString() == "hlsl::vk";
+  const auto *HlslND = dyn_cast<NamespaceDecl>(VkND->getDeclContext());
+  if (!HlslND || HlslND->getName() != "hlsl")
+    return false;
+
+  return HlslND->getDeclContext()->isTranslationUnit();
 }
 
 static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef,
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index d3e4a3a634764..0ce9780cf3fa0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
@@ -124,8 +124,12 @@ class AnalysisOrderChecker
   bool evalCall(const CallEvent &Call, CheckerContext &C) const {
     if (isCallbackEnabled(C, "EvalCall")) {
       llvm::errs() << "EvalCall";
-      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
-        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
+      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) {
+        llvm::errs() << " (";
+        ND->printQualifiedName(llvm::errs());
+        llvm::errs() << ')';
+      }
+
       llvm::errs() << " {argno: " << Call.getNumArgs() << '}';
       llvm::errs() << " [" << Call.getKindAsString() << ']';
       llvm::errs() << '\n';
@@ -138,8 +142,11 @@ class AnalysisOrderChecker
   void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
     if (isCallbackEnabled(C, "PreCall")) {
       llvm::errs() << "PreCall";
-      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
-        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
+      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) {
+        llvm::errs() << " (";
+        ND->printQualifiedName(llvm::errs());
+        llvm::errs() << ')';
+      }
       llvm::errs() << " [" << Call.getKindAsString() << ']';
       llvm::errs() << '\n';
     }
@@ -148,8 +155,11 @@ class AnalysisOrderChecker
   void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
     if (isCallbackEnabled(C, "PostCall")) {
       llvm::errs() << "PostCall";
-      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
-        llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
+      if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) {
+        llvm::errs() << " (";
+        ND->printQualifiedName(llvm::errs());
+        llvm::errs() << ')';
+      }
       llvm::errs() << " [" << Call.getKindAsString() << ']';
       llvm::errs() << '\n';
     }
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 5ee5601a9319a..029c3df4fdc51 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -3857,18 +3857,21 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
     return true;
   }
 
-  if (FName == "postEvent" &&
-      FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
+  auto IsInClass = [](const FunctionDecl *FD, StringRef ClassName) {
+    if (const auto *RD = dyn_cast<CXXRecordDecl>(FD->getDeclContext()))
+      return RD->getName() == ClassName;
+    return false;
+  };
+
+  if (FName == "postEvent" && IsInClass(FD, "QCoreApplication")) {
     return true;
   }
 
-  if (FName == "connectImpl" &&
-      FD->getQualifiedNameAsString() == "QObject::connectImpl") {
+  if (FName == "connectImpl" && IsInClass(FD, "QObject")) {
     return true;
   }
 
-  if (FName == "singleShotImpl" &&
-      FD->getQualifiedNameAsString() == "QTimer::singleShotImpl") {
+  if (FName == "singleShotImpl" && IsInClass(FD, "QTimer")) {
     return true;
   }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 9c616a2d17783..e669b25e83a3b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -662,7 +662,7 @@ void MoveChecker::explainObject(ProgramStateRef State, llvm::raw_ostream &OS,
                                 MisuseKind MK) const {
   // We may need a leading space every time we actually explain anything,
   // and we never know if we are to explain anything until we try.
-  if (const auto DR =
+  if (const auto *DR =
           dyn_cast_or_null<DeclRegion>(unwrapRValueReferenceIndirection(MR))) {
     const auto *RegionDecl = cast<NamedDecl>(DR->getDecl());
     OS << " '" << RegionDecl->getDeclName() << "'";
@@ -670,18 +670,20 @@ void MoveChecker::explainObject(ProgramStateRef State, llvm::raw_ostream &OS,
 
   ObjectKind OK = classifyObject(State, MR, RD);
   switch (OK.StdKind) {
-    case SK_NonStd:
-    case SK_Safe:
+  case SK_NonStd:
+  case SK_Safe:
+    break;
+  case SK_SmartPtr:
+    if (MK != MK_Dereference)
       break;
-    case SK_SmartPtr:
-      if (MK != MK_Dereference)
-        break;
 
-      // We only care about the type if it's a dereference.
-      [[fallthrough]];
-    case SK_Unsafe:
-      OS << " of type '" << RD->getQualifiedNameAsString() << "'";
-      break;
+    // We only care about the type if it's a dereference.
+    [[fallthrough]];
+  case SK_Unsafe:
+    OS << " of type '";
+    RD->printQualifiedName(OS);
+    OS << "'";
+    break;
   };
 }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp b/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp
index 3583e7b2aa6f8..756f6cf4157f2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp
@@ -63,8 +63,12 @@ LLVM_DUMP_METHOD std::string
 NoOwnershipChangeVisitor::getFunctionName(const ExplodedNode *CallEnterN) {
   if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
           CallEnterN->getLocationAs<CallEnter>()->getCallExpr()))
-    if (const FunctionDecl *FD = CE->getDirectCallee())
-      return FD->getQualifiedNameAsString();
+    if (const FunctionDecl *FD = CE->getDirectCallee()) {
+      SmallString<128> Name;
+      llvm::raw_svector_ostream OS(Name);
+      FD->printQualifiedName(OS);
+      return std::string(Name.str());
+    }
   return "";
 }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 59d11c4d8ae2c..4b0c6b60f84ed 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -173,9 +173,13 @@ static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
       FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
 
     if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
-      os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
+      os << "Call to method '";
+      MD->printQualifiedName(os);
+      os << '\'';
     } else if (FD) {
-      os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
+      os << "Call to function '";
+      FD->printQualifiedName(os);
+      os << '\'';
     } else {
       os << "function call";
     }
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 36a71d510b902..7d65ff51f3f7c 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -211,18 +211,20 @@ const ParmVarDecl *ParamVarRegion::getDecl() const {
   if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
     assert(Index < FD->param_size());
     return FD->parameters()[Index];
-  } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+  }
+  if (const auto *BD = dyn_cast<BlockDecl>(D)) {
     assert(Index < BD->param_size());
     return BD->parameters()[Index];
-  } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+  }
+  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
     assert(Index < MD->param_size());
     return MD->parameters()[Index];
-  } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+  }
+  if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
     assert(Index < CD->param_size());
     return CD->parameters()[Index];
-  } else {
-    llvm_unreachable("Unexpected Decl kind!");
   }
+  llvm_unreachable("Unexpected Decl kind!");
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp
index 483e62d4a9a7e..6f92683501e3f 100644
--- a/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -355,7 +355,7 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
       const nonloc::PointerToMember &CastRes =
           castAs<nonloc::PointerToMember>();
       if (CastRes.getDecl())
-        os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|";
+        os << "|" << CastRes.getDecl() << "|";
       bool first = true;
       for (const auto &I : CastRes) {
         if (first) {
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index ce44fcd240ffa..2c71769f4b646 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -373,9 +373,16 @@ class AnalysisConsumer : public AnalysisASTConsumer,
 
 std::string timeTraceScopeDeclName(StringRef FunName, const Decl *D) {
   if (llvm::timeTraceProfilerEnabled()) {
-    if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
-      return (FunName + " " + ND->getQualifiedNameAsString()).str();
-    return (FunName + " <anonymous> ").str();
+    SmallString<128> NameBuf;
+    llvm::raw_svector_ostream OS(NameBuf);
+
+    OS << FunName << " ";
+    if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
+      ND->printQualifiedName(OS);
+    else
+      OS << "<anonymous>";
+
+    return std::string(NameBuf.str());
   }
   return "";
 }
diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
index 7ca789bba9c02..5466cc55c260f 100644
--- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -358,23 +358,36 @@ int SyntaxTree::Impl::findPositionInParent(NodeId Id, bool Shifted) const {
 std::string
 SyntaxTree::Impl::getRelativeName(const NamedDecl *ND,
                                   const DeclContext *Context) const {
-  std::string Val = ND->getQualifiedNameAsString();
-  std::string ContextPrefix;
-  if (!Context)
-    return Val;
-  if (auto *Namespace = dyn_cast<NamespaceDecl>(Context))
-    ContextPrefix = Namespace->getQualifiedNameAsString();
-  else if (auto *Record = dyn_cast<RecordDecl>(Context))
-    ContextPrefix = Record->getQualifiedNameAsString();
-  else if (AST.getLangOpts().CPlusPlus11)
-    if (auto *Tag = dyn_cast<TagDecl>(Context))
-      ContextPrefix = Tag->getQualifiedNameAsString();
-  // Strip the qualifier, if Val refers to something in the current scope.
-  // But leave one leading ':' in place, so that we know that this is a
-  // relative path.
-  if (!ContextPrefix.empty() && StringRef(Val).starts_with(ContextPrefix))
-    Val = Val.substr(ContextPrefix.size() + 1);
-  return Val;
+  SmallString<128> ValBuf;
+  {
+    llvm::raw_svector_ostream OS(ValBuf);
+    ND->printQualifiedName(OS);
+  }
+
+  if (Context) {
+    if (const auto *ContextND = dyn_cast<NamedDecl>(Context)) {
+      if (isa<NamespaceDecl>(Context) || isa<RecordDecl>(Context) ||
+          (AST.getLangOpts().CPlusPlus11 && isa<TagDecl>(Context))) {
+
+        SmallString<128> ContextPrefixBuf;
+        {
+          llvm::raw_svector_ostream OS(ContextPrefixBuf);
+          ContextND->printQualifiedName(OS);
+        }
+
+        StringRef Val = ValBuf.str();
+        StringRef ContextPrefix = ContextPrefixBuf.str();
+
+        // Strip the qualifier, if Val refers to something in the current scope.
+        // But leave one leading ':' in place, so that we know that this is a
+        // relative path.
+        if (!ContextPrefix.empty() && Val.starts_with(ContextPrefix))
+          return std::string(Val.substr(ContextPrefix.size() + 1));
+      }
+    }
+  }
+
+  return std::string(ValBuf.str());
 }
 
 std::string SyntaxTree::Impl::getRelativeName(const NamedDecl *ND) const {
@@ -691,8 +704,12 @@ StringRef Node::getTypeLabel() const { return getType().asStringRef(); }
 
 std::optional<std::string> Node::getQualifiedIdentifier() const {
   if (auto *ND = ASTNode.get<NamedDecl>()) {
-    if (ND->getDeclName().isIdentifier())
-      return ND->getQualifiedNameAsString();
+    if (ND->getDeclName().isIdentifier()) {
+      SmallString<128> Buf;
+      llvm::raw_svector_ostream OS(Buf);
+      ND->printQualifiedName(OS);
+      return std::string(Buf.str());
+    }
   }
   return std::nullopt;
 }
diff --git a/clang/lib/Tooling/Refactoring/Lookup.cpp b/clang/lib/Tooling/Refactoring/Lookup.cpp
index dedde860516ab..2a6ffc2271518 100644
--- a/clang/lib/Tooling/Refactoring/Lookup.cpp
+++ b/clang/lib/Tooling/Refactoring/Lookup.cpp
@@ -62,11 +62,11 @@ usingFromDifferentCanonicalNamespace(const DeclContext *FromContext,
   if (UseNamespaces.size() < FromNamespaces.size())
     return false;
   unsigned Diff = UseNamespaces.size() - FromNamespaces.size();
-  auto FromIter = FromNamespaces.begin();
+  auto *FromIter = FromNamespaces.begin();
   // Only compare `FromNamespaces` with namespaces in `UseNamespaces` that can
   // collide, i.e. the top N namespaces where N is the number of namespaces in
   // `FromNamespaces`.
-  auto UseIter = UseNamespaces.begin() + Diff;
+  auto *UseIter = UseNamespaces.begin() + Diff;
   for (; FromIter != FromNamespaces.end() && UseIter != UseNamespaces.end();
        ++FromIter, ++UseIter) {
     // Literally the same namespace, not a collision.
@@ -96,8 +96,13 @@ static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
     // Otherwise strip off redundant namespace qualifications from the new name.
     // We use the fully qualified name of the namespace and remove that part
     // from NewName if it has an identical prefix.
-    std::string NS =
-        "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
+    SmallString<128> NS;
+    {
+      llvm::raw_svector_ostream OS(NS);
+      OS << "::";
+      cast<NamespaceDecl>(DeclA)->printQualifiedName(OS);
+      OS << "::";
+    }
     if (NewName.consume_front(NS))
       return NewName;
 
@@ -145,15 +150,21 @@ static std::string disambiguateSpellingInScope(StringRef Spelling,
     for (const auto *NS : EnclosingNamespaces) {
       auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head)));
       if (!LookupRes.empty()) {
-        for (const NamedDecl *Res : LookupRes)
+        for (const NamedDecl *Res : LookupRes) {
           // If `Res` is not visible in `UseLoc`, we don't consider it
           // ambiguous. For example, a reference in a header file should not be
           // affected by a potentially ambiguous name in some file that includes
           // the header.
-          if (!TrimmedQName.starts_with(Res->getQualifiedNameAsString()) &&
+          SmallString<128> ResQName;
+          {
+            llvm::raw_svector_ostream OS(ResQName);
+            Res->printQualifiedName(OS);
+          }
+          if (!TrimmedQName.starts_with(ResQName.str()) &&
               SM.isBeforeInTranslationUnit(
                   SM.getSpellingLoc(Res->getLocation()), UseLoc))
             return true;
+        }
       }
     }
     return false;
diff --git a/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp b/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
index 66902614488a7..1f52a624aac6d 100644
--- a/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
+++ b/clang/lib/Tooling/Refactoring/Rename/USRFinder.cpp
@@ -106,10 +106,21 @@ class NamedDeclFindingVisitor
   bool VisitNamedDecl(const NamedDecl *ND) {
     if (!ND)
       return true;
-    // Fully qualified name is used to find the declaration.
-    if (Name != ND->getQualifiedNameAsString() &&
-        Name != "::" + ND->getQualifiedNameAsString())
+
+    SmallString<128> QNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QNameBuf);
+      ND->printQualifiedName(OS);
+    }
+
+    StringRef QName = QNameBuf.str();
+    StringRef TargetName = Name;
+
+    TargetName.consume_front("::");
+
+    if (TargetName != QName)
       return true;
+
     Result = ND;
     return false;
   }
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index f3b4c9ca7fa9a..c75d419809a1a 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -120,7 +120,12 @@ TEST_P(RedirectingImporterTest, InterceptImport) {
       getImportedDecl("class shouldNotBeImported {};", Lang_CXX03,
                       "class realDecl {};", Lang_CXX03, "shouldNotBeImported");
   auto *Imported = cast<CXXRecordDecl>(To);
-  EXPECT_EQ(Imported->getQualifiedNameAsString(), "realDecl");
+  SmallString<128> QualifiedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(QualifiedNameBuf);
+    Imported->printQualifiedName(OS);
+  }
+  EXPECT_EQ(QualifiedNameBuf.str(), "realDecl");
 
   // Make sure our importer prevented the importing of the decl.
   auto *ToTU = Imported->getTranslationUnitDecl();
diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 195b8ab4c4e66..b7fa991a5b31c 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -817,22 +817,6 @@ void instantiate_template() {
   EXPECT_EQ(GetNameInfoRange(Matches[2]), "<input.cc:6:14, col:15>");
 }
 
-TEST(Decl, getQualifiedNameAsString) {
-  llvm::Annotations Code(R"cpp(
-namespace x::y {
-  template <class T> class Foo { Foo() {} };
-}
-)cpp");
-
-  auto AST = tooling::buildASTFromCode(Code.code());
-  ASTContext &Ctx = AST->getASTContext();
-
-  auto const *FD = selectFirst<CXXConstructorDecl>(
-      "ctor", match(cxxConstructorDecl().bind("ctor"), Ctx));
-  ASSERT_NE(FD, nullptr);
-  ASSERT_EQ(FD->getQualifiedNameAsString(), "x::y::Foo::Foo<T>");
-}
-
 TEST(Decl, NoWrittenArgsInImplicitlyInstantiatedVarSpec) {
   const char *Code = R"cpp(
     template <typename>
diff --git a/clang/unittests/Frontend/FrontendActionTest.cpp b/clang/unittests/Frontend/FrontendActionTest.cpp
index ae12b4ffcf931..4e8b4cc46fb5c 100644
--- a/clang/unittests/Frontend/FrontendActionTest.cpp
+++ b/clang/unittests/Frontend/FrontendActionTest.cpp
@@ -17,12 +17,9 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "clang/Sema/Sema.h"
-#include "clang/Serialization/InMemoryModuleCache.h"
 #include "clang/Serialization/ModuleCache.h"
 #include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/VirtualFileSystem.h"
-#include "llvm/TargetParser/Triple.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -70,7 +67,12 @@ class TestASTFrontendAction : public ASTFrontendAction {
     }
 
     bool VisitNamedDecl(NamedDecl *Decl) override {
-      decl_names_.push_back(Decl->getQualifiedNameAsString());
+      SmallString<128> QualifiedNameBuf;
+      {
+        llvm::raw_svector_ostream OS(QualifiedNameBuf);
+        Decl->printQualifiedName(OS);
+      }
+      decl_names_.push_back(std::string(QualifiedNameBuf.str()));
       return true;
     }
 
diff --git a/clang/unittests/Index/IndexTests.cpp b/clang/unittests/Index/IndexTests.cpp
index e20764e4fb9d9..12534e3167393 100644
--- a/clang/unittests/Index/IndexTests.cpp
+++ b/clang/unittests/Index/IndexTests.cpp
@@ -10,7 +10,6 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
-#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/SourceLocation.h"
@@ -23,8 +22,6 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Tooling/Tooling.h"
 #include "clang/UnifiedSymbolResolution/USRGeneration.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/VirtualFileSystem.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <memory>
@@ -85,7 +82,14 @@ class Indexer : public IndexDataConsumer {
       return true;
     TestSymbol S;
     S.SymInfo = getSymbolInfo(D);
-    S.QName = ND->getQualifiedNameAsString();
+
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      ND->printQualifiedName(OS);
+    }
+    S.QName = std::string(QualifiedNameBuf.str());
+
     S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());
     S.DeclPos =
         Position::fromSourceLocation(D->getLocation(), AST->getSourceManager());
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp
index 450be2a25a12f..be2c56c4f0871 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterTest.cpp
@@ -73,7 +73,12 @@ TEST_F(InterpreterTest, Sanity) {
 }
 
 static std::string DeclToString(Decl *D) {
-  return llvm::cast<NamedDecl>(D)->getQualifiedNameAsString();
+  SmallString<128> QualifiedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(QualifiedNameBuf);
+    llvm::cast<NamedDecl>(D)->printQualifiedName(OS);
+  }
+  return std::string(QualifiedNameBuf.str());
 }
 
 TEST_F(InterpreterTest, IncrementalInputTopLevelDecls) {
@@ -165,8 +170,14 @@ TEST_F(InterpreterTest, TranslationUnitRedeclChainAcrossManyPTUs) {
       ++Decls;
       // Walking up from the decl is what faults in a long-lived session.
       EXPECT_EQ(&D->getASTContext(), &Interp->getASTContext());
-      if (auto *ND = dyn_cast<NamedDecl>(D))
-        (void)ND->getQualifiedNameAsString();
+      if (auto *ND = dyn_cast<NamedDecl>(D)) {
+        SmallString<128> QualifiedNameBuf;
+        {
+          llvm::raw_svector_ostream OS(QualifiedNameBuf);
+          ND->printQualifiedName(OS);
+        }
+        (void)QualifiedNameBuf.str();
+      }
     }
   }
   EXPECT_GT(Nodes, 1u);
@@ -290,14 +301,20 @@ TEST_F(InterpreterTest, FindMangledNameSymbol) {
 }
 
 static Value AllocateObject(TypeDecl *TD, Interpreter &Interp) {
-  std::string Name = TD->getQualifiedNameAsString();
+  SmallString<128> NameBuf;
+  {
+    llvm::raw_svector_ostream OS(NameBuf);
+    TD->printQualifiedName(OS);
+  }
+  llvm::StringRef Name = NameBuf.str();
+
   Value Addr;
   // FIXME: Consider providing an option in clang::Value to take ownership of
   // the memory created from the interpreter.
   // cantFail(Interp.ParseAndExecute("new " + Name + "()", &Addr));
 
   // The lifetime of the temporary is extended by the clang::Value.
-  cantFail(Interp.ParseAndExecute(Name + "()", &Addr));
+  cantFail(Interp.ParseAndExecute((Name + "()").str(), &Addr));
   return Addr;
 }
 
diff --git a/clang/unittests/Sema/CodeCompleteTest.cpp b/clang/unittests/Sema/CodeCompleteTest.cpp
index be611b330e501..5af00c1a1bdff 100644
--- a/clang/unittests/Sema/CodeCompleteTest.cpp
+++ b/clang/unittests/Sema/CodeCompleteTest.cpp
@@ -8,10 +8,8 @@
 
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
-#include "clang/Lex/Preprocessor.h"
 #include "clang/Parse/ParseAST.h"
 #include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaDiagnostic.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/Testing/Annotations/Annotations.h"
 #include "gmock/gmock.h"
@@ -112,9 +110,16 @@ class VisitedContextFinder : public CodeCompleteConsumer {
   std::vector<std::string> getVisitedNamespace(
       CodeCompletionContext::VisitedContextSet VisitedContexts) const {
     std::vector<std::string> NSNames;
-    for (const auto *Context : VisitedContexts)
-      if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
-        NSNames.push_back(NS->getQualifiedNameAsString());
+    for (const auto *Context : VisitedContexts) {
+      if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context)) {
+        SmallString<128> QualifiedNameBuf;
+        {
+          llvm::raw_svector_ostream OS(QualifiedNameBuf);
+          NS->printQualifiedName(OS);
+        }
+        NSNames.push_back(std::string(QualifiedNameBuf.str()));
+      }
+    }
     return NSNames;
   }
 
diff --git a/clang/unittests/Tooling/LookupTest.cpp b/clang/unittests/Tooling/LookupTest.cpp
index ed6f5d4f3092c..47981ce8305a3 100644
--- a/clang/unittests/Tooling/LookupTest.cpp
+++ b/clang/unittests/Tooling/LookupTest.cpp
@@ -200,7 +200,12 @@ TEST(LookupTest, replaceNestedClassName) {
   Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
     // Filter Types by name since there are other `RecordTypeLoc` in the test
     // file.
-    if (Type.getDecl()->getQualifiedNameAsString() == "a::b::Foo") {
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      Type.getDecl()->printQualifiedName(OS);
+    }
+    if (QualifiedNameBuf.str() == "a::b::Foo") {
       EXPECT_EQ("x::Bar", replaceTypeLoc(Type.getDecl(), Type.getBeginLoc(),
                                          "::a::x::Bar"));
     }
@@ -215,7 +220,12 @@ TEST(LookupTest, replaceNestedClassName) {
     // file.
     // `a::b::Foo` in using shadow decl is not `TypeLoc`.
     auto *TD = Type.getDecl()->getTargetDecl();
-    if (TD->getQualifiedNameAsString() == "a::b::Foo") {
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      TD->printQualifiedName(OS);
+    }
+    if (QualifiedNameBuf.str() == "a::b::Foo") {
       EXPECT_EQ("Bar", replaceTypeLoc(TD, Type.getBeginLoc(), "::a::x::Bar"));
     }
   };
@@ -227,7 +237,12 @@ TEST(LookupTest, replaceNestedClassName) {
   // `x::y::Foo` in c.cc [1], it should not make "Foo" at [0] ambiguous because
   // it's not visible at [0].
   Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
-    if (Type.getDecl()->getQualifiedNameAsString() == "x::y::Old") {
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      Type.getDecl()->printQualifiedName(OS);
+    }
+    if (QualifiedNameBuf.str() == "x::y::Old") {
       EXPECT_EQ("Foo",
                 replaceTypeLoc(Type.getDecl(), Type.getBeginLoc(), "::x::Foo"));
     }
diff --git a/clang/unittests/Tooling/QualTypeNamesTest.cpp b/clang/unittests/Tooling/QualTypeNamesTest.cpp
index cb83d6e86cb23..e93cad57cad82 100644
--- a/clang/unittests/Tooling/QualTypeNamesTest.cpp
+++ b/clang/unittests/Tooling/QualTypeNamesTest.cpp
@@ -29,10 +29,15 @@ struct TypeNameVisitor : TestVisitor {
       std::string ActualName = TypeName::getFullyQualifiedName(
           VD->getType(), *Context, Policy, WithGlobalNsPrefix);
       if (ExpectedName != ActualName) {
+        SmallString<128> QualifiedNameBuf;
+        {
+          llvm::raw_svector_ostream OS(QualifiedNameBuf);
+          VD->printQualifiedName(OS);
+        }
         // A custom message makes it much easier to see what declaration
         // failed compared to EXPECT_EQ.
         ADD_FAILURE() << "Typename::getFullyQualifiedName failed for "
-                      << VD->getQualifiedNameAsString() << std::endl
+                      << QualifiedNameBuf << std::endl
                       << "   Actual: " << ActualName << std::endl
                       << " Expected: " << ExpectedName;
       }
diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp
index 481559ed08efd..48c2228947aaf 100644
--- a/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp
+++ b/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp
@@ -49,7 +49,12 @@ class RecordingVisitor : public CRTPTestVisitor<RecordingVisitor> {
   }
 
   bool VisitCXXMethodDecl(CXXMethodDecl *D) {
-    VisitedNodes.push_back(D->getQualifiedNameAsString());
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      D->printQualifiedName(OS);
+    }
+    VisitedNodes.push_back(std::string(QualifiedNameBuf.str()));
     return true;
   }
 
@@ -59,13 +64,24 @@ class RecordingVisitor : public CRTPTestVisitor<RecordingVisitor> {
   }
 
   bool VisitCXXRecordDecl(CXXRecordDecl *D) {
-    if (!D->isImplicit())
-      VisitedNodes.push_back(D->getQualifiedNameAsString());
+    if (!D->isImplicit()) {
+      SmallString<128> QualifiedNameBuf;
+      {
+        llvm::raw_svector_ostream OS(QualifiedNameBuf);
+        D->printQualifiedName(OS);
+      }
+      VisitedNodes.push_back(std::string(QualifiedNameBuf.str()));
+    }
     return true;
   }
 
   bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
-    VisitedNodes.push_back(T->getDecl()->getQualifiedNameAsString());
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      T->getDecl()->printQualifiedName(OS);
+    }
+    VisitedNodes.push_back(std::string(QualifiedNameBuf.str()));
     return true;
   }
 };
diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp
index fe95e8987a73a..ed3e6dbe31ecf 100644
--- a/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp
+++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp
@@ -15,8 +15,12 @@ namespace {
 class CXXMemberCallVisitor : public ExpectedLocationVisitor {
 public:
   bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) override {
-    Match(Call->getMethodDecl()->getQualifiedNameAsString(),
-          Call->getBeginLoc());
+    SmallString<128> QualifiedNameBuf;
+    {
+      llvm::raw_svector_ostream OS(QualifiedNameBuf);
+      Call->getMethodDecl()->printQualifiedName(OS);
+    }
+    Match(QualifiedNameBuf.str(), Call->getBeginLoc());
     return true;
   }
 };
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
index 9381a29f56f43..70902f3cdc797 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "clang/Sema/Lookup.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/Support/Error.h"
 #include <optional>
 
@@ -100,8 +101,8 @@ struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
 
   static char ID;
 
-  MissingDeclContext(DeclContext *context, std::string error)
-      : m_context(context), m_error(error) {}
+  MissingDeclContext(DeclContext *context, llvm::Twine error)
+      : m_context(context), m_error(error.str()) {}
 
   DeclContext *m_context;
   std::string m_error;
@@ -148,9 +149,14 @@ getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
       if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
         return DC->getPrimaryContext();
     }
+    SmallString<128> Msg;
+    {
+      llvm::raw_svector_ostream OS(Msg);
+      OS << "Couldn't find namespace ";
+      ns->printQualifiedName(OS);
+    }
     return llvm::make_error<MissingDeclContext>(
-        foreign_ctxt,
-        "Couldn't find namespace " + ns->getQualifiedNameAsString());
+        foreign_ctxt, "Couldn't find namespace " + Msg.str());
   }
 
   return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index b60f1d9e41958..92cb4c6faa6fd 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2950,9 +2950,14 @@ void DWARFASTParserClang::CreateStaticMemberVariable(
   llvm::Expected<llvm::APInt> const_value_or_err =
       ExtractIntFromFormValue(ct, *attrs.const_value_form);
   if (!const_value_or_err) {
+    clang::SmallString<128> QName;
+    {
+      llvm::raw_svector_ostream OS(QName);
+      v->printQualifiedName(OS);
+    }
     LLDB_LOG_ERROR(log, const_value_or_err.takeError(),
                    "Failed to add const value to variable {1}: {0}",
-                   v->getQualifiedNameAsString());
+                   QName.str());
     return;
   }
 
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
index 6d4af9ec6bf95..02b179ab08c35 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
@@ -1219,11 +1219,13 @@ PdbAstBuilderClang::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
   clang::DeclContext *parent = GetParentClangDeclContext(PdbSymUid(func_id));
   if (!parent)
     return nullptr;
-  std::string context_name;
-  if (clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(parent)) {
-    context_name = ns->getQualifiedNameAsString();
-  } else if (clang::TagDecl *tag = llvm::dyn_cast<clang::TagDecl>(parent)) {
-    context_name = tag->getQualifiedNameAsString();
+  clang::SmallString<128> context_name_buf;
+  if (const auto *parent_nd = llvm::dyn_cast<clang::NamedDecl>(parent)) {
+    if (llvm::isa<clang::NamespaceDecl>(parent) ||
+        llvm::isa<clang::TagDecl>(parent)) {
+      llvm::raw_svector_ostream OS(context_name_buf);
+      parent_nd->printQualifiedName(OS);
+    }
   }
 
   SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
@@ -1255,8 +1257,9 @@ PdbAstBuilderClang::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
   CompilerType func_ct = ToCompilerType(qt);
 
   llvm::StringRef proc_name = proc.Name;
-  if (!context_name.empty() && !(proc_name.consume_front(context_name) &&
-                                 proc_name.consume_front("::"))) {
+  if (!context_name_buf.empty() &&
+      !(proc_name.consume_front(context_name_buf) &&
+        proc_name.consume_front("::"))) {
     // If we have some context, but the function name doesn't start with it, use
     // the basename.
     MSVCUndecoratedNameParser parser(proc.Name);
@@ -1516,7 +1519,12 @@ void PdbAstBuilderClang::ParseNamespace(clang::DeclContext &context) {
   clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(&context);
   if (m_parsed_namespaces.contains(ns))
     return;
-  std::string qname = ns->getQualifiedNameAsString();
+  clang::SmallString<128> qname_buf;
+  {
+    llvm::raw_svector_ostream OS(qname_buf);
+    ns->printQualifiedName(OS);
+  }
+  llvm::StringRef qname = qname_buf.str();
   SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
       m_clang.GetSymbolFile()->GetBackingSymbolFile());
   PdbIndex &index = pdb->GetIndex();
diff --git a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp
index 61905ee8df862..609797e18cfb2 100644
--- a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp
+++ b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp
@@ -121,7 +121,14 @@ TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
   // Search and check that we found $persistent_class.
   decl_map->FindExternalVisibleDecls(search);
   EXPECT_EQ(1U, decls.size());
-  EXPECT_EQ(decl_name, decls.front()->getQualifiedNameAsString());
+
+  SmallString<128> QualifiedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(QualifiedNameBuf);
+    decls.front()->printQualifiedName(OS);
+  }
+  EXPECT_EQ(decl_name, QualifiedNameBuf.str());
+
   auto *record = llvm::cast<clang::RecordDecl>(decls.front());
   // The class was minimally imported from the scratch AST context.
   EXPECT_TRUE(record->hasExternalLexicalStorage());
diff --git a/lldb/unittests/Symbol/TestClangASTImporter.cpp b/lldb/unittests/Symbol/TestClangASTImporter.cpp
index 07c42088b9101..f1af97964f0c4 100644
--- a/lldb/unittests/Symbol/TestClangASTImporter.cpp
+++ b/lldb/unittests/Symbol/TestClangASTImporter.cpp
@@ -54,8 +54,21 @@ TEST_F(TestClangASTImporter, CopyDeclTagDecl) {
 
   // Check that we got the correct decl by just comparing their qualified name.
   clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
-  EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
-            imported_tag_decl->getQualifiedNameAsString());
+
+  SmallString<128> SourceNameBuf;
+  {
+    llvm::raw_svector_ostream OS(SourceNameBuf);
+    source.record_decl->printQualifiedName(OS);
+  }
+
+  SmallString<128> ImportedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(ImportedNameBuf);
+    imported_tag_decl->printQualifiedName(OS);
+  }
+
+  EXPECT_EQ(SourceNameBuf.str(), ImportedNameBuf.str());
+
   // We did a minimal import of the tag decl.
   EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
 
@@ -80,8 +93,21 @@ TEST_F(TestClangASTImporter, CopyTypeTagDecl) {
 
   // Check that we got the correct decl by just comparing their qualified name.
   clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
-  EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
-            imported_tag_decl->getQualifiedNameAsString());
+
+  SmallString<128> SourceNameBuf;
+  {
+    llvm::raw_svector_ostream OS(SourceNameBuf);
+    source.record_decl->printQualifiedName(OS);
+  }
+
+  SmallString<128> ImportedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(ImportedNameBuf);
+    imported_tag_decl->printQualifiedName(OS);
+  }
+
+  EXPECT_EQ(SourceNameBuf.str(), ImportedNameBuf.str());
+
   // We did a minimal import of the tag decl.
   EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
 
@@ -139,8 +165,21 @@ TEST_F(TestClangASTImporter, DeportDeclTagDecl) {
 
   // Check that we got the correct decl by just comparing their qualified name.
   clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
-  EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
-            imported_tag_decl->getQualifiedNameAsString());
+
+  SmallString<128> SourceNameBuf;
+  {
+    llvm::raw_svector_ostream OS(SourceNameBuf);
+    source.record_decl->printQualifiedName(OS);
+  }
+
+  SmallString<128> ImportedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(ImportedNameBuf);
+    imported_tag_decl->printQualifiedName(OS);
+  }
+
+  EXPECT_EQ(SourceNameBuf.str(), ImportedNameBuf.str());
+
   // The record should be completed as we deported it.
   EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
 
@@ -162,8 +201,21 @@ TEST_F(TestClangASTImporter, DeportTypeTagDecl) {
 
   // Check that we got the correct decl by just comparing their qualified name.
   clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
-  EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
-            imported_tag_decl->getQualifiedNameAsString());
+
+  SmallString<128> SourceNameBuf;
+  {
+    llvm::raw_svector_ostream OS(SourceNameBuf);
+    source.record_decl->printQualifiedName(OS);
+  }
+
+  SmallString<128> ImportedNameBuf;
+  {
+    llvm::raw_svector_ostream OS(ImportedNameBuf);
+    imported_tag_decl->printQualifiedName(OS);
+  }
+
+  EXPECT_EQ(SourceNameBuf.str(), ImportedNameBuf.str());
+
   // The record should be completed as we deported it.
   EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
 



More information about the cfe-commits mailing list