Index: cfe/trunk/include/clang/Tooling/ASTDiff/ASTDiff.h =================================================================== --- cfe/trunk/include/clang/Tooling/ASTDiff/ASTDiff.h +++ cfe/trunk/include/clang/Tooling/ASTDiff/ASTDiff.h @@ -68,10 +68,10 @@ class SyntaxTree { public: /// Constructs a tree from a translation unit. - SyntaxTree(const ASTContext &AST); + SyntaxTree(ASTContext &AST); /// Constructs a tree from any AST node. template - SyntaxTree(T *Node, const ASTContext &AST) + SyntaxTree(T *Node, ASTContext &AST) : TreeImpl(llvm::make_unique(this, Node, AST)) {} SyntaxTree(SyntaxTree &&Other) = default; ~SyntaxTree(); Index: cfe/trunk/lib/Tooling/ASTDiff/ASTDiff.cpp =================================================================== --- cfe/trunk/lib/Tooling/ASTDiff/ASTDiff.cpp +++ cfe/trunk/lib/Tooling/ASTDiff/ASTDiff.cpp @@ -111,24 +111,22 @@ /// Represents the AST of a TranslationUnit. class SyntaxTree::Impl { public: - /// Constructs a tree from the entire translation unit. - Impl(SyntaxTree *Parent, const ASTContext &AST); /// Constructs a tree from an AST node. - Impl(SyntaxTree *Parent, Decl *N, const ASTContext &AST); - Impl(SyntaxTree *Parent, Stmt *N, const ASTContext &AST); + Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST); + Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST); template Impl(SyntaxTree *Parent, typename std::enable_if::value, T>::type *Node, - const ASTContext &AST) + ASTContext &AST) : Impl(Parent, dyn_cast(Node), AST) {} template Impl(SyntaxTree *Parent, typename std::enable_if::value, T>::type *Node, - const ASTContext &AST) + ASTContext &AST) : Impl(Parent, dyn_cast(Node), AST) {} SyntaxTree *Parent; - const ASTContext &AST; + ASTContext &AST; std::vector Leaves; // Maps preorder indices to postorder ones. std::vector PostorderIds; @@ -147,6 +145,10 @@ bool isInSubtree(NodeId Id, NodeId SubtreeRoot) const; int findPositionInParent(NodeId Id, bool Shifted = false) const; + std::string getRelativeName(const NamedDecl *ND, + const DeclContext *Context) const; + std::string getRelativeName(const NamedDecl *ND) const; + std::string getNodeValue(NodeId Id) const; std::string getNodeValue(const Node &Node) const; std::string getDeclValue(const Decl *D) const; @@ -270,7 +272,7 @@ }; } // end anonymous namespace -SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, const ASTContext &AST) +SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST) : Parent(Parent), AST(AST) { NodeCountVisitor NodeCounter(*this); NodeCounter.TraverseDecl(N); @@ -280,7 +282,7 @@ initTree(); } -SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, const ASTContext &AST) +SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST) : Parent(Parent), AST(AST) { NodeCountVisitor NodeCounter(*this); NodeCounter.TraverseStmt(N); @@ -365,6 +367,46 @@ llvm_unreachable("Node not found in parent's children."); } +// Returns the qualified name of ND. If it is subordinate to Context, +// then the prefix of the latter is removed from the returned value. +std::string +SyntaxTree::Impl::getRelativeName(const NamedDecl *ND, + const DeclContext *Context) const { + std::string ContextPrefix; + if (auto *Namespace = dyn_cast(Context)) + ContextPrefix = Namespace->getQualifiedNameAsString(); + else if (auto *Record = dyn_cast(Context)) + ContextPrefix = Record->getQualifiedNameAsString(); + else if (AST.getLangOpts().CPlusPlus11) + if (auto *Tag = dyn_cast(Context)) + ContextPrefix = Tag->getQualifiedNameAsString(); + std::string Val = ND->getQualifiedNameAsString(); + // Strip the qualifier, if Val refers to somthing in the current scope. + // But leave one leading ':' in place, so that we know that this is a + // relative path. + if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix)) + Val = Val.substr(ContextPrefix.size() + 1); + return Val; +} + +std::string SyntaxTree::Impl::getRelativeName(const NamedDecl *ND) const { + return getRelativeName(ND, ND->getDeclContext()); +} + +static const DeclContext *getEnclosingDeclContext(ASTContext &AST, + const Stmt *S) { + while (S) { + const auto &Parents = AST.getParents(*S); + if (Parents.empty()) + return nullptr; + const auto &P = Parents[0]; + if (const auto *D = P.get()) + return D->getDeclContext(); + S = P.get(); + } + llvm_unreachable("Could not find Decl ancestor."); +} + std::string SyntaxTree::Impl::getNodeValue(NodeId Id) const { return getNodeValue(getNode(Id)); } @@ -384,8 +426,7 @@ TypePP.AnonymousTagLocations = false; if (auto *V = dyn_cast(D)) { - Value += V->getQualifiedNameAsString() + "(" + - V->getType().getAsString(TypePP) + ")"; + Value += getRelativeName(V) + "(" + V->getType().getAsString(TypePP) + ")"; if (auto *C = dyn_cast(D)) { for (auto *Init : C->inits()) { if (!Init->isWritten()) @@ -397,7 +438,7 @@ Value += C->getNameAsString(); } else { assert(Init->isAnyMemberInitializer()); - Value += Init->getMember()->getQualifiedNameAsString(); + Value += getRelativeName(Init->getMember()); } Value += ","; } @@ -405,7 +446,7 @@ return Value; } if (auto *N = dyn_cast(D)) - Value += N->getQualifiedNameAsString() + ";"; + Value += getRelativeName(N) + ";"; if (auto *T = dyn_cast(D)) return Value + T->getUnderlyingType().getAsString(TypePP) + ";"; if (auto *T = dyn_cast(D)) @@ -429,7 +470,7 @@ if (auto *B = dyn_cast(S)) return B->getOpcodeStr(); if (auto *M = dyn_cast(S)) - return M->getMemberDecl()->getQualifiedNameAsString(); + return getRelativeName(M->getMemberDecl()); if (auto *I = dyn_cast(S)) { SmallString<256> Str; I->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false); @@ -441,7 +482,7 @@ return Str.str(); } if (auto *D = dyn_cast(S)) - return D->getDecl()->getQualifiedNameAsString(); + return getRelativeName(D->getDecl(), getEnclosingDeclContext(AST, S)); if (auto *String = dyn_cast(S)) return String->getString(); if (auto *B = dyn_cast(S)) @@ -949,7 +990,7 @@ return DiffImpl->getMapped(SourceTree.TreeImpl, Id); } -SyntaxTree::SyntaxTree(const ASTContext &AST) +SyntaxTree::SyntaxTree(ASTContext &AST) : TreeImpl(llvm::make_unique( this, AST.getTranslationUnitDecl(), AST)) {} Index: cfe/trunk/test/Tooling/clang-diff-ast.cpp =================================================================== --- cfe/trunk/test/Tooling/clang-diff-ast.cpp +++ cfe/trunk/test/Tooling/clang-diff-ast.cpp @@ -5,7 +5,7 @@ // CHECK: {{^}} NamespaceDecl: test;( namespace test { -// CHECK: {{^}} FunctionDecl: test::f( +// CHECK: {{^}} FunctionDecl: :f( // CHECK: CompoundStmt( void f() { // CHECK: VarDecl: i(int)( @@ -17,7 +17,7 @@ auto b = true; // CHECK: CallExpr( // CHECK-NOT: ImplicitCastExpr - // CHECK: DeclRefExpr: test::f( + // CHECK: DeclRefExpr: :f( f(); // CHECK: UnaryOperator: ++( ++i; @@ -41,7 +41,7 @@ // CHECK: CXXRecordDecl: X;X;( class X : Base { int m; - // CHECK: CXXMethodDecl: X::foo(const char *(int) + // CHECK: CXXMethodDecl: :foo(const char *(int) // CHECK: ParmVarDecl: i(int)( const char *foo(int i) { if (i == 0) @@ -56,12 +56,12 @@ int not_initialized; // All initialized members, bases and delegating initializers are are // appended, separated by commas. - // CHECK: CXXConstructorDecl: X::X(void (char, int){{( __attribute__\(\(thiscall\)\))?}})Base,X::m,( + // CHECK: CXXConstructorDecl: :X(void (char, int){{( __attribute__\(\(thiscall\)\))?}})Base,:m,( X(char c, int) : Base(), m(0) { - // CHECK: MemberExpr: X::m( + // CHECK: MemberExpr: :m( int x = m; } - // CHECK: CXXConstructorDecl: X::X(void (char){{( __attribute__\(\(thiscall\)\))?}})X,( + // CHECK: CXXConstructorDecl: :X(void (char){{( __attribute__\(\(thiscall\)\))?}})X,( X(char s) : X(s, 4) {} }; Index: cfe/trunk/test/Tooling/clang-diff-basic.cpp =================================================================== --- cfe/trunk/test/Tooling/clang-diff-basic.cpp +++ cfe/trunk/test/Tooling/clang-diff-basic.cpp @@ -11,18 +11,18 @@ } } -// CHECK: Match DeclRefExpr: src::foo{{.*}} to DeclRefExpr: dst::inner::foo +// CHECK: Match DeclRefExpr: :foo{{.*}} to DeclRefExpr: :inner::foo void main() { inner::foo(); } // CHECK: Match StringLiteral: foo{{.*}} to StringLiteral: foo const char *b = "f" "o" "o"; // unsigned is canonicalized to unsigned int -// CHECK: Match TypedefDecl: src::nat;unsigned int;{{.*}} to TypedefDecl: dst::nat;unsigned int; +// CHECK: Match TypedefDecl: :nat;unsigned int;{{.*}} to TypedefDecl: :nat;unsigned int; typedef unsigned nat; -// CHECK: Match VarDecl: src::p(int){{.*}} to VarDecl: dst::prod(double) -// CHECK: Update VarDecl: src::p(int){{.*}} to dst::prod(double) +// CHECK: Match VarDecl: :p(int){{.*}} to VarDecl: :prod(double) +// CHECK: Update VarDecl: :p(int){{.*}} to :prod(double) // CHECK: Match BinaryOperator: *{{.*}} to BinaryOperator: * double prod = 1 * 2 * 10; // CHECK: Update DeclRefExpr Index: cfe/trunk/test/Tooling/clang-diff-html.test =================================================================== --- cfe/trunk/test/Tooling/clang-diff-html.test +++ cfe/trunk/test/Tooling/clang-diff-html.test @@ -11,12 +11,12 @@ // match, move // CHECK: void foo() +// CHECK-NEXT: :foo(void ())' class='m'>void foo() // match // CHECK: void main() +// CHECK-NEXT: :main(void ())'>void main() // deletion // CHECK: