Index: include/clang/Tooling/ASTDiff/ASTDiff.h =================================================================== --- include/clang/Tooling/ASTDiff/ASTDiff.h +++ include/clang/Tooling/ASTDiff/ASTDiff.h @@ -37,6 +37,8 @@ using NodeRef = const Node &; +void printChangeKind(raw_ostream &OS, ChangeKind Kind); + struct ComparisonOptions { /// During top-down matching, only consider nodes of at least this height. int MinHeight = 2; @@ -64,6 +66,8 @@ const Node *getMapped(NodeRef N) const; ChangeKind getNodeChange(NodeRef N) const; + void dumpChanges(raw_ostream &OS, bool DumpMatches = false) const; + class Impl; private: @@ -131,6 +135,10 @@ NodeRefIterator begin() const; NodeRefIterator end() const; + void dump(raw_ostream &OS) const { + OS << getTypeLabel() << "(" << getId() << ")"; + } + int findPositionInParent() const; /// Returns the range that contains the text that is associated with this @@ -163,7 +171,11 @@ inline bool isListSeparator(Token &Tok) { return Tok.is(tok::comma); } -struct NodeRefIterator { +struct NodeRefIterator + : public std::iterator { + using difference_type = + std::iterator::difference_type; + SyntaxTree::Impl *Tree; const NodeId *IdPointer; NodeRefIterator(SyntaxTree::Impl *Tree, const NodeId *IdPointer) @@ -171,7 +183,9 @@ NodeRef operator*() const; NodeRefIterator &operator++(); NodeRefIterator &operator+(int Offset); + difference_type operator-(const NodeRefIterator &Other) const; bool operator!=(const NodeRefIterator &Other) const; + bool operator==(const NodeRefIterator &Other) const; }; } // end namespace diff Index: lib/Tooling/ASTDiff/ASTDiff.cpp =================================================================== --- lib/Tooling/ASTDiff/ASTDiff.cpp +++ lib/Tooling/ASTDiff/ASTDiff.cpp @@ -31,6 +31,27 @@ bool ComparisonOptions::isMatchingAllowed(NodeRef N1, NodeRef N2) const { return (N1.isMacro() && N2.isMacro()) || N1.getType().isSame(N2.getType()); } +void printChangeKind(raw_ostream &OS, ChangeKind Kind) { + switch (Kind) { + case NoChange: + break; + case Delete: + OS << "Delete"; + break; + case Update: + OS << "Update"; + break; + case Insert: + OS << "Insert"; + break; + case Move: + OS << "Move"; + break; + case UpdateMove: + OS << "Update and Move"; + break; + } +} namespace { struct NodeChange { @@ -62,6 +83,8 @@ ChangeKind getNodeChange(NodeRef N) const; + void dumpChanges(raw_ostream &OS, bool DumpMatches) const; + private: // Adds a mapping between two nodes. void link(NodeRef N1, NodeRef N2); @@ -1203,6 +1226,62 @@ return DiffImpl->getNodeChange(N); } +static void dumpDstChange(raw_ostream &OS, const ASTDiff::Impl &Diff, + SyntaxTree::Impl &SrcTree, SyntaxTree::Impl &DstTree, + NodeRef Dst) { + const Node *Src = Diff.getMapped(Dst); + ChangeKind Change = Diff.getNodeChange(Dst); + printChangeKind(OS, Change); + switch (Change) { + case NoChange: + break; + case Delete: + llvm_unreachable("The destination tree can't have deletions."); + case Update: + OS << " "; + Src->dump(OS); + OS << "\n"; + break; + case Insert: + case Move: + case UpdateMove: + OS << " "; + Dst.dump(OS); + OS << " into "; + if (!Dst.getParent()) + OS << "None"; + else + Dst.getParent()->dump(OS); + OS << " at " << Dst.findPositionInParent() << "\n"; + break; + } +} + +void ASTDiff::Impl::dumpChanges(raw_ostream &OS, bool DumpMatches) const { + for (NodeRef N2 : T2) { + const Node *N1 = getMapped(N2); + if (DumpMatches && N1) { + OS << "Match "; + N1->dump(OS); + OS << " to "; + N2.dump(OS); + OS << "\n"; + } + dumpDstChange(OS, *this, T1, T2, N2); + } + for (NodeRef N1 : T1) { + if (!getMapped(N1)) { + OS << "Delete "; + N1.dump(OS); + OS << "\n"; + } + } +} + +void ASTDiff::dumpChanges(raw_ostream &OS, bool DumpMatches) const { + DiffImpl->dumpChanges(OS, DumpMatches); +} + SyntaxTree::SyntaxTree(ASTUnit &AST) : TreeImpl(llvm::make_unique( this, AST.getASTContext().getTranslationUnitDecl(), AST)) {} Index: tools/clang-diff/ClangDiff.cpp =================================================================== --- tools/clang-diff/ClangDiff.cpp +++ tools/clang-diff/ClangDiff.cpp @@ -384,57 +384,15 @@ OS << "]}"; } -static void printNode(raw_ostream &OS, diff::SyntaxTree &Tree, - diff::NodeRef Node) { - OS << Node.getTypeLabel(); - OS << "(" << Node.getId() << ")"; -} - static void printTree(raw_ostream &OS, diff::SyntaxTree &Tree) { for (diff::NodeRef Node : Tree) { for (int I = 0; I < Node.Depth; ++I) OS << " "; - printNode(OS, Tree, Node); + Node.dump(OS); OS << "\n"; } } -static void printDstChange(raw_ostream &OS, diff::ASTDiff &Diff, - diff::SyntaxTree &SrcTree, diff::SyntaxTree &DstTree, - diff::NodeRef Dst) { - const diff::Node *Src = Diff.getMapped(Dst); - diff::ChangeKind Change = Diff.getNodeChange(Dst); - switch (Change) { - case diff::NoChange: - break; - case diff::Delete: - llvm_unreachable("The destination tree can't have deletions."); - case diff::Update: - OS << "Update "; - printNode(OS, SrcTree, *Src); - OS << "\n"; - break; - case diff::Insert: - case diff::Move: - case diff::UpdateMove: - if (Change == diff::Insert) - OS << "Insert"; - else if (Change == diff::Move) - OS << "Move"; - else if (Change == diff::UpdateMove) - OS << "Update and Move"; - OS << " "; - printNode(OS, DstTree, Dst); - OS << " into "; - if (!Dst.getParent()) - OS << "None"; - else - printNode(OS, DstTree, *Dst.getParent()); - OS << " at " << Dst.findPositionInParent() << "\n"; - break; - } -} - int main(int argc, const char **argv) { std::string ErrorMessage; std::unique_ptr CommonCompilations = @@ -509,24 +467,7 @@ return 0; } - for (diff::NodeRef Dst : DstTree) { - const diff::Node *Src = Diff.getMapped(Dst); - if (PrintMatches && Src) { - llvm::outs() << "Match "; - printNode(llvm::outs(), SrcTree, *Src); - llvm::outs() << " to "; - printNode(llvm::outs(), DstTree, Dst); - llvm::outs() << "\n"; - } - printDstChange(llvm::outs(), Diff, SrcTree, DstTree, Dst); - } - for (diff::NodeRef Src : SrcTree) { - if (!Diff.getMapped(Src)) { - llvm::outs() << "Delete "; - printNode(llvm::outs(), SrcTree, Src); - llvm::outs() << "\n"; - } - } + Diff.dumpChanges(llvm::outs(), PrintMatches); return 0; }