1e5dd7070Spatrick //===- ASTDiff.h - AST differencing API -----------------------*- C++ -*- -===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // 4e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 6e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7e5dd7070Spatrick // 8e5dd7070Spatrick //===----------------------------------------------------------------------===// 9e5dd7070Spatrick // 10e5dd7070Spatrick // This file specifies an interface that can be used to compare C++ syntax 11e5dd7070Spatrick // trees. 12e5dd7070Spatrick // 13e5dd7070Spatrick // We use the gumtree algorithm which combines a heuristic top-down search that 14e5dd7070Spatrick // is able to match large subtrees that are equivalent, with an optimal 15e5dd7070Spatrick // algorithm to match small subtrees. 16e5dd7070Spatrick // 17e5dd7070Spatrick //===----------------------------------------------------------------------===// 18e5dd7070Spatrick 19e5dd7070Spatrick #ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H 20e5dd7070Spatrick #define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H 21e5dd7070Spatrick 22e5dd7070Spatrick #include "clang/Tooling/ASTDiff/ASTDiffInternal.h" 23*12c85518Srobert #include <optional> 24e5dd7070Spatrick 25e5dd7070Spatrick namespace clang { 26e5dd7070Spatrick namespace diff { 27e5dd7070Spatrick 28e5dd7070Spatrick enum ChangeKind { 29e5dd7070Spatrick None, 30e5dd7070Spatrick Delete, // (Src): delete node Src. 31e5dd7070Spatrick Update, // (Src, Dst): update the value of node Src to match Dst. 32e5dd7070Spatrick Insert, // (Src, Dst, Pos): insert Src as child of Dst at offset Pos. 33e5dd7070Spatrick Move, // (Src, Dst, Pos): move Src to be a child of Dst at offset Pos. 34e5dd7070Spatrick UpdateMove // Same as Move plus Update. 35e5dd7070Spatrick }; 36e5dd7070Spatrick 37e5dd7070Spatrick /// Represents a Clang AST node, alongside some additional information. 38e5dd7070Spatrick struct Node { 39e5dd7070Spatrick NodeId Parent, LeftMostDescendant, RightMostDescendant; 40e5dd7070Spatrick int Depth, Height, Shift = 0; 41ec727ea7Spatrick DynTypedNode ASTNode; 42e5dd7070Spatrick SmallVector<NodeId, 4> Children; 43e5dd7070Spatrick ChangeKind Change = None; 44e5dd7070Spatrick 45ec727ea7Spatrick ASTNodeKind getType() const; 46e5dd7070Spatrick StringRef getTypeLabel() const; isLeafNode47e5dd7070Spatrick bool isLeaf() const { return Children.empty(); } 48*12c85518Srobert std::optional<StringRef> getIdentifier() const; 49*12c85518Srobert std::optional<std::string> getQualifiedIdentifier() const; 50e5dd7070Spatrick }; 51e5dd7070Spatrick 52e5dd7070Spatrick /// SyntaxTree objects represent subtrees of the AST. 53e5dd7070Spatrick /// They can be constructed from any Decl or Stmt. 54e5dd7070Spatrick class SyntaxTree { 55e5dd7070Spatrick public: 56e5dd7070Spatrick /// Constructs a tree from a translation unit. 57e5dd7070Spatrick SyntaxTree(ASTContext &AST); 58e5dd7070Spatrick /// Constructs a tree from any AST node. 59e5dd7070Spatrick template <class T> SyntaxTree(T * Node,ASTContext & AST)60e5dd7070Spatrick SyntaxTree(T *Node, ASTContext &AST) 61e5dd7070Spatrick : TreeImpl(std::make_unique<Impl>(this, Node, AST)) {} 62e5dd7070Spatrick SyntaxTree(SyntaxTree &&Other) = default; 63e5dd7070Spatrick ~SyntaxTree(); 64e5dd7070Spatrick 65e5dd7070Spatrick const ASTContext &getASTContext() const; 66e5dd7070Spatrick StringRef getFilename() const; 67e5dd7070Spatrick 68e5dd7070Spatrick int getSize() const; 69e5dd7070Spatrick NodeId getRootId() const; 70e5dd7070Spatrick using PreorderIterator = NodeId; 71e5dd7070Spatrick PreorderIterator begin() const; 72e5dd7070Spatrick PreorderIterator end() const; 73e5dd7070Spatrick 74e5dd7070Spatrick const Node &getNode(NodeId Id) const; 75e5dd7070Spatrick int findPositionInParent(NodeId Id) const; 76e5dd7070Spatrick 77e5dd7070Spatrick // Returns the starting and ending offset of the node in its source file. 78e5dd7070Spatrick std::pair<unsigned, unsigned> getSourceRangeOffsets(const Node &N) const; 79e5dd7070Spatrick 80e5dd7070Spatrick /// Serialize the node attributes to a string representation. This should 81e5dd7070Spatrick /// uniquely distinguish nodes of the same kind. Note that this function just 82e5dd7070Spatrick /// returns a representation of the node value, not considering descendants. 83e5dd7070Spatrick std::string getNodeValue(NodeId Id) const; 84e5dd7070Spatrick std::string getNodeValue(const Node &Node) const; 85e5dd7070Spatrick 86e5dd7070Spatrick class Impl; 87e5dd7070Spatrick std::unique_ptr<Impl> TreeImpl; 88e5dd7070Spatrick }; 89e5dd7070Spatrick 90e5dd7070Spatrick struct ComparisonOptions { 91e5dd7070Spatrick /// During top-down matching, only consider nodes of at least this height. 92e5dd7070Spatrick int MinHeight = 2; 93e5dd7070Spatrick 94e5dd7070Spatrick /// During bottom-up matching, match only nodes with at least this value as 95e5dd7070Spatrick /// the ratio of their common descendants. 96e5dd7070Spatrick double MinSimilarity = 0.5; 97e5dd7070Spatrick 98e5dd7070Spatrick /// Whenever two subtrees are matched in the bottom-up phase, the optimal 99e5dd7070Spatrick /// mapping is computed, unless the size of either subtrees exceeds this. 100e5dd7070Spatrick int MaxSize = 100; 101e5dd7070Spatrick 102e5dd7070Spatrick bool StopAfterTopDown = false; 103e5dd7070Spatrick 104e5dd7070Spatrick /// Returns false if the nodes should never be matched. isMatchingAllowedComparisonOptions105e5dd7070Spatrick bool isMatchingAllowed(const Node &N1, const Node &N2) const { 106e5dd7070Spatrick return N1.getType().isSame(N2.getType()); 107e5dd7070Spatrick } 108e5dd7070Spatrick }; 109e5dd7070Spatrick 110*12c85518Srobert class ASTDiff { 111*12c85518Srobert public: 112*12c85518Srobert ASTDiff(SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options); 113*12c85518Srobert ~ASTDiff(); 114*12c85518Srobert 115*12c85518Srobert // Returns the ID of the node that is mapped to the given node in SourceTree. 116*12c85518Srobert NodeId getMapped(const SyntaxTree &SourceTree, NodeId Id) const; 117*12c85518Srobert 118*12c85518Srobert class Impl; 119*12c85518Srobert 120*12c85518Srobert private: 121*12c85518Srobert std::unique_ptr<Impl> DiffImpl; 122*12c85518Srobert }; 123*12c85518Srobert 124e5dd7070Spatrick } // end namespace diff 125e5dd7070Spatrick } // end namespace clang 126e5dd7070Spatrick 127e5dd7070Spatrick #endif 128