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 &t = T())</Declaration>
-// CHECK: <Declaration>friend void vector<A>::f(const test3::A &)</Declaration>
+// CHECK: <Declaration>friend void vector<test3::A>::f(const test3::A &)</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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits