schroedersi updated this revision to Diff 104655.
schroedersi added a comment.

I forgot to add the previous changes in Diff 104649 
<https://reviews.llvm.org/differential/diff/104649/> (it only contains the 
incremental diff of the printing context changes). This diff contains all 
changes between trunk and the current patch state. I apologize!


https://reviews.llvm.org/D30946

Files:
  include/clang/AST/Decl.h
  include/clang/AST/DeclBase.h
  include/clang/AST/NestedNameSpecifier.h
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/TemplateBase.h
  include/clang/AST/TemplateName.h
  include/clang/AST/Type.h
  lib/AST/Decl.cpp
  lib/AST/DeclPrinter.cpp
  lib/AST/DeclarationName.cpp
  lib/AST/NestedNameSpecifier.cpp
  lib/AST/TemplateBase.cpp
  lib/AST/TemplateName.cpp
  lib/AST/TypePrinter.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/Tooling/Core/QualTypeNames.cpp
  test/CXX/class.access/p6.cpp
  test/Index/comment-cplus-decls.cpp
  unittests/AST/AbsoluteScopeTest.cpp
  unittests/AST/CMakeLists.txt
  unittests/AST/NamedDeclPrinterTest.cpp
  unittests/AST/TypePrinterTest.cpp

Index: unittests/AST/TypePrinterTest.cpp
===================================================================
--- /dev/null
+++ unittests/AST/TypePrinterTest.cpp
@@ -0,0 +1,464 @@
+//===- unittests/AST/TypePrinterTest.cpp ------ TypePrinter printer tests -===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for TypePrinter::print(...).
+//
+// These tests have a coding convention:
+// * variable whose type to be printed is named 'A' unless it should have some
+// special name
+// * additional helper classes/namespaces/... are 'Z', 'Y', 'X' and so on.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+namespace {
+
+class PrintMatch : public MatchFinder::MatchCallback {
+  SmallString<1024> Printed;
+  unsigned NumFoundDecls;
+  bool SuppressUnwrittenScope;
+  ScopePrintingKind::ScopePrintingKind Scope;
+
+public:
+  explicit PrintMatch(bool suppressUnwrittenScope,
+                      ScopePrintingKind::ScopePrintingKind scope)
+      : NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope),
+        Scope(scope) {}
+
+  void run(const MatchFinder::MatchResult &Result) override {
+    const ValueDecl *VD = Result.Nodes.getNodeAs<ValueDecl>("id");
+    if (!VD)
+      return;
+    NumFoundDecls++;
+    if (NumFoundDecls > 1)
+      return;
+
+    llvm::raw_svector_ostream Out(Printed);
+    PrintingPolicy Policy = Result.Context->getPrintingPolicy();
+    Policy.SuppressUnwrittenScope = SuppressUnwrittenScope;
+    Policy.Scope = Scope;
+    QualType Type = VD->getType();
+    Type.print(Out, Policy);
+  }
+
+  StringRef getPrinted() const { return Printed; }
+
+  unsigned getNumFoundDecls() const { return NumFoundDecls; }
+};
+
+::testing::AssertionResult
+PrintedTypeMatches(StringRef Code, const std::vector<std::string> &Args,
+                   bool SuppressUnwrittenScope,
+                   const DeclarationMatcher &NodeMatch,
+                   StringRef ExpectedPrinted, StringRef FileName,
+                   ScopePrintingKind::ScopePrintingKind Scope) {
+  PrintMatch Printer(SuppressUnwrittenScope, Scope);
+  MatchFinder Finder;
+  Finder.addMatcher(NodeMatch, &Printer);
+  std::unique_ptr<FrontendActionFactory> Factory =
+      newFrontendActionFactory(&Finder);
+
+  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
+    return testing::AssertionFailure()
+           << "Parsing error in \"" << Code.str() << "\"";
+
+  if (Printer.getNumFoundDecls() == 0)
+    return testing::AssertionFailure()
+           << "Matcher didn't find any value declarations";
+
+  if (Printer.getNumFoundDecls() > 1)
+    return testing::AssertionFailure()
+           << "Matcher should match only one value declaration "
+              "(found "
+           << Printer.getNumFoundDecls() << ")";
+
+  if (Printer.getPrinted() != ExpectedPrinted)
+    return ::testing::AssertionFailure()
+           << "Expected \"" << ExpectedPrinted.str()
+           << "\", "
+              "got \""
+           << Printer.getPrinted().str() << "\"";
+
+  return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult
+PrintedTypeCXX11MatchesWrapper(StringRef Code, StringRef DeclName,
+                               StringRef ExpectedPrinted,
+                               ScopePrintingKind::ScopePrintingKind Scope) {
+  std::vector<std::string> Args(1, "-std=c++11");
+  return PrintedTypeMatches(Code, Args,
+                            /*SuppressUnwrittenScope*/ true,
+                            valueDecl(hasName(DeclName)).bind("id"),
+                            ExpectedPrinted, "input.cc", Scope);
+}
+
+::testing::AssertionResult
+PrintedTypeCXX11Matches(StringRef Code, StringRef DeclName,
+                        StringRef ExpectedPrintedAllScopes,
+                        StringRef ExpectedPrintedScopesAsWritten,
+                        StringRef ExpectedPrintedNoScopes) {
+  std::vector<std::string> Args(1, "-std=c++11");
+
+  // Scope == FullScope
+  ::testing::AssertionResult result = PrintedTypeCXX11MatchesWrapper(
+      Code, DeclName, ExpectedPrintedAllScopes, ScopePrintingKind::FullScope);
+  if (!result.operator bool()) {
+    return result << ", with: FullScope";
+  }
+
+  // TODO: Activate this as soon as something similar to ScopeAsWritten is
+  // implemented.
+  //  // Scope == ScopeAsWritten
+  //  result =
+  //      PrintedTypeCXX11MatchesWrapper(Code, DeclName,
+  //                                     ExpectedPrintedScopesAsWritten,
+  //                                     ScopePrintingKind::ScopeAsWritten);
+  //  if(!result.operator bool()) {
+  //    return result << ", with: ScopeAsWritten";
+  //  }
+
+  // Scope == SuppressScope
+  result =
+      PrintedTypeCXX11MatchesWrapper(Code, DeclName, ExpectedPrintedNoScopes,
+                                     ScopePrintingKind::SuppressScope);
+  if (!result.operator bool()) {
+    return result << ", with: SuppressScope";
+  }
+
+  return ::testing::AssertionSuccess();
+}
+
+} // unnamed namespace
+
+TEST(TypePrinter, UnwrittenScope) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W { };"
+        "}"
+        "W A;"
+      "}"
+    "}",
+    "A",
+    "::Z::Y::W",
+    "W",
+    "W"));
+}
+
+TEST(TypePrinter, UnwrittenScopeWithTag) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "class W { };"
+      "namespace Z {"
+        "class W { };"
+        "namespace Y {"
+          "class W { };"
+          "namespace X {"
+            "class W { };"
+          "}"
+          "class W A;"
+        "}"
+      "}",
+      "A",
+      "class ::Z::Y::W",
+      "class W",
+      "class W"));
+}
+
+TEST(TypePrinter, WrittenScopeAbsolute1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W { };"
+        "}"
+        "::Z::Y::W A;"
+      "}"
+    "}",
+    "A",
+    "::Z::Y::W",
+    "::Z::Y::W",
+    "W"));
+}
+
+TEST(TypePrinter, WrittenScopeAbsolute2) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W { };"
+        "}"
+        "::W A;"
+      "}"
+    "}",
+    "A",
+    "::W",
+    "::W",
+    "W"));
+}
+
+TEST(TypePrinter, WrittenScopeNonAbsolute1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W { };"
+        "}"
+        "X::W A;"
+      "}"
+    "}",
+    "A",
+    "::Z::Y::X::W",
+    "X::W",
+    "W"));
+}
+
+TEST(TypePrinter, WrittenScopeNonAbsolute2) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W { };"
+        "}"
+        "Z::Y::X::W A;"
+      "}"
+    "}",
+    "A",
+    "::Z::Y::X::W",
+    "Z::Y::X::W",
+    "W"));
+}
+
+TEST(TypePrinter, WrittenScopeNonAbsolute3) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W {"
+            "Z::W (*A)(W);"
+          "};"
+        "}"
+      "}"
+    "}",
+    "A",
+    "::Z::W (*)(::Z::Y::X::W)",
+    "Z::W (*)(W)",
+    "W (*)(W)"));
+}
+
+TEST(TypePrinter, WrittenScopeNonAbsoluteNested1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "class W { };"
+    "namespace Z {"
+      "class W { };"
+      "namespace Y {"
+        "class W { };"
+        "namespace X {"
+          "class W { };"
+        "}"
+        "::W (*(Z::W::* A)(void (W::*)(X::W, W, ::Z::W, int, void (Y::W::*)(int))))();"
+      "}"
+    "}",
+    "A",
+    "::W (*(::Z::W::*)(void (::Z::Y::W::*)(::Z::Y::X::W, ::Z::Y::W, ::Z::W, int, void (::Z::Y::W::*)(int))))()",
+    //FIXME: The written scope of a member pointer seems not to be in the AST:
+    "::W (*("/*Z::*/"W::*)(void (W::*)(X::W, W, ::Z::W, int, void ("/*Y::*/"W::*)(int))))()",
+    "W (*(W::*)(void (W::*)(W, W, W, int, void (W::*)(int))))()"));
+}
+
+
+TEST(TypePrinter, TemplClassWithSimpleTemplArg) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "namespace Z { template <typename T> class X { }; class Y { };"
+      "X<Y> A;"
+    "}",
+    "A",
+    "::Z::X< ::Z::Y>",
+    "X<Y>",
+    "X<Y>"));
+}
+
+TEST(TypePrinter, TemplClassWithTemplClassTemplArg1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+    "namespace Z { template <typename T> class X { public: template <typename T2, typename T3> class Y { }; };"
+      "namespace W { namespace V { class U { }; } }"
+      "X< X<bool>::Y<int, W::V::U> > A;"
+    "}",
+    "A",
+    "::Z::X< ::Z::X<bool>::Y<int, ::Z::W::V::U> >",
+    "X<X<bool>::Y<int, W::V::U> >",
+    "X<Y<int, U> >"));
+}
+
+TEST(TypePrinter, TypeDef1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "class W { };"
+      "namespace Z {"
+        "namespace Y {"
+          "class W { };"
+          "namespace X {"
+            "class W {"
+              "public:"
+              "class V { };"
+            "};"
+          "}"
+          "typedef X::W WT1;"
+        "}"
+        "class W { };"
+        "typedef Y::WT1 WT2;"
+        "WT2::V A;"
+      "}",
+      "A",
+      "::Z::WT2::V",
+      "WT2::V",
+      "V"));
+}
+
+TEST(TypePrinter, TypeDef2) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "class W { };"
+      "namespace Z {"
+        "namespace Y {"
+          "class W { };"
+          "namespace X {"
+            "class W {"
+              "public:"
+              "class V { };"
+            "};"
+          "}"
+          "typedef X::W WT1;"
+        "}"
+        "class W { };"
+        "typedef Y::WT1 WT2;"
+        "WT2 A;"
+      "}",
+      "A",
+      "::Z::WT2",
+      "WT2",
+      "WT2"));
+}
+
+
+TEST(TypePrinter, TypeDef3) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "class W { };"
+      "namespace Z {"
+        "namespace Y {"
+          "class W { };"
+            "namespace X {"
+            "class W {"
+              "public:"
+              "class V { };"
+              "typedef V VT1;"
+            "};"
+          "}"
+          "typedef X::W WT1;"
+        "}"
+        "class W { };"
+        "Y::WT1::VT1 A;"
+      "}",
+      "A",
+      "::Z::Y::WT1::VT1",
+      "Y::WT1::VT1",
+      "VT1"));
+}
+
+TEST(TypePrinter, AnonymousNamespace1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "namespace Z {"
+        "namespace {"
+          "namespace {"
+            "namespace Y {"
+              "namespace {"
+                "class X { };"
+              "}"
+              "X A;"
+            "}"
+          "}"
+        "}"
+      "}",
+      "A",
+      "::Z::Y::X",
+      "X",
+      "X"));
+}
+
+// Template dependent type: Printing of absolute scope not possible.
+TEST(TypePrinter, TemplateDependent1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "template <typename U, typename Y>"
+      "struct Z : public Y {"
+        "template<typename X> struct V {"
+          "class W { };"
+          "typename Y::template V<X>::W A;"
+        "};"
+      "};",
+      "A",
+      "typename Y::template V<X>::W",
+      "typename Y::template V<X>::W",
+      "typename W"));
+}
+
+TEST(TypePrinter, TemplateDependent2) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "template <typename U, typename Y>"
+      "struct Z : public Y {"
+        "template<typename X> struct V {"
+          "class W { };"
+          "V<X>::W A;"
+        "};"
+      "};",
+      "A",
+      "::Z::V<X>::W",
+      "V<X>::W",
+      "W"));
+}
+
+
+// Local class: Printing of absolute scope not possible.
+TEST(TypePrinter, LocalClasses1) {
+  ASSERT_TRUE(PrintedTypeCXX11Matches(
+      "void f() {"
+        "class Z {"
+          "public: class Y { };"
+        "};"
+        "Z::Y A;"
+      "}",
+      "A",
+      "Z::Y", // TODO: or "::f()::Z::Y"?
+      "Z::Y",
+      "Y"));
+}
Index: unittests/AST/NamedDeclPrinterTest.cpp
===================================================================
--- unittests/AST/NamedDeclPrinterTest.cpp
+++ unittests/AST/NamedDeclPrinterTest.cpp
@@ -32,10 +32,12 @@
   SmallString<1024> Printed;
   unsigned NumFoundDecls;
   bool SuppressUnwrittenScope;
+  bool MakeAbsolute;
 
 public:
-  explicit PrintMatch(bool suppressUnwrittenScope)
-    : NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope) {}
+  explicit PrintMatch(bool suppressUnwrittenScope, bool makeAbsolute)
+      : NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope),
+        MakeAbsolute(makeAbsolute) {}
 
   void run(const MatchFinder::MatchResult &Result) override {
     const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");
@@ -48,6 +50,8 @@
     llvm::raw_svector_ostream Out(Printed);
     PrintingPolicy Policy = Result.Context->getPrintingPolicy();
     Policy.SuppressUnwrittenScope = SuppressUnwrittenScope;
+    Policy.Scope = MakeAbsolute ? ScopePrintingKind::FullScope
+                                : ScopePrintingKind::DefaultScope;
     ND->printQualifiedName(Out, Policy);
   }
 
@@ -60,12 +64,11 @@
   }
 };
 
-::testing::AssertionResult
-PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
-                        bool SuppressUnwrittenScope,
-                        const DeclarationMatcher &NodeMatch,
-                        StringRef ExpectedPrinted, StringRef FileName) {
-  PrintMatch Printer(SuppressUnwrittenScope);
+::testing::AssertionResult PrintedNamedDeclMatches(
+    StringRef Code, const std::vector<std::string> &Args,
+    bool SuppressUnwrittenScope, const DeclarationMatcher &NodeMatch,
+    StringRef ExpectedPrinted, StringRef FileName, bool MakeAbsolute) {
+  PrintMatch Printer(SuppressUnwrittenScope, MakeAbsolute);
   MatchFinder Finder;
   Finder.addMatcher(NodeMatch, &Printer);
   std::unique_ptr<FrontendActionFactory> Factory =
@@ -94,26 +97,24 @@
 
 ::testing::AssertionResult
 PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName,
-                             StringRef ExpectedPrinted) {
+                             StringRef ExpectedPrinted,
+                             bool MakeAbsolute = false) {
   std::vector<std::string> Args(1, "-std=c++98");
-  return PrintedNamedDeclMatches(Code,
-                                 Args,
+  return PrintedNamedDeclMatches(Code, Args,
                                  /*SuppressUnwrittenScope*/ false,
                                  namedDecl(hasName(DeclName)).bind("id"),
-                                 ExpectedPrinted,
-                                 "input.cc");
+                                 ExpectedPrinted, "input.cc", MakeAbsolute);
 }
 
 ::testing::AssertionResult
 PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName,
-                                    StringRef ExpectedPrinted) {
+                                    StringRef ExpectedPrinted,
+                                    bool MakeAbsolute = false) {
   std::vector<std::string> Args(1, "-std=c++11");
-  return PrintedNamedDeclMatches(Code,
-                                 Args,
+  return PrintedNamedDeclMatches(Code, Args,
                                  /*SuppressUnwrittenScope*/ true,
                                  namedDecl(hasName(DeclName)).bind("id"),
-                                 ExpectedPrinted,
-                                 "input.cc");
+                                 ExpectedPrinted, "input.cc", MakeAbsolute);
 }
 
 } // unnamed namespace
@@ -125,27 +126,59 @@
     "(anonymous namespace)::A"));
 }
 
+TEST(NamedDeclPrinter, TestNamespace1Absolute) {
+  ASSERT_TRUE(PrintedNamedDeclCXX98Matches(
+    "namespace { int A; }",
+    "A",
+    "::(anonymous namespace)::A",
+    true));
+}
+
 TEST(NamedDeclPrinter, TestNamespace2) {
   ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
     "inline namespace Z { namespace { int A; } }",
     "A",
     "A"));
 }
 
+TEST(NamedDeclPrinter, TestNamespace2Absolute) {
+  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
+    "inline namespace Z { namespace { int A; } }",
+    "A",
+    "::A",
+    true));
+}
+
 TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) {
   ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
     "enum { A };",
     "A",
     "A"));
 }
 
+TEST(NamedDeclPrinter, TestUnscopedUnnamedEnumAbsolute) {
+  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
+    "enum { A };",
+    "A",
+    "::A",
+    true));
+}
+
 TEST(NamedDeclPrinter, TestNamedEnum) {
   ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
     "enum X { A };",
     "A",
     "X::A"));
 }
 
+TEST(NamedDeclPrinter, TestNamedEnumAbsolute) {
+  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
+    "enum X { A };",
+    "A",
+    "::X::A",
+    true));
+}
+
 TEST(NamedDeclPrinter, TestScopedNamedEnum) {
   ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
     "enum class X { A };",
@@ -167,9 +200,33 @@
     "X::Y::A"));
 }
 
+TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnumAbsolute) {
+  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
+    "class X { enum Y { A }; };",
+    "A",
+    "::X::Y::A",
+    true));
+}
+
 TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) {
   ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
     "class X { enum class Y { A }; };",
     "A",
     "X::Y::A"));
 }
+
+TEST(NamedDeclPrinter, TestClassWithScopedNamedEnumAbsolute) {
+  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
+    "class X { enum class Y { A }; };",
+    "A",
+    "::X::Y::A",
+    true));
+}
+
+TEST(NamedDeclPrinter, TestLocalClass) {
+  ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
+      "class X { void f() { enum class Y { A }; } };",
+      "A",
+      "::X::f()::Y::A",
+      true));
+}
Index: unittests/AST/CMakeLists.txt
===================================================================
--- unittests/AST/CMakeLists.txt
+++ unittests/AST/CMakeLists.txt
@@ -3,6 +3,7 @@
   )
 
 add_clang_unittest(ASTTests
+  AbsoluteScopeTest.cpp
   ASTContextParentMapTest.cpp
   ASTImporterTest.cpp
   ASTTypeTraitsTest.cpp
@@ -17,6 +18,7 @@
   PostOrderASTVisitor.cpp
   SourceLocationTest.cpp
   StmtPrinterTest.cpp
+  TypePrinterTest.cpp
   )
 
 target_link_libraries(ASTTests
Index: unittests/AST/AbsoluteScopeTest.cpp
===================================================================
--- /dev/null
+++ unittests/AST/AbsoluteScopeTest.cpp
@@ -0,0 +1,218 @@
+//===- unittests/AST/AbsoluteScopeTest.cpp - absolute scope printing test -===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains tests for ScopePrintingKind::FullScope. In each test,
+// code is rewritten by changing the type of a variable declaration to
+// another class or function type. Without printing the full scopes the
+// resulting code would be ill-formed.
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+class DeclASTVisitor : public RecursiveASTVisitor<DeclASTVisitor>,
+                       public ASTConsumer {
+  StringRef VarDeclName;
+  StringRef DeclNameOfNewType;
+  unsigned int NumFoundVarDecls;
+  unsigned int NumFoundDeclsOfNewtype;
+  const VarDecl *FoundVarDecl;
+  QualType FoundNewType;
+
+public:
+  DeclASTVisitor(StringRef declName, StringRef namedDeclNameOfNewType)
+      : VarDeclName(declName), DeclNameOfNewType(namedDeclNameOfNewType),
+        NumFoundVarDecls(0), NumFoundDeclsOfNewtype(0) {}
+
+  // Look for the variable declaration described by the given name:
+  bool VisitVarDecl(VarDecl *VD) {
+    if (VD->getNameAsString() == VarDeclName) {
+      NumFoundVarDecls++;
+      FoundVarDecl = VD;
+    }
+    return true;
+  }
+
+  // Look for the declaration described by the given name and store the type.
+  bool VisitTypeDecl(TypeDecl *TD) {
+    if (TD->getNameAsString() == DeclNameOfNewType) {
+      NumFoundDeclsOfNewtype++;
+      FoundNewType = QualType(TD->getTypeForDecl(), 0);
+    }
+    return true;
+  }
+  // ... also accept value declarations (e.g. functions) because they have a
+  // type too
+  bool VisitValueDecl(ValueDecl *VD) {
+    if (VD->getNameAsString() == DeclNameOfNewType) {
+      NumFoundDeclsOfNewtype++;
+      FoundNewType = VD->getType();
+    }
+    return true;
+  }
+
+  virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
+    for (DeclGroupRef::iterator i = DR.begin(), e = DR.end(); i != e; ++i) {
+      TraverseDecl(*i);
+    }
+    return true;
+  }
+
+  unsigned int getNumFoundVarDecls() const { return NumFoundVarDecls; }
+
+  unsigned int getNumFoundDeclsOfNewType() const {
+    return NumFoundDeclsOfNewtype;
+  }
+
+  const VarDecl *getFoundVarDecl() const { return FoundVarDecl; }
+
+  QualType getFoundNewType() const { return FoundNewType; }
+};
+
+::testing::AssertionResult ChangeTypeOfDeclaration(StringRef Code,
+                                                   StringRef VarDeclName,
+                                                   StringRef DeclNameOfNewType,
+                                                   bool CPP11 = true) {
+  CompilerInstance compilerInstance;
+  compilerInstance.createDiagnostics();
+
+  LangOptions &lo = compilerInstance.getLangOpts();
+  lo.CPlusPlus = 1;
+  if (CPP11) {
+    lo.CPlusPlus11 = 1;
+  }
+
+  auto TO = std::make_shared<TargetOptions>();
+  TO->Triple = llvm::sys::getDefaultTargetTriple();
+  TargetInfo *TI =
+      TargetInfo::CreateTargetInfo(compilerInstance.getDiagnostics(), TO);
+  compilerInstance.setTarget(TI);
+
+  compilerInstance.createFileManager();
+  compilerInstance.createSourceManager(compilerInstance.getFileManager());
+  SourceManager &sourceManager = compilerInstance.getSourceManager();
+  compilerInstance.createPreprocessor(TU_Module);
+  compilerInstance.createASTContext();
+
+  // Set the main file handled by the source manager to the input code:
+  std::unique_ptr<llvm::MemoryBuffer> mb(
+      llvm::MemoryBuffer::getMemBufferCopy(Code, "input.cc"));
+  sourceManager.setMainFileID(sourceManager.createFileID(std::move(mb)));
+  compilerInstance.getDiagnosticClient().BeginSourceFile(
+      compilerInstance.getLangOpts(), &compilerInstance.getPreprocessor());
+
+  // Create the declaration visitor:
+  DeclASTVisitor declVisitor(VarDeclName, DeclNameOfNewType);
+
+  // Parse the code:
+  ParseAST(compilerInstance.getPreprocessor(), &declVisitor,
+           compilerInstance.getASTContext());
+
+  // Evaluate the result of the AST traverse:
+  if (declVisitor.getNumFoundVarDecls() != 1) {
+    return testing::AssertionFailure()
+           << "Expected exactly one variable declaration with the name \""
+           << VarDeclName << "\" but " << declVisitor.getNumFoundVarDecls()
+           << " were found";
+  }
+  if (declVisitor.getNumFoundDeclsOfNewType() != 1) {
+    return testing::AssertionFailure()
+           << "Expected exactly one declaration with the name \""
+           << DeclNameOfNewType << "\" but "
+           << declVisitor.getNumFoundDeclsOfNewType() << " were found";
+  }
+
+  // Found information on the basis of which the transformation will take place:
+  const VarDecl *foundVarDecl = declVisitor.getFoundVarDecl();
+  QualType foundNewType = declVisitor.getFoundNewType();
+
+  Rewriter rewriter;
+  rewriter.setSourceMgr(sourceManager, compilerInstance.getLangOpts());
+
+  // Create declaration with the old name and the new type:
+  std::string newDeclText;
+  llvm::raw_string_ostream newDeclTextStream(newDeclText);
+  PrintingPolicy policy = foundVarDecl->getASTContext().getPrintingPolicy();
+  policy.PolishForDeclaration = true;
+  // The important flag:
+  policy.Scope = ScopePrintingKind::FullScope;
+  foundNewType.print(newDeclTextStream, policy, VarDeclName);
+
+  // Replace the old declaration placeholder with the new declaration:
+  rewriter.ReplaceText(foundVarDecl->getSourceRange(), newDeclTextStream.str());
+
+  const RewriteBuffer *rewriteBuffer =
+      rewriter.getRewriteBufferFor(sourceManager.getMainFileID());
+  if (!rewriteBuffer) {
+    return testing::AssertionFailure() << "No changes have been made";
+  } else {
+    // Check whether the transformed/rewritten code is valid:
+    std::unique_ptr<FrontendActionFactory> Factory =
+        newFrontendActionFactory<SyntaxOnlyAction>();
+    std::vector<std::string> args(1, "-std=c++11");
+    std::string rewrittenCode =
+        std::string(rewriteBuffer->begin(), rewriteBuffer->end());
+    if (!runToolOnCodeWithArgs(Factory->create(), rewrittenCode, args,
+                               "input.cc")) {
+      return testing::AssertionFailure()
+             << "Parsing error in rewritten code \"" << rewrittenCode << "\"";
+    } else {
+      return testing::AssertionSuccess();
+    }
+  }
+}
+
+} // unnamed namespace
+
+TEST(AbsoluteScope, Test01) {
+  ASSERT_TRUE(ChangeTypeOfDeclaration("namespace Z {"
+                                      "  namespace Z { }"
+                                      "  namespace Y {"
+                                      "    class X3 { };"
+                                      "  }"
+                                      "  int A;"
+                                      "}",
+                                      "A", "X3"));
+}
+
+TEST(AbsoluteScope, Test02) {
+  ASSERT_TRUE(ChangeTypeOfDeclaration("namespace Z {"
+                                      "  namespace Y {"
+                                      "    class X3 { };"
+                                      "    void F(X3) { }"
+                                      "  }"
+                                      "  namespace Z {"
+                                      "    namespace Z { }"
+                                      "    int A;"
+                                      "  }"
+                                      "}",
+                                      "A", "F"));
+}
Index: test/Index/comment-cplus-decls.cpp
===================================================================
--- test/Index/comment-cplus-decls.cpp
+++ test/Index/comment-cplus-decls.cpp
@@ -149,7 +149,7 @@
   };
 }
 // CHECK: <Declaration>void f(const T &amp;t = T())</Declaration>
-// CHECK: <Declaration>friend void vector&lt;A&gt;::f(const test3::A &amp;)</Declaration>
+// CHECK: <Declaration>friend void vector&lt;test3::A&gt;::f(const test3::A &amp;)</Declaration>
 
 class MyClass
 {
Index: test/CXX/class.access/p6.cpp
===================================================================
--- test/CXX/class.access/p6.cpp
+++ test/CXX/class.access/p6.cpp
@@ -92,7 +92,7 @@
 
   template <class T> class Outer::A<T, typename T::nature> {
   public:
-    static void foo(); // expected-note {{'Outer::A<B, Green>::foo' declared here}}
+    static void foo(); // expected-note {{'Outer::A<test3::B, test3::Green>::foo' declared here}}
   };
 
   class B {
@@ -102,7 +102,38 @@
 
   void test() {
     Outer::A<B, Green>::foo();
-    Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo' in 'test3::Outer::A<test3::B, test3::Blue>'; did you mean 'Outer::A<B, Green>::foo'?}}
+    Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo' in 'test3::Outer::A<test3::B, test3::Blue>'; did you mean 'Outer::A<test3::B, test3::Green>::foo'?}}
+  }
+}
+
+// Modified version of test3 showing that inner scopes of a nested name specifier are necessary to create a valid suggestion.
+namespace test3_1 {
+
+  namespace Colors {
+    class Green { };
+    class Blue { };
+  }
+
+  // We have to wrap this in a class because a partial specialization
+  // isn't actually in the context of the template.
+  struct Outer {
+    template <class T, class Nat> class A {
+    };
+  };
+
+  template <class T> class Outer::A<T, typename T::nature> {
+  public:
+    static void foo(); // expected-note {{'Outer::A<test3_1::B, test3_1::Colors::Green>::foo' declared here}}
+  };
+
+  class B {
+  private: typedef Colors::Green nature;
+    friend class Outer;
+  };
+
+  void test() {
+    Outer::A<B, Colors::Green>::foo();
+    Outer::A<B, Colors::Blue>::foo(); // expected-error {{no member named 'foo' in 'test3_1::Outer::A<test3_1::B, test3_1::Colors::Blue>'; did you mean 'Outer::A<test3_1::B, test3_1::Colors::Green>::foo'?}}
   }
 }
 
Index: lib/Tooling/Core/QualTypeNames.cpp
===================================================================
--- lib/Tooling/Core/QualTypeNames.cpp
+++ lib/Tooling/Core/QualTypeNames.cpp
@@ -465,7 +465,7 @@
                                   const ASTContext &Ctx,
                                   bool WithGlobalNsPrefix) {
   PrintingPolicy Policy(Ctx.getPrintingPolicy());
-  Policy.SuppressScope = false;
+  Policy.Scope = ScopePrintingKind::DefaultScope;
   Policy.AnonymousTagLocations = false;
   Policy.PolishForDeclaration = true;
   Policy.SuppressUnwrittenScope = true;
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -909,8 +909,7 @@
 
   SmallString<128> NS;
   llvm::raw_svector_ostream OS(NS);
-  Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(),
-                              /*qualified*/ false);
+  Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy());
 
   TemplateSpecializationType::PrintTemplateArgumentList(
       OS, Ty->template_arguments(),
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -26,23 +26,21 @@
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
-namespace {
-  /// \brief RAII object that enables printing of the ARC __strong lifetime
-  /// qualifier.
-  class IncludeStrongLifetimeRAII {
-    PrintingPolicy &Policy;
-    bool Old;
-    
-  public:
-    explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy) 
+namespace clang {
+/// \brief RAII object that enables printing of the ARC __strong lifetime
+/// qualifier.
+class IncludeStrongLifetimeRAII {
+  PrintingPolicy &Policy;
+  bool Old;
+
+public:
+  explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
       : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
-        if (!Policy.SuppressLifetimeQualifiers)
-          Policy.SuppressStrongLifetime = false;
-    }
-    
-    ~IncludeStrongLifetimeRAII() {
-      Policy.SuppressStrongLifetime = Old;
-    }
+    if (!Policy.SuppressLifetimeQualifiers)
+      Policy.SuppressStrongLifetime = false;
+  }
+
+  ~IncludeStrongLifetimeRAII() { Policy.SuppressStrongLifetime = Old; }
   };
 
   class ParamPolicyRAII {
@@ -63,32 +61,30 @@
   class ElaboratedTypePolicyRAII {
     PrintingPolicy &Policy;
     bool SuppressTagKeyword;
-    bool SuppressScope;
     
   public:
     explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
       SuppressTagKeyword = Policy.SuppressTagKeyword;
-      SuppressScope = Policy.SuppressScope;
       Policy.SuppressTagKeyword = true;
-      Policy.SuppressScope = true;
     }
     
     ~ElaboratedTypePolicyRAII() {
       Policy.SuppressTagKeyword = SuppressTagKeyword;
-      Policy.SuppressScope = SuppressScope;
     }
   };
   
   class TypePrinter {
     PrintingPolicy Policy;
+    PrintingContext Context;
     unsigned Indentation;
     bool HasEmptyPlaceHolder;
     bool InsideCCAttribute;
 
   public:
-    explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0)
-      : Policy(Policy), Indentation(Indentation),
-        HasEmptyPlaceHolder(false), InsideCCAttribute(false) { }
+    explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0,
+                         PrintingContext Context = PrintingContext())
+        : Policy(Policy), Context(Context), Indentation(Indentation),
+          HasEmptyPlaceHolder(false), InsideCCAttribute(false) {}
 
     void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
                StringRef PlaceHolder);
@@ -417,7 +413,8 @@
 
   PrintingPolicy InnerPolicy(Policy);
   InnerPolicy.IncludeTagDefinition = false;
-  TypePrinter(InnerPolicy).print(QualType(T->getClass(), 0), OS, StringRef());
+  TypePrinter(InnerPolicy, 0, Context)
+      .print(QualType(T->getClass(), 0), OS, StringRef());
 
   OS << "::*";
 }
@@ -592,21 +589,20 @@
   OS << ")))";
 }
 
-void 
-FunctionProtoType::printExceptionSpecification(raw_ostream &OS, 
-                                               const PrintingPolicy &Policy)
-                                                                         const {
-  
+void FunctionProtoType::printExceptionSpecification(
+    raw_ostream &OS, const PrintingPolicy &Policy,
+    PrintingContext Context) const {
+
   if (hasDynamicExceptionSpec()) {
     OS << " throw(";
     if (getExceptionSpecType() == EST_MSAny)
       OS << "...";
     else
       for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
         if (I)
           OS << ", ";
-        
-        OS << getExceptionType(I).stream(Policy);
+
+        OS << getExceptionType(I).stream(Policy, Twine(), 0, Context);
       }
     OS << ')';
   } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
@@ -770,7 +766,7 @@
     OS << " &&";
     break;
   }
-  T->printExceptionSpecification(OS, Policy);
+  T->printExceptionSpecification(OS, Policy, Context);
 
   if (T->hasTrailingReturn()) {
     OS << " -> ";
@@ -801,13 +797,11 @@
 }
 
 void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) {
-
-  // Compute the full nested-name-specifier for this type.
-  // In C, this will always be empty except when the type
-  // being printed is anonymous within other Record.
-  if (!Policy.SuppressScope)
+  if (Policy.Scope != ScopePrintingKind::SuppressScope &&
+      !Context.TemporarySuppressScope) {
+    // Print the scope:
     AppendScope(D->getDeclContext(), OS);
-
+  }
   IdentifierInfo *II = D->getIdentifier();
   OS << II->getName();
   spaceBeforePlaceHolder(OS);
@@ -820,10 +814,10 @@
 void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T,
                                              raw_ostream &OS) { }
 
-void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { 
+void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) {
   printTypeSpec(T->getDecl(), OS);
 }
-void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) { } 
+void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {}
 
 void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
                                         raw_ostream &OS) {
@@ -905,7 +899,7 @@
     printBefore(T->getDeducedType(), OS);
   } else {
     IncludeStrongLifetimeRAII Strong(Policy);
-    T->getTemplateName().print(OS, Policy);
+    T->getTemplateName().print(OS, Policy, Context);
     spaceBeforePlaceHolder(OS);
   }
 }
@@ -942,7 +936,12 @@
 }
 /// Appends the given scope to the end of a string.
 void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
-  if (DC->isTranslationUnit()) return;
+  if (DC->isTranslationUnit()) {
+    if (Policy.Scope == ScopePrintingKind::FullScope) {
+      OS << "::";
+    }
+    return;
+  }
   if (DC->isFunctionOrMethod()) return;
   AppendScope(DC->getParent(), OS);
 
@@ -960,7 +959,7 @@
     OS << Spec->getIdentifier()->getName();
     const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
     TemplateSpecializationType::PrintTemplateArgumentList(
-        OS, TemplateArgs.asArray(), Policy);
+        OS, TemplateArgs.asArray(), Policy, false, Context);
     OS << "::";
   } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
     if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl())
@@ -976,7 +975,7 @@
   if (Policy.IncludeTagDefinition) {
     PrintingPolicy SubPolicy = Policy;
     SubPolicy.IncludeTagDefinition = false;
-    D->print(OS, SubPolicy, Indentation);
+    D->print(OS, SubPolicy, Indentation, false, Context);
     spaceBeforePlaceHolder(OS);
     return;
   }
@@ -994,7 +993,8 @@
   // Compute the full nested-name-specifier for this type.
   // In C, this will always be empty except when the type
   // being printed is anonymous within other Record.
-  if (!Policy.SuppressScope)
+  if (Policy.Scope != ScopePrintingKind::SuppressScope &&
+      !Context.TemporarySuppressScope)
     AppendScope(D->getDeclContext(), OS);
 
   if (const IdentifierInfo *II = D->getIdentifier())
@@ -1033,6 +1033,8 @@
     OS << (Policy.MSVCFormatting ? '\'' : ')');
   }
 
+  Context.TemporarySuppressScope = false;
+
   // If this is a class template specialization, print the template
   // arguments.
   if (ClassTemplateSpecializationDecl *Spec
@@ -1047,7 +1049,8 @@
       Args = TemplateArgs.asArray();
     }
     IncludeStrongLifetimeRAII Strong(Policy);
-    TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, Policy);
+    TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, Policy,
+                                                          false, Context);
   }
 
   spaceBeforePlaceHolder(OS);
@@ -1101,13 +1104,14 @@
 }
 
 void TypePrinter::printTemplateSpecializationBefore(
-                                            const TemplateSpecializationType *T, 
-                                            raw_ostream &OS) { 
+    const TemplateSpecializationType *T, raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
-  T->getTemplateName().print(OS, Policy);
+  T->getTemplateName().print(OS, Policy, Context);
+
+  Context.TemporarySuppressScope = false;
 
   TemplateSpecializationType::PrintTemplateArgumentList(
-      OS, T->template_arguments(), Policy);
+      OS, T->template_arguments(), Policy, false, Context);
   spaceBeforePlaceHolder(OS);
 }
 void TypePrinter::printTemplateSpecializationAfter(
@@ -1123,17 +1127,35 @@
 
 void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
                                         raw_ostream &OS) {
+  bool ScopeHasBeenPrinted = false;
   // The tag definition will take care of these.
-  if (!Policy.IncludeTagDefinition)
-  {
+  if (!Policy.IncludeTagDefinition) {
     OS << TypeWithKeyword::getKeywordName(T->getKeyword());
     if (T->getKeyword() != ETK_None)
       OS << " ";
-    NestedNameSpecifier* Qualifier = T->getQualifier();
-    if (Qualifier)
-      Qualifier->print(OS, Policy);
+    NestedNameSpecifier *Qualifier = T->getQualifier();
+    if (Qualifier) {
+      Qualifier->print(OS, Policy, Context);
+      ScopeHasBeenPrinted = true;
+    }
+    // If there are no nested name specifiers, the complete scope will be
+    // printed later (location depends on the sub-type).
   }
-  
+
+  // Currently the following sub-types are known:
+  if (!isa<TagType>(T->getNamedType()) &&
+      !isa<TemplateSpecializationType>(T->getNamedType()) &&
+      !isa<TypedefType>(T->getNamedType()) &&
+      !isa<DeducedTemplateSpecializationType>(T->getNamedType())) {
+    llvm::errs() << "Unknown elaborated sub-type: "
+                 << T->getNamedType()->getTypeClassName() << "\n";
+    llvm_unreachable("Unknown elaborated sub-type (see error output)");
+  }
+
+  // Suppress the outer nested name specifier of the underlying type in case
+  // of DefaultScope and if a scope has already been printed.
+  Context.TemporarySuppressScope =
+      Policy.Scope == ScopePrintingKind::DefaultScope || ScopeHasBeenPrinted;
   ElaboratedTypePolicyRAII PolicyRAII(Policy);
   printBefore(T->getNamedType(), OS);
 }
@@ -1163,9 +1185,8 @@
   OS << TypeWithKeyword::getKeywordName(T->getKeyword());
   if (T->getKeyword() != ETK_None)
     OS << " ";
-  
-  T->getQualifier()->print(OS, Policy);
-  
+  T->getQualifier()->print(OS, Policy, Context);
+
   OS << T->getIdentifier()->getName();
   spaceBeforePlaceHolder(OS);
 }
@@ -1179,13 +1200,15 @@
   OS << TypeWithKeyword::getKeywordName(T->getKeyword());
   if (T->getKeyword() != ETK_None)
     OS << " ";
-  
+
   if (T->getQualifier())
-    T->getQualifier()->print(OS, Policy);    
+    T->getQualifier()->print(OS, Policy, Context);
   OS << T->getIdentifier()->getName();
-  TemplateSpecializationType::PrintTemplateArgumentList(OS,
-                                                        T->template_arguments(),
-                                                        Policy);
+
+  Context.TemporarySuppressScope = false;
+
+  TemplateSpecializationType::PrintTemplateArgumentList(
+      OS, T->template_arguments(), Policy, false, Context);
   spaceBeforePlaceHolder(OS);
 }
 void TypePrinter::printDependentTemplateSpecializationAfter(
@@ -1489,18 +1512,17 @@
 void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, 
                                               raw_ostream &OS) { }
 
-void TemplateSpecializationType::
-  PrintTemplateArgumentList(raw_ostream &OS,
-                            const TemplateArgumentListInfo &Args,
-                            const PrintingPolicy &Policy) {
-  return PrintTemplateArgumentList(OS,
-                                   Args.arguments(),
-                                   Policy);
+void TemplateSpecializationType::PrintTemplateArgumentList(
+    raw_ostream &OS, const TemplateArgumentListInfo &Args,
+    const PrintingPolicy &Policy, PrintingContext Context) {
+  return PrintTemplateArgumentList(OS, Args.arguments(), Policy, Context);
 }
 
 void TemplateSpecializationType::PrintTemplateArgumentList(
     raw_ostream &OS, ArrayRef<TemplateArgument> Args,
-    const PrintingPolicy &Policy, bool SkipBrackets) {
+    const PrintingPolicy &Policy, bool SkipBrackets, PrintingContext Context) {
+  assert(!Context.TemporarySuppressScope &&
+         "Suppressing the scope of each argument is not supported.");
   const char *Comma = Policy.MSVCFormatting ? "," : ", ";
   if (!SkipBrackets)
     OS << '<';
@@ -1514,13 +1536,12 @@
     if (Arg.getKind() == TemplateArgument::Pack) {
       if (Arg.pack_size() && !FirstArg)
         OS << Comma;
-      PrintTemplateArgumentList(ArgOS,
-                                Arg.getPackAsArray(),
-                                Policy, true);
+      PrintTemplateArgumentList(ArgOS, Arg.getPackAsArray(), Policy, true,
+                                Context);
     } else {
       if (!FirstArg)
         OS << Comma;
-      Arg.print(Policy, ArgOS);
+      Arg.print(Policy, ArgOS, Context);
     }
     StringRef ArgString = ArgOS.str();
 
@@ -1547,10 +1568,9 @@
 }
 
 // Sadly, repeat all that with TemplateArgLoc.
-void TemplateSpecializationType::
-PrintTemplateArgumentList(raw_ostream &OS,
-                          ArrayRef<TemplateArgumentLoc> Args,
-                          const PrintingPolicy &Policy) {
+void TemplateSpecializationType::PrintTemplateArgumentList(
+    raw_ostream &OS, ArrayRef<TemplateArgumentLoc> Args,
+    const PrintingPolicy &Policy, PrintingContext Context) {
   OS << '<';
   const char *Comma = Policy.MSVCFormatting ? "," : ", ";
 
@@ -1564,11 +1584,10 @@
     SmallString<128> Buf;
     llvm::raw_svector_ostream ArgOS(Buf);
     if (Arg.getArgument().getKind() == TemplateArgument::Pack) {
-      PrintTemplateArgumentList(ArgOS,
-                                Arg.getArgument().getPackAsArray(),
-                                Policy, true);
+      PrintTemplateArgumentList(ArgOS, Arg.getArgument().getPackAsArray(),
+                                Policy, true, Context);
     } else {
-      Arg.getArgument().print(Policy, ArgOS);
+      Arg.getArgument().print(Policy, ArgOS, Context);
     }
     StringRef ArgString = ArgOS.str();
 
@@ -1720,13 +1739,13 @@
   return buffer;
 }
 
-void QualType::print(const Type *ty, Qualifiers qs,
-                     raw_ostream &OS, const PrintingPolicy &policy,
-                     const Twine &PlaceHolder, unsigned Indentation) {
+void QualType::print(const Type *ty, Qualifiers qs, raw_ostream &OS,
+                     const PrintingPolicy &policy, const Twine &PlaceHolder,
+                     unsigned Indentation, PrintingContext Context) {
   SmallString<128> PHBuf;
   StringRef PH = PlaceHolder.toStringRef(PHBuf);
 
-  TypePrinter(policy, Indentation).print(ty, qs, OS, PH);
+  TypePrinter(policy, Indentation, Context).print(ty, qs, OS, PH);
 }
 
 void QualType::getAsStringInternal(const Type *ty, Qualifiers qs,
Index: lib/AST/TemplateName.cpp
===================================================================
--- lib/AST/TemplateName.cpp
+++ lib/AST/TemplateName.cpp
@@ -174,29 +174,33 @@
   return getAsSubstTemplateTemplateParmPack() != nullptr;
 }
 
-void
-TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
-                    bool SuppressNNS) const {
-  if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
-    OS << *Template;
-  else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
-    if (!SuppressNNS)
-      QTN->getQualifier()->print(OS, Policy);
+void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
+                         PrintingContext Context) const {
+  if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) {
+    if (Policy.Scope == ScopePrintingKind::FullScope &&
+        !Context.TemporarySuppressScope) {
+      Template->printQualifiedName(OS, Policy, Context);
+    } else {
+      OS << *Template;
+    }
+  } else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
+    if (!Context.TemporarySuppressScope)
+      QTN->getQualifier()->print(OS, Policy, Context);
     if (QTN->hasTemplateKeyword())
       OS << "template ";
     OS << *QTN->getDecl();
   } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
-    if (!SuppressNNS && DTN->getQualifier())
-      DTN->getQualifier()->print(OS, Policy);
+    if (!Context.TemporarySuppressScope && DTN->getQualifier())
+      DTN->getQualifier()->print(OS, Policy, Context);
     OS << "template ";
     
     if (DTN->isIdentifier())
       OS << DTN->getIdentifier()->getName();
     else
       OS << "operator " << getOperatorSpelling(DTN->getOperator());
   } else if (SubstTemplateTemplateParmStorage *subst
                = getAsSubstTemplateTemplateParm()) {
-    subst->getReplacement().print(OS, Policy, SuppressNNS);
+    subst->getReplacement().print(OS, Policy);
   } else if (SubstTemplateTemplateParmPackStorage *SubstPack
                                         = getAsSubstTemplateTemplateParmPack())
     OS << *SubstPack->getParameterPack();
Index: lib/AST/TemplateBase.cpp
===================================================================
--- lib/AST/TemplateBase.cpp
+++ lib/AST/TemplateBase.cpp
@@ -35,8 +35,9 @@
 /// \param Out the raw_ostream instance to use for printing.
 ///
 /// \param Policy the printing policy for EnumConstantDecl printing.
-static void printIntegral(const TemplateArgument &TemplArg,
-                          raw_ostream &Out, const PrintingPolicy& Policy) {
+static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out,
+                          const PrintingPolicy &Policy,
+                          PrintingContext Context = PrintingContext()) {
   const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr();
   const llvm::APSInt &Val = TemplArg.getAsIntegral();
 
@@ -47,7 +48,7 @@
       // may create a size difference between the enum value and template
       // argument value, requiring isSameValue here instead of operator==.
       if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) {
-        ECD->printQualifiedName(Out, Policy);
+        ECD->printQualifiedName(Out, Policy, Context);
         return;
       }
     }
@@ -376,26 +377,26 @@
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
 
-void TemplateArgument::print(const PrintingPolicy &Policy, 
-                             raw_ostream &Out) const {
+void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
+                             PrintingContext Context) const {
   switch (getKind()) {
   case Null:
     Out << "(no value)";
     break;
     
   case Type: {
     PrintingPolicy SubPolicy(Policy);
     SubPolicy.SuppressStrongLifetime = true;
-    getAsType().print(Out, SubPolicy);
+    getAsType().print(Out, SubPolicy, Twine(), 0, Context);
     break;
   }
     
   case Declaration: {
     NamedDecl *ND = cast<NamedDecl>(getAsDecl());
     Out << '&';
     if (ND->getDeclName()) {
       // FIXME: distinguish between pointer and reference args?
-      ND->printQualifiedName(Out);
+      ND->printQualifiedName(Out, Context);
     } else {
       Out << "(anonymous)";
     }
@@ -407,16 +408,16 @@
     break;
 
   case Template:
-    getAsTemplate().print(Out, Policy);
+    getAsTemplate().print(Out, Policy, Context);
     break;
 
   case TemplateExpansion:
-    getAsTemplateOrTemplatePattern().print(Out, Policy);
+    getAsTemplateOrTemplatePattern().print(Out, Policy, Context);
     Out << "...";
     break;
       
   case Integral: {
-    printIntegral(*this, Out, Policy);
+    printIntegral(*this, Out, Policy, Context);
     break;
   }
     
@@ -432,8 +433,8 @@
         First = false;
       else
         Out << ", ";
-      
-      P.print(Policy, Out);
+
+      P.print(Policy, Out, Context);
     }
     Out << ">";
     break;        
Index: lib/AST/NestedNameSpecifier.cpp
===================================================================
--- lib/AST/NestedNameSpecifier.cpp
+++ lib/AST/NestedNameSpecifier.cpp
@@ -258,25 +258,55 @@
 
 /// \brief Print this nested name specifier to the given output
 /// stream.
-void
-NestedNameSpecifier::print(raw_ostream &OS,
-                           const PrintingPolicy &Policy) const {
+void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
+                                PrintingContext Context) const {
+  if (Policy.Scope == ScopePrintingKind::SuppressScope ||
+      Context.TemporarySuppressScope) {
+    return;
+  }
+
+  // Nested name specifiers describe the scope as written in the source code.
+  // Thus these specifier may not contain the full scope if parts of the scope
+  // were not written in the source code. If IncludeUnwrittenScopes is set to
+  // true the parts of the scope that were not written in the source code are
+  // printed.
+  bool IncludeUnwrittenScopes = false;
+
   if (getPrefix())
     getPrefix()->print(OS, Policy);
+  else if (Policy.Scope == ScopePrintingKind::FullScope &&
+           getKind() != NestedNameSpecifier::Global) {
+    // If this is the first written nested name specifier and it is not the
+    // global scope specifier then maybe not all scopes have been written in the
+    // source code ("maybe" because sometimes is not possible to write an
+    // absolute scope e.g. dependent names or local classes). Try to include the
+    // unwritten scopes if the printing of all scopes is requested:
+    IncludeUnwrittenScopes = true;
+  }
 
   switch (getKind()) {
   case Identifier:
     OS << getAsIdentifier()->getName();
     break;
 
   case Namespace:
+    if (IncludeUnwrittenScopes) {
+      getAsNamespace()->printQualifiedName(OS, Policy);
+      break;
+    }
+
     if (getAsNamespace()->isAnonymousNamespace())
       return;
-      
+
     OS << getAsNamespace()->getName();
     break;
 
   case NamespaceAlias:
+    if (IncludeUnwrittenScopes) {
+      getAsNamespaceAlias()->getNamespace()->printQualifiedName(OS, Policy);
+      break;
+    }
+
     OS << getAsNamespaceAlias()->getName();
     break;
 
@@ -295,31 +325,20 @@
   case TypeSpec: {
     const Type *T = getAsType();
 
-    PrintingPolicy InnerPolicy(Policy);
-    InnerPolicy.SuppressScope = true;
+    if (IncludeUnwrittenScopes) {
+      QualType(T, 0).print(OS, Policy);
+      break;
+    }
 
     // Nested-name-specifiers are intended to contain minimally-qualified
     // types. An actual ElaboratedType will not occur, since we'll store
     // just the type that is referred to in the nested-name-specifier (e.g.,
     // a TypedefType, TagType, etc.). However, when we are dealing with
     // dependent template-id types (e.g., Outer<T>::template Inner<U>),
     // the type requires its own nested-name-specifier for uniqueness, so we
     // suppress that nested-name-specifier during printing.
-    assert(!isa<ElaboratedType>(T) &&
-           "Elaborated type in nested-name-specifier");
-    if (const TemplateSpecializationType *SpecType
-          = dyn_cast<TemplateSpecializationType>(T)) {
-      // Print the template name without its corresponding
-      // nested-name-specifier.
-      SpecType->getTemplateName().print(OS, InnerPolicy, true);
-
-      // Print the template argument list.
-      TemplateSpecializationType::PrintTemplateArgumentList(
-          OS, SpecType->template_arguments(), InnerPolicy);
-    } else {
-      // Print the type normally
-      QualType(T, 0).print(OS, InnerPolicy);
-    }
+    Context.TemporarySuppressScope = true;
+    QualType(T, 0).print(OS, Policy, Twine(), 0, Context);
     break;
   }
   }
Index: lib/AST/DeclarationName.cpp
===================================================================
--- lib/AST/DeclarationName.cpp
+++ lib/AST/DeclarationName.cpp
@@ -653,15 +653,18 @@
   case DeclarationName::CXXDestructorName:
   case DeclarationName::CXXConversionFunctionName:
     if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) {
-      if (Name.getNameKind() == DeclarationName::CXXDestructorName)
-        OS << '~';
-      else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
-        OS << "operator ";
       LangOptions LO;
       LO.CPlusPlus = true;
       LO.Bool = true;
       PrintingPolicy PP(LO);
-      PP.SuppressScope = true;
+      PP.Scope = ScopePrintingKind::SuppressScope;
+      if (Name.getNameKind() == DeclarationName::CXXDestructorName)
+        OS << '~';
+      else if (Name.getNameKind() ==
+               DeclarationName::CXXConversionFunctionName) {
+        OS << "operator ";
+        PP.Scope = ScopePrintingKind::DefaultScope;
+      }
       OS << TInfo->getType().getAsString(PP);
     } else
       OS << Name;
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -28,6 +28,7 @@
   class DeclPrinter : public DeclVisitor<DeclPrinter> {
     raw_ostream &Out;
     PrintingPolicy Policy;
+    PrintingContext Context;
     unsigned Indentation;
     bool PrintInstantiation;
 
@@ -48,9 +49,10 @@
 
   public:
     DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
-                unsigned Indentation = 0, bool PrintInstantiation = false)
-      : Out(Out), Policy(Policy), Indentation(Indentation),
-        PrintInstantiation(PrintInstantiation) { }
+                unsigned Indentation = 0, bool PrintInstantiation = false,
+                PrintingContext Context = PrintingContext())
+        : Out(Out), Policy(Policy), Context(Context), Indentation(Indentation),
+          PrintInstantiation(PrintInstantiation) {}
 
     void VisitDeclContext(DeclContext *DC, bool Indent = true);
 
@@ -114,8 +116,9 @@
 }
 
 void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy,
