Index: include/clang/Tooling/ASTDiff/ASTDiff.h =================================================================== --- include/clang/Tooling/ASTDiff/ASTDiff.h +++ include/clang/Tooling/ASTDiff/ASTDiff.h @@ -68,15 +68,15 @@ 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(const SyntaxTree &Tree) = delete; ~SyntaxTree(); - const ASTContext &getASTContext() const; + ASTContext &getASTContext() const; StringRef getFilename() const; int getSize() const; Index: lib/Tooling/ASTDiff/ASTDiff.cpp =================================================================== --- lib/Tooling/ASTDiff/ASTDiff.cpp +++ lib/Tooling/ASTDiff/ASTDiff.cpp @@ -111,23 +111,23 @@ class SyntaxTree::Impl { public: /// Constructs a tree from the entire translation unit. - Impl(SyntaxTree *Parent, const ASTContext &AST); + Impl(SyntaxTree *Parent, 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; @@ -276,10 +276,10 @@ }; } // end anonymous namespace -SyntaxTree::Impl::Impl(SyntaxTree *Parent, const ASTContext &AST) +SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTContext &AST) : Impl(Parent, AST.getTranslationUnitDecl(), AST) {} -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); @@ -289,7 +289,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); @@ -374,6 +374,43 @@ llvm_unreachable("Node not found in parent's children."); } +// Returns the qualified name of ND. If the is declared in Context then +// the name is made relative with respect to the qualified name of Context. +static std::string getRelativeName(const NamedDecl *ND, + const DeclContext *Context) { + std::string ContextPrefix; + if (auto *Namespace = dyn_cast(Context)) + ContextPrefix = Namespace->getQualifiedNameAsString(); + else 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() && + Val.substr(0, ContextPrefix.size()) == ContextPrefix) + Val = Val.substr(ContextPrefix.size() + 1); + return Val; +} + +static std::string getRelativeName(const NamedDecl *ND) { + 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)); } @@ -393,8 +430,7 @@ TypePP.AnonymousTagLocations = false; if (auto *X = dyn_cast(D)) { - Value += X->getQualifiedNameAsString() + "(" + - X->getType().getAsString(TypePP) + ")"; + Value += getRelativeName(X) + "(" + X->getType().getAsString(TypePP) + ")"; if (auto *X = dyn_cast(D)) { for (auto *Init : X->inits()) { if (!Init->isWritten()) @@ -407,14 +443,14 @@ Value += X->getNameAsString() + ","; } else { assert(Init->isAnyMemberInitializer()); - Value += Init->getMember()->getQualifiedNameAsString() + ","; + Value += getRelativeName(Init->getMember()) + ","; } } } return Value; } if (auto *X = dyn_cast(D)) - Value += X->getQualifiedNameAsString() + ";"; + Value += getRelativeName(X) + ";"; if (auto *X = dyn_cast(D)) return Value + X->getUnderlyingType().getAsString(TypePP) + ";"; if (auto *X = dyn_cast(D)) @@ -438,7 +474,7 @@ if (auto *X = dyn_cast(S)) return X->getOpcodeStr(); if (auto *X = dyn_cast(S)) - return X->getMemberDecl()->getQualifiedNameAsString(); + return getRelativeName(X->getMemberDecl()); if (auto *X = dyn_cast(S)) { SmallString<256> Str; X->getValue().toString(Str, /*Radix=*/10, /*Signed=*/false); @@ -450,7 +486,7 @@ return Str.str(); } if (auto *X = dyn_cast(S)) - return X->getDecl()->getQualifiedNameAsString(); + return getRelativeName(X->getDecl(), getEnclosingDeclContext(AST, S)); if (auto *X = dyn_cast(S)) return X->getString(); if (auto *X = dyn_cast(S)) @@ -951,13 +987,13 @@ return DiffImpl->getMapped(*SourceTree.TreeImpl, Id); } -SyntaxTree::SyntaxTree(const ASTContext &AST) +SyntaxTree::SyntaxTree(ASTContext &AST) : TreeImpl(llvm::make_unique( this, AST.getTranslationUnitDecl(), AST)) {} SyntaxTree::~SyntaxTree() = default; -const ASTContext &SyntaxTree::getASTContext() const { return TreeImpl->AST; } +ASTContext &SyntaxTree::getASTContext() const { return TreeImpl->AST; } const Node &SyntaxTree::getNode(NodeId Id) const { return TreeImpl->getNode(Id); Index: test/Tooling/clang-diff-ast.cpp =================================================================== --- test/Tooling/clang-diff-ast.cpp +++ 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)( @@ -16,7 +16,7 @@ // CHECK: CXXBoolLiteralExpr: true( auto b = true; // CHECK: CallExpr( - // CHECK: DeclRefExpr: test::f( + // CHECK: DeclRefExpr: :f( f(); // CHECK: UnaryOperator: ++( ++i; @@ -40,7 +40,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) @@ -51,9 +51,9 @@ // CHECK: AccessSpecDecl: public( public: - // CHECK: CXXConstructorDecl: X::X(void (char, int))Base,X::m,( + // CHECK: CXXConstructorDecl: :X(void (char, int))Base,:m,( X(char, int) : Base(), m(0) { - // CHECK: MemberExpr: X::m( + // CHECK: MemberExpr: :m( int x = m; } }; Index: test/Tooling/clang-diff-basic.cpp =================================================================== --- test/Tooling/clang-diff-basic.cpp +++ test/Tooling/clang-diff-basic.cpp @@ -45,18 +45,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: test/Tooling/clang-diff-opt.cpp =================================================================== --- test/Tooling/clang-diff-opt.cpp +++ test/Tooling/clang-diff-opt.cpp @@ -9,6 +9,8 @@ void f1() { {;} {{;}} } +class A { int x; void f() { int a1 = x; } }; + #else void f1() { @@ -19,5 +21,18 @@ // CHECK: Match NullStmt(4) to NullStmt(3) ; {{;}} } + +class B { + // Only the class name changed; it is not included in the field value, + // therefore there is no update. + // CHECK: Match FieldDecl: :x(int)(9) to FieldDecl: :x(int)(8) + // CHECK-NOT: Update FieldDecl: :x(int)(9) + int x; + void f() { + // CHECK: Match MemberExpr: :x(14) to MemberExpr: :x(13) + // CHECK-NOT: Update MemberExpr: :x(14) + int b2 = B::x; + } +}; #endif Index: test/Tooling/clang-diff-topdown.cpp =================================================================== --- test/Tooling/clang-diff-topdown.cpp +++ test/Tooling/clang-diff-topdown.cpp @@ -27,6 +27,14 @@ {{;;}} } +int x; + +namespace src { + int x; + int x1 = x + 1; + int x2 = ::x + 1; +} + #else void f1() { @@ -45,4 +53,14 @@ ; } +int x; + +namespace dst { + int x; + // CHECK: Match DeclRefExpr: :x(17) to DeclRefExpr: :x(22) + int x1 = x + 1; + // CHECK: Match DeclRefExpr: x(21) to DeclRefExpr: x(26) + int x2 = ::x + 1; +} + #endif