schroedersi created this revision.
Herald added subscribers: mgorny, klimek.

PrintingPolicy::SuppressScope was replaced by PrintingPolicy::Scope. Possible
values for PrintingPolicy::Scope are:

- FullScope: 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:

  namespace Z { namespace Z { namespace Y { class X { }; // (1) } } namespace Y 
{ class X { }; // (2) } // (3) }

  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.
- DefaultScope: This corresponds to the previous behavior with 
SuppressScope==false: 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.
- SuppressScope: Do not print any scope.


https://reviews.llvm.org/D30946

Files:
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/TemplateName.h
  lib/AST/Decl.cpp
  lib/AST/NestedNameSpecifier.cpp
  lib/AST/TemplateName.cpp
  lib/AST/TypePrinter.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/Tooling/Core/QualTypeNames.cpp
  test/CXX/class.access/p6.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,471 @@
+//===- 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);
   }
 
@@ -64,8 +68,9 @@
 PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
                         bool SuppressUnwrittenScope,
                         const DeclarationMatcher &NodeMatch,
-                        StringRef ExpectedPrinted, StringRef FileName) {
-  PrintMatch Printer(SuppressUnwrittenScope);
+                        StringRef ExpectedPrinted, StringRef FileName,
+                        bool MakeAbsolute) {
+  PrintMatch Printer(SuppressUnwrittenScope, MakeAbsolute);
   MatchFinder Finder;
   Finder.addMatcher(NodeMatch, &Printer);
   std::unique_ptr<FrontendActionFactory> Factory =
@@ -94,26 +99,30 @@
 
 ::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,
                                  /*SuppressUnwrittenScope*/ false,
                                  namedDecl(hasName(DeclName)).bind("id"),
                                  ExpectedPrinted,
-                                 "input.cc");
+                                 "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,
                                  /*SuppressUnwrittenScope*/ true,
                                  namedDecl(hasName(DeclName)).bind("id"),
                                  ExpectedPrinted,
-                                 "input.cc");
+                                 "input.cc",
+                                 MakeAbsolute);
 }
 
 } // unnamed namespace
@@ -125,27 +134,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 +208,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/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
@@ -907,8 +907,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,7 +26,7 @@
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
-namespace {
+namespace clang {
   /// \brief RAII object that enables printing of the ARC __strong lifetime
   /// qualifier.
   class IncludeStrongLifetimeRAII {
@@ -63,19 +63,19 @@
   class ElaboratedTypePolicyRAII {
     PrintingPolicy &Policy;
     bool SuppressTagKeyword;
-    bool SuppressScope;
     
   public:
-    explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
+    explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy,
+                                      bool TemporarySuppressScope = true)
+        : Policy(Policy) {
       SuppressTagKeyword = Policy.SuppressTagKeyword;
-      SuppressScope = Policy.SuppressScope;
       Policy.SuppressTagKeyword = true;
-      Policy.SuppressScope = true;
+      Policy.TemporarySuppressScope = TemporarySuppressScope;
     }
     
     ~ElaboratedTypePolicyRAII() {
       Policy.SuppressTagKeyword = SuppressTagKeyword;
-      Policy.SuppressScope = SuppressScope;
+      Policy.TemporarySuppressScope = false;
     }
   };
   
@@ -799,13 +799,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 &&
+     !Policy.TemporarySuppressScope) {
+    // Print the scope:
     AppendScope(D->getDeclContext(), OS);
-
+  }
   IdentifierInfo *II = D->getIdentifier();
   OS << II->getName();
   spaceBeforePlaceHolder(OS);
@@ -818,10 +816,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) {
@@ -940,7 +938,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);
 
@@ -992,7 +995,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 &&
+      !Policy.TemporarySuppressScope)
     AppendScope(D->getDeclContext(), OS);
 
   if (const IdentifierInfo *II = D->getIdentifier())
@@ -1031,6 +1035,8 @@
     OS << (Policy.MSVCFormatting ? '\'' : ')');
   }
 
+  Policy.TemporarySuppressScope = false;
+
   // If this is a class template specialization, print the template
   // arguments.
   if (ClassTemplateSpecializationDecl *Spec
@@ -1100,10 +1106,12 @@
 
 void TypePrinter::printTemplateSpecializationBefore(
                                             const TemplateSpecializationType *T, 
-                                            raw_ostream &OS) { 
+                                            raw_ostream &OS) {
   IncludeStrongLifetimeRAII Strong(Policy);
   T->getTemplateName().print(OS, Policy);
 
+  Policy.TemporarySuppressScope = false;
+
   TemplateSpecializationType::PrintTemplateArgumentList(
       OS, T->template_arguments(), Policy);
   spaceBeforePlaceHolder(OS);
@@ -1121,18 +1129,36 @@
 
 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)
+    NestedNameSpecifier *Qualifier = T->getQualifier();
+    if (Qualifier) {
       Qualifier->print(OS, Policy);
+      ScopeHasBeenPrinted = true;
+    }
+    // If there are no nested name specifiers, the complete scope will be
+    // printed later (location depends on the sub-type).
   }
-  
-  ElaboratedTypePolicyRAII PolicyRAII(Policy);
+
+  // 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.
+  bool temporarySuppressScope =
+      Policy.Scope == ScopePrintingKind::DefaultScope || ScopeHasBeenPrinted;
+  ElaboratedTypePolicyRAII PolicyRAII(Policy, temporarySuppressScope);
   printBefore(T->getNamedType(), OS);
 }
 void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
@@ -1161,7 +1187,6 @@
   OS << TypeWithKeyword::getKeywordName(T->getKeyword());
   if (T->getKeyword() != ETK_None)
     OS << " ";
-  
   T->getQualifier()->print(OS, Policy);
   
   OS << T->getIdentifier()->getName();
@@ -1177,10 +1202,13 @@
   OS << TypeWithKeyword::getKeywordName(T->getKeyword());
   if (T->getKeyword() != ETK_None)
     OS << " ";
-  
+
   if (T->getQualifier())
-    T->getQualifier()->print(OS, Policy);    
+    T->getQualifier()->print(OS, Policy);
   OS << T->getIdentifier()->getName();
+
+  Policy.TemporarySuppressScope = false;
+
   TemplateSpecializationType::PrintTemplateArgumentList(OS,
                                                         T->template_arguments(),
                                                         Policy);
Index: lib/AST/TemplateName.cpp
===================================================================
--- lib/AST/TemplateName.cpp
+++ lib/AST/TemplateName.cpp
@@ -175,18 +175,22 @@
 }
 
 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)
+TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy) const {
+  if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) {
+    if (Policy.Scope == ScopePrintingKind::FullScope &&
+        !Policy.TemporarySuppressScope) {
+      Template->printQualifiedName(OS, Policy);
+    } else {
+      OS << *Template;
+    }
+  } else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
+    if (!Policy.TemporarySuppressScope)
       QTN->getQualifier()->print(OS, Policy);
     if (QTN->hasTemplateKeyword())
       OS << "template ";
     OS << *QTN->getDecl();
   } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
-    if (!SuppressNNS && DTN->getQualifier())
+    if (!Policy.TemporarySuppressScope && DTN->getQualifier())
       DTN->getQualifier()->print(OS, Policy);
     OS << "template ";
     
@@ -196,7 +200,7 @@
       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/NestedNameSpecifier.cpp
===================================================================
--- lib/AST/NestedNameSpecifier.cpp
+++ lib/AST/NestedNameSpecifier.cpp
@@ -261,22 +261,52 @@
 void
 NestedNameSpecifier::print(raw_ostream &OS,
                            const PrintingPolicy &Policy) const {
+  if(Policy.Scope == ScopePrintingKind::SuppressScope
+     || Policy.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;
 
@@ -294,31 +324,21 @@
   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);
-    }
+    PrintingPolicy InnerPolicy(Policy);
+    InnerPolicy.TemporarySuppressScope = true;
+    QualType(T, 0).print(OS, InnerPolicy);
     break;
   }
   }
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1427,10 +1427,17 @@
   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 && !P.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/TemplateName.h
===================================================================
--- include/clang/AST/TemplateName.h
+++ include/clang/AST/TemplateName.h
@@ -277,12 +277,7 @@
   ///
   /// \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;
+  void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
   /// \brief Debugging aid that dumps the template name.
   void dump(raw_ostream &OS) const;
Index: include/clang/AST/PrettyPrinter.h
===================================================================
--- include/clang/AST/PrettyPrinter.h
+++ include/clang/AST/PrettyPrinter.h
@@ -30,17 +30,68 @@
   virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0;
 };
 
+// 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 Describes how types, statements, expressions, and
 /// declarations should be printed.
 ///
 /// 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),
+      IncludeTagDefinition(false), Scope(ScopePrintingKind::DefaultScope),
       SuppressUnwrittenScope(false), SuppressInitializers(false),
       ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
       SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
@@ -50,7 +101,8 @@
       UseVoidForZeroParams(!LO.CPlusPlus),
       TerseOutput(false), PolishForDeclaration(false),
       Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar),
-      IncludeNewlines(true), MSVCFormatting(false) { }
+      IncludeNewlines(true), MSVCFormatting(false),
+      TemporarySuppressScope(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 +153,15 @@
   /// \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 +192,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 +233,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.
   ///
@@ -200,6 +254,13 @@
   /// prints anonymous namespaces as `anonymous namespace' and does not insert
   /// spaces after template arguments.
   bool MSVCFormatting : 1;
+
+private:
+  /// \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 currently only used internally.
+  bool TemporarySuppressScope : 1;
 };
 
 } // end namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to