-                 unsigned Indentation, bool PrintInstantiation) const {
-  DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation);
+                 unsigned Indentation, bool PrintInstantiation,
+                 PrintingContext Context) const {
+  DeclPrinter Printer(Out, Policy, Indentation, PrintInstantiation, Context);
   Printer.Visit(const_cast<Decl*>(this));
 }
 
@@ -510,7 +513,7 @@
   PrintingPolicy SubPolicy(Policy);
   SubPolicy.SuppressSpecifiers = false;
   std::string Proto;
-  if (!Policy.SuppressScope) {
+  if (Policy.Scope != ScopePrintingKind::SuppressScope) {
     if (const NestedNameSpecifier *NS = D->getQualifier()) {
       llvm::raw_string_ostream OS(Proto);
       NS->print(OS, Policy);
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1404,12 +1404,13 @@
   return OS.str();
 }
 
-void NamedDecl::printQualifiedName(raw_ostream &OS) const {
-  printQualifiedName(OS, getASTContext().getPrintingPolicy());
+void NamedDecl::printQualifiedName(raw_ostream &OS,
+                                   PrintingContext Context) const {
+  printQualifiedName(OS, getASTContext().getPrintingPolicy(), Context);
 }
 
-void NamedDecl::printQualifiedName(raw_ostream &OS,
-                                   const PrintingPolicy &P) const {
+void NamedDecl::printQualifiedName(raw_ostream &OS, const PrintingPolicy &P,
+                                   PrintingContext Context) const {
   const DeclContext *Ctx = getDeclContext();
 
   // For ObjC methods, look through categories and use the interface as context.
@@ -1425,10 +1426,18 @@
   typedef SmallVector<const DeclContext *, 8> ContextsTy;
   ContextsTy Contexts;
 
-  // Collect contexts.
-  while (Ctx && isa<NamedDecl>(Ctx)) {
-    Contexts.push_back(Ctx);
-    Ctx = Ctx->getParent();
+  if (P.Scope != ScopePrintingKind::SuppressScope &&
+      !Context.TemporarySuppressScope) {
+    // Collect contexts.
+    while (Ctx && isa<NamedDecl>(Ctx)) {
+      Contexts.push_back(Ctx);
+      Ctx = Ctx->getParent();
+    }
+
+    if (P.Scope == ScopePrintingKind::FullScope) {
+      // Add global scope specifier up front
+      OS << "::";
+    }
   }
 
   for (const DeclContext *DC : reverse(Contexts)) {
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -18,6 +18,7 @@
 #define LLVM_CLANG_AST_TYPE_H
 
 #include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/Diagnostic.h"
@@ -950,19 +951,21 @@
   std::string getAsString(const PrintingPolicy &Policy) const;
 
   void print(raw_ostream &OS, const PrintingPolicy &Policy,
-             const Twine &PlaceHolder = Twine(),
-             unsigned Indentation = 0) const {
-    print(split(), OS, Policy, PlaceHolder, Indentation);
+             const Twine &PlaceHolder = Twine(), unsigned Indentation = 0,
+             PrintingContext Context = PrintingContext()) const {
+    print(split(), OS, Policy, PlaceHolder, Indentation, Context);
   }
   static void print(SplitQualType split, raw_ostream &OS,
                     const PrintingPolicy &policy, const Twine &PlaceHolder,
-                    unsigned Indentation = 0) {
-    return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation);
+                    unsigned Indentation = 0,
+                    PrintingContext Context = PrintingContext()) {
+    return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation,
+                 Context);
   }
-  static void print(const Type *ty, Qualifiers qs,
-                    raw_ostream &OS, const PrintingPolicy &policy,
-                    const Twine &PlaceHolder,
-                    unsigned Indentation = 0);
+  static void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
+                    const PrintingPolicy &policy, const Twine &PlaceHolder,
+                    unsigned Indentation = 0,
+                    PrintingContext Context = PrintingContext());
 
   void getAsStringInternal(std::string &Str,
                            const PrintingPolicy &Policy) const {
@@ -979,25 +982,30 @@
   class StreamedQualTypeHelper {
     const QualType &T;
     const PrintingPolicy &Policy;
+    PrintingContext Context;
     const Twine &PlaceHolder;
     unsigned Indentation;
   public:
     StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy,
-                           const Twine &PlaceHolder, unsigned Indentation)
-      : T(T), Policy(Policy), PlaceHolder(PlaceHolder),
-        Indentation(Indentation) { }
+                           const Twine &PlaceHolder, unsigned Indentation,
+                           PrintingContext Context = PrintingContext())
+        : T(T), Policy(Policy), Context(Context), PlaceHolder(PlaceHolder),
+          Indentation(Indentation) {}
 
     friend raw_ostream &operator<<(raw_ostream &OS,
                                    const StreamedQualTypeHelper &SQT) {
-      SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation);
+      SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation,
+                  SQT.Context);
       return OS;
     }
   };
 
-  StreamedQualTypeHelper stream(const PrintingPolicy &Policy,
-                                const Twine &PlaceHolder = Twine(),
-                                unsigned Indentation = 0) const {
-    return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation);
+  StreamedQualTypeHelper
+  stream(const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(),
+         unsigned Indentation = 0,
+         PrintingContext Context = PrintingContext()) const {
+    return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation,
+                                  Context);
   }
 
   void dump(const char *s) const;
@@ -3527,8 +3535,9 @@
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
-  void printExceptionSpecification(raw_ostream &OS,
-                                   const PrintingPolicy &Policy) const;
+  void printExceptionSpecification(
+      raw_ostream &OS, const PrintingPolicy &Policy,
+      PrintingContext Context = PrintingContext()) const;
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == FunctionProto;
@@ -4328,18 +4337,21 @@
 
   /// \brief Print a template argument list, including the '<' and '>'
   /// enclosing the template arguments.
-  static void PrintTemplateArgumentList(raw_ostream &OS,
-                                        ArrayRef<TemplateArgument> Args,
-                                        const PrintingPolicy &Policy,
-                                        bool SkipBrackets = false);
-
-  static void PrintTemplateArgumentList(raw_ostream &OS,
-                                        ArrayRef<TemplateArgumentLoc> Args,
-                                        const PrintingPolicy &Policy);
-
-  static void PrintTemplateArgumentList(raw_ostream &OS,
-                                        const TemplateArgumentListInfo &,
-                                        const PrintingPolicy &Policy);
+  static void
+  PrintTemplateArgumentList(raw_ostream &OS, ArrayRef<TemplateArgument> Args,
+                            const PrintingPolicy &Policy,
+                            bool SkipBrackets = false,
+                            PrintingContext Context = PrintingContext());
+
+  static void
+  PrintTemplateArgumentList(raw_ostream &OS, ArrayRef<TemplateArgumentLoc> Args,
+                            const PrintingPolicy &Policy,
+                            PrintingContext Context = PrintingContext());
+
+  static void
+  PrintTemplateArgumentList(raw_ostream &OS, const TemplateArgumentListInfo &,
+                            const PrintingPolicy &Policy,
+                            PrintingContext Context = PrintingContext());
 
   /// True if this template specialization type matches a current
   /// instantiation in the context in which it is found.
Index: include/clang/AST/TemplateName.h
===================================================================
--- include/clang/AST/TemplateName.h
+++ include/clang/AST/TemplateName.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_AST_TEMPLATENAME_H
 
 #include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerUnion.h"
@@ -277,12 +278,8 @@
   ///
   /// \param OS the output stream to which the template name will be
   /// printed.
-  ///
-  /// \param SuppressNNS if true, don't print the
-  /// nested-name-specifier that precedes the template name (if it has
-  /// one).
   void print(raw_ostream &OS, const PrintingPolicy &Policy,
-             bool SuppressNNS = false) const;
+             PrintingContext Context = PrintingContext()) const;
 
   /// \brief Debugging aid that dumps the template name.
   void dump(raw_ostream &OS) const;
Index: include/clang/AST/TemplateBase.h
===================================================================
--- include/clang/AST/TemplateBase.h
+++ include/clang/AST/TemplateBase.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CLANG_AST_TEMPLATEBASE_H
 #define LLVM_CLANG_AST_TEMPLATEBASE_H
 
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/APSInt.h"
@@ -353,8 +354,9 @@
   TemplateArgument getPackExpansionPattern() const;
 
   /// \brief Print this template argument to the given output stream.
-  void print(const PrintingPolicy &Policy, raw_ostream &Out) const;
-             
+  void print(const PrintingPolicy &Policy, raw_ostream &Out,
+             PrintingContext Context = PrintingContext()) const;
+
   /// \brief Debugging aid that dumps the template argument.
   void dump(raw_ostream &Out) const;
 
Index: include/clang/AST/PrettyPrinter.h
===================================================================
--- include/clang/AST/PrettyPrinter.h
+++ include/clang/AST/PrettyPrinter.h
@@ -30,27 +30,94 @@
   virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0;
 };
 
-/// \brief Describes how types, statements, expressions, and
-/// declarations should be printed.
+// namespace with enum (instead of enum class) to avoid
+// 'PrintingPolicy::Scope' is too small to hold all values of
+// 'ScopePrintingKind' warnings.
+namespace ScopePrintingKind {
+enum ScopePrintingKind {
+  /// \brief Print all nested name specifiers (including the global scope
+  /// specifier). This is necessary if a printed non-absolute scope would not
+  /// select the desired scope.
+  ///
+  /// Example: Consider the following code:
+  /// \code
+  /// namespace Z {
+  ///   namespace Z {
+  ///     namespace Y {
+  ///       class X { }; // (1)
+  ///     }
+  ///   }
+  ///   namespace Y {
+  ///     class X { }; // (2)
+  ///   }
+  ///   // (3)
+  /// }
+  /// \endcode
+  /// Printing type ::Z::Y::X (marked with (2)) without FullScope results in
+  /// "Z::Y::X". If this is used at the position marked with (3), it
+  /// will select the wrong type ::Z::Z::Y::X (marked with (1)). With FullScope
+  /// the result is "::Z::Y::X" and the correct type is selected.
+  ///
+  /// Please note that in some cases it is not possible to print the full scope.
+  /// For example in case of a local class or a dependent name.
+  FullScope,
+
+  /// \brief In case of an elaborated type print the outer scope as written in
+  /// the source. (If there is a tag keyword and no scope in the source then no
+  /// scope is printed.)
+  /// Otherwise print the full scope but without the global scope specifier.
+  ///
+  /// This distinction is made for inner scopes recursively.
+  DefaultScope,
+
+  /// \brief Do not print any scope.
+  SuppressScope
+};
+}
+
+/// \brief Provides a context for one printing process. This should be used for
+/// mutable information that need to be shared across the member functions
+/// involved in the printing process of types and declarations.
+struct PrintingContext {
+  /// \brief Creates a default printing context.
+  PrintingContext() : TemporarySuppressScope(false) {}
+
+  /// \brief When true, suppress printing of current outer scope. For example
+  /// with TemporarySuppressScope set to true "::A::B::C<D::E, ::F>" ist
+  /// printed as "C<D::E, ::F>". This is currently only supported in some cases
+  /// and is only used internally.
+  bool TemporarySuppressScope : 1;
+};
+
+/// \brief Describes how types, statements, expressions, and declarations should
+/// be printed.
+///
+/// This should not be mutated during the printing process. Use PrintingContext
+/// for mutable information instead.
 ///
 /// This type is intended to be small and suitable for passing by value.
 /// It is very frequently copied.
 struct PrintingPolicy {
+  friend class TypePrinter;
+  friend class NestedNameSpecifier;
+  friend class TemplateName;
+  friend class ElaboratedTypePolicyRAII;
+  friend class NamedDecl;
+
   /// \brief Create a default printing policy for the specified language.
   PrintingPolicy(const LangOptions &LO)
-    : Indentation(2), SuppressSpecifiers(false),
-      SuppressTagKeyword(LO.CPlusPlus),
-      IncludeTagDefinition(false), SuppressScope(false),
-      SuppressUnwrittenScope(false), SuppressInitializers(false),
-      ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
-      SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
-      SuppressTemplateArgsInCXXConstructors(false),
-      Bool(LO.Bool), Restrict(LO.C99),
-      Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11),
-      UseVoidForZeroParams(!LO.CPlusPlus),
-      TerseOutput(false), PolishForDeclaration(false),
-      Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
-      IncludeNewlines(true), MSVCFormatting(false) { }
+      : Indentation(2), SuppressSpecifiers(false),
+        SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
+        Scope(ScopePrintingKind::DefaultScope), SuppressUnwrittenScope(false),
+        SuppressInitializers(false), ConstantArraySizeAsWritten(false),
+        AnonymousTagLocations(true), SuppressStrongLifetime(false),
+        SuppressLifetimeQualifiers(false),
+        SuppressTemplateArgsInCXXConstructors(false), Bool(LO.Bool),
+        Restrict(LO.C99), Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11),
+        UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false),
+        PolishForDeclaration(false), Half(LO.Half),
+        MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
+        MSVCFormatting(false) {}
 
   /// \brief Adjust this printing policy for cases where it's known that
   /// we're printing C++ code (for instance, if AST dumping reaches a
@@ -101,13 +168,14 @@
   /// \endcode
   bool IncludeTagDefinition : 1;
 
-  /// \brief Suppresses printing of scope specifiers.
-  bool SuppressScope : 1;
+  /// \brief Specifies whether the scope should be printed, and if so, how
+  /// detailed.
+  ScopePrintingKind::ScopePrintingKind Scope : 2;
 
   /// \brief Suppress printing parts of scope specifiers that don't need
   /// to be written, e.g., for inline or anonymous namespaces.
   bool SuppressUnwrittenScope : 1;
-  
+
   /// \brief Suppress printing of variable initializers.
   ///
   /// This flag is used when printing the loop variable in a for-range
@@ -138,16 +206,16 @@
   /// char a[9] = "A string";
   /// \endcode
   bool ConstantArraySizeAsWritten : 1;
-  
+
   /// \brief When printing an anonymous tag name, also print the location of
-  /// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just 
+  /// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just
   /// prints "(anonymous)" for the name.
   bool AnonymousTagLocations : 1;
-  
+
   /// \brief When true, suppress printing of the __strong lifetime qualifier in
   /// ARC.
   unsigned SuppressStrongLifetime : 1;
-  
+
   /// \brief When true, suppress printing of lifetime qualifier in
   /// ARC.
   unsigned SuppressLifetimeQualifiers : 1;
@@ -179,7 +247,7 @@
   /// declarations inside namespaces etc.  Effectively, this should print
   /// only the requested declaration.
   unsigned TerseOutput : 1;
-  
+
   /// \brief When true, do certain refinement needed for producing proper
   /// declaration tag; such as, do not print attributes attached to the declaration.
   ///
Index: include/clang/AST/NestedNameSpecifier.h
===================================================================
--- include/clang/AST/NestedNameSpecifier.h
+++ include/clang/AST/NestedNameSpecifier.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
 #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
 
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerIntPair.h"
@@ -208,7 +209,8 @@
 
   /// \brief Print this nested name specifier to the given output
   /// stream.
-  void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
+  void print(raw_ostream &OS, const PrintingPolicy &Policy,
+             PrintingContext Context = PrintingContext()) const;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddPointer(Prefix.getOpaqueValue());
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -16,6 +16,7 @@
 
 #include "clang/AST/AttrIterator.h"
 #include "clang/AST/DeclarationName.h"
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/VersionTuple.h"
 #include "llvm/ADT/PointerUnion.h"
@@ -1090,7 +1091,8 @@
   void print(raw_ostream &Out, unsigned Indentation = 0,
              bool PrintInstantiation = false) const;
   void print(raw_ostream &Out, const PrintingPolicy &Policy,
-             unsigned Indentation = 0, bool PrintInstantiation = false) const;
+             unsigned Indentation = 0, bool PrintInstantiation = false,
+             PrintingContext Context = PrintingContext()) const;
   static void printGroup(Decl** Begin, unsigned NumDecls,
                          raw_ostream &Out, const PrintingPolicy &Policy,
                          unsigned Indentation = 0);
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -18,6 +18,7 @@
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/Redeclarable.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/Linkage.h"
@@ -27,8 +28,8 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/TrailingObjects.h"
+#include "llvm/Support/raw_ostream.h"
 
 namespace clang {
 struct ASTTemplateArgumentListInfo;
@@ -266,8 +267,10 @@
   /// namespace), it will return same result as printName().
   /// Creating this name is expensive, so it should be called only when
   /// performance doesn't matter.
-  void printQualifiedName(raw_ostream &OS) const;
-  void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const;
+  void printQualifiedName(raw_ostream &OS,
+                          PrintingContext Context = PrintingContext()) const;
+  void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy,
+                          PrintingContext Context = PrintingContext()) const;
 
   // FIXME: Remove string version.
   std::string getQualifiedNameAsString() const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D30946: [... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D309... Simon Schroeder via Phabricator via cfe-commits
    • [PATCH] D309... Simon Schroeder via Phabricator via cfe-commits
    • [PATCH] D309... Simon Schroeder via Phabricator via cfe-commits
    • [PATCH] D309... Simon Schroeder via Phabricator via cfe-commits

Reply via email to