;
36Mapping(Mapping &&
Other) =
default;
37Mapping &operator=(Mapping &&
Other) =
default;
39Mapping(
size_tSize) {
40SrcToDst = std::make_unique<NodeId[]>(Size);
41DstToSrc = std::make_unique<NodeId[]>(Size);
44 void link(NodeId Src, NodeId Dst) {
45SrcToDst[Src] = Dst, DstToSrc[Dst] = Src;
48NodeId getDst(NodeId Src)
const{
returnSrcToDst[Src]; }
49NodeId getSrc(NodeId Dst)
const{
returnDstToSrc[Dst]; }
50 boolhasSrc(NodeId Src)
const{
returngetDst(Src).isValid(); }
51 boolhasDst(NodeId Dst)
const{
returngetSrc(Dst).isValid(); }
54std::unique_ptr<NodeId[]> SrcToDst, DstToSrc;
76assert(&*
Tree== &
T2&&
"Invalid tree.");
88 boolhaveSameParents(
constMapping &M,
NodeIdId1,
NodeIdId2)
const;
92 voidaddOptimalMapping(Mapping &M,
NodeIdId1,
NodeIdId2)
const;
96 doublegetJaccardSimilarity(
constMapping &M,
NodeIdId1,
NodeIdId2)
const;
99 NodeIdfindCandidate(
constMapping &M,
NodeIdId1)
const;
102Mapping matchTopDown()
const;
105 voidmatchBottomUp(Mapping &M)
const;
162 voidsetLeftMostDescendants();
190 int Id= 0, Depth = 0;
194PreorderVisitor(SyntaxTree::Impl &Tree) :
Tree(
Tree) {}
196 template<
classT> std::tuple<NodeId, NodeId> PreTraverse(
T*ASTNode) {
198 Tree.Nodes.emplace_back();
199 Node&N =
Tree.getMutableNode(MyId);
203assert(!N.ASTNode.getNodeKind().isNone() &&
204 "Expected nodes to have a valid kind.");
207 P.Children.push_back(MyId);
212 returnstd::make_tuple(MyId,
Tree.getNode(MyId).Parent);
214 voidPostTraverse(std::tuple<NodeId, NodeId> State) {
215NodeId MyId, PreviousParent;
216std::tie(MyId, PreviousParent) = State;
217assert(MyId.isValid() &&
"Expecting to only traverse valid nodes.");
220 Node&N =
Tree.getMutableNode(MyId);
221N.RightMostDescendant =
Id- 1;
222assert(N.RightMostDescendant >= 0 &&
223N.RightMostDescendant <
Tree.getSize() &&
224 "Rightmost descendant must be a valid tree node.");
226 Tree.Leaves.push_back(MyId);
228 for(NodeId Child : N.Children)
229N.Height = std::max(N.Height, 1 +
Tree.getNode(Child).Height);
231 boolTraverseDecl(
Decl*
D) {
234 autoSavedState = PreTraverse(
D);
236PostTraverse(SavedState);
239 boolTraverseStmt(
Stmt*S) {
240 if(
auto*
E= dyn_cast_or_null<Expr>(S))
244 autoSavedState = PreTraverse(S);
246PostTraverse(SavedState);
249 boolTraverseType(
QualType T) {
return true; }
253 autoSavedState = PreTraverse(
Init);
255PostTraverse(SavedState);
262:
Parent(
Parent), AST(AST), TypePP(AST.getLangOpts()) {
268PreorderVisitor PreorderWalker(*
this);
269PreorderWalker.TraverseDecl(N);
275PreorderVisitor PreorderWalker(*
this);
276PreorderWalker.TraverseStmt(N);
282std::vector<NodeId> Postorder;
287Postorder.push_back(
Id);
295std::vector<NodeId> Ids;
298 while(Expanded < Ids.size())
299 for(
NodeIdChild :
Tree.getNode(Ids[Expanded++]).Children)
300Ids.push_back(Child);
304voidSyntaxTree::Impl::initTree() {
305setLeftMostDescendants();
307PostorderIds.resize(
getSize());
308std::function<void(NodeId)> PostorderTraverse = [&](NodeId
Id) {
310PostorderTraverse(Child);
311PostorderIds[
Id] = PostorderId;
318voidSyntaxTree::Impl::setLeftMostDescendants() {
319 for(NodeId Leaf : Leaves) {
320getMutableNode(Leaf).LeftMostDescendant = Leaf;
321NodeId
Parent, Cur = Leaf;
325getMutableNode(Cur).LeftMostDescendant = Leaf;
344 for(
size_tI = 0,
E= Siblings.size(); I <
E; ++I) {
347 if(Siblings[I] ==
Id) {
352llvm_unreachable(
"Node not found in parent's children.");
361std::string ContextPrefix;
364 if(
auto*Namespace = dyn_cast<NamespaceDecl>(Context))
365ContextPrefix = Namespace->getQualifiedNameAsString();
366 else if(
auto*
Record= dyn_cast<RecordDecl>(Context))
367ContextPrefix =
Record->getQualifiedNameAsString();
368 else if(AST.getLangOpts().CPlusPlus11)
369 if(
auto*Tag = dyn_cast<TagDecl>(Context))
370ContextPrefix = Tag->getQualifiedNameAsString();
374 if(!ContextPrefix.empty() && StringRef(Val).starts_with(ContextPrefix))
375Val = Val.substr(ContextPrefix.size() + 1);
389 const auto&
P= Parents[0];
390 if(
const auto*
D=
P.get<
Decl>())
392S =
P.get<
Stmt>();
399 if(
Init->isAnyMemberInitializer())
400 returnstd::string(
Init->getAnyMember()->getName());
401 if(
Init->isBaseInitializer())
403 if(
Init->isDelegatingInitializer())
404 return Init->getTypeSourceInfo()->getType().getAsString(TypePP);
405llvm_unreachable(
"Unknown initializer type");
414 if(
auto*S = DTN.
get<
Stmt>())
415 returngetStmtValue(S);
416 if(
auto*
D= DTN.
get<
Decl>())
417 returngetDeclValue(
D);
420llvm_unreachable(
"Fatal: unhandled AST node.\n");
425 if(
auto*
V= dyn_cast<ValueDecl>(
D))
426 returngetRelativeName(
V) +
"("+
V->getType().getAsString(TypePP) +
")";
427 if(
auto*N = dyn_cast<NamedDecl>(
D))
428 Value+= getRelativeName(N) +
";";
429 if(
auto*
T= dyn_cast<TypedefNameDecl>(
D))
430 return Value+
T->getUnderlyingType().getAsString(TypePP) +
";";
431 if(
auto*
T= dyn_cast<TypeDecl>(
D))
432 if(
T->getTypeForDecl())
436 if(
auto*
U= dyn_cast<UsingDirectiveDecl>(
D))
437 returnstd::string(
U->getNominatedNamespace()->getName());
438 if(
auto*A = dyn_cast<AccessSpecDecl>(
D)) {
447 if(
auto*
U= dyn_cast<UnaryOperator>(S))
449 if(
auto*B = dyn_cast<BinaryOperator>(S))
450 returnstd::string(B->getOpcodeStr());
451 if(
auto*M = dyn_cast<MemberExpr>(S))
452 returngetRelativeName(M->getMemberDecl());
453 if(
auto*I = dyn_cast<IntegerLiteral>(S)) {
455I->getValue().toString(Str,
10,
false);
456 returnstd::string(Str);
458 if(
auto*F = dyn_cast<FloatingLiteral>(S)) {
460F->getValue().toString(Str);
461 returnstd::string(Str);
463 if(
auto*
D= dyn_cast<DeclRefExpr>(S))
465 if(
auto*String = dyn_cast<StringLiteral>(S))
466 returnstd::string(String->getString());
467 if(
auto*B = dyn_cast<CXXBoolLiteralExpr>(S))
468 returnB->getValue() ?
"true":
"false";
479 operator int()
const{
return Id; }
490std::vector<NodeId> RootIds;
492std::vector<SNodeId> LeftMostDescendants;
499 intNumLeaves = setLeftMostDescendants();
500computeKeyRoots(NumLeaves);
502 int getSize()
const{
returnRootIds.size(); }
504assert(
Id> 0 &&
Id<= getSize() &&
"Invalid subtree node index.");
505 returnRootIds[
Id- 1];
508 return Tree.getNode(getIdInRoot(
Id));
511assert(
Id> 0 &&
Id<= getSize() &&
"Invalid subtree node index.");
512 returnLeftMostDescendants[
Id- 1];
516 return Tree.PostorderIds[getIdInRoot(
SNodeId(1))];
519 return Tree.getNodeValue(getIdInRoot(
Id));
524 intsetLeftMostDescendants() {
526LeftMostDescendants.resize(getSize());
527 for(
intI = 0; I < getSize(); ++I) {
530NumLeaves += N.
isLeaf();
531assert(I ==
Tree.PostorderIds[getIdInRoot(SI)] - getPostorderOffset() &&
532 "Postorder traversal in subtree should correspond to traversal in " 533 "the root tree by a constant offset.");
535getPostorderOffset());
539 voidcomputeKeyRoots(
intLeaves) {
540KeyRoots.resize(Leaves);
541std::unordered_set<int>
Visited;
543 for(SNodeId I(getSize()); I > 0; --I) {
544SNodeId LeftDesc = getLeftMostDescendant(I);
547assert(K >= 0 &&
"K should be non-negative");
562std::unique_ptr<std::unique_ptr<double[]>[]> TreeDist, ForestDist;
567: DiffImpl(DiffImpl), S1(T1, Id1), S2(T2, Id2) {
568TreeDist = std::make_unique<std::unique_ptr<double[]>[]>(
570ForestDist = std::make_unique<std::unique_ptr<double[]>[]>(
572 for(
intI = 0,
E= S1.
getSize() + 1; I <
E; ++I) {
573TreeDist[I] = std::make_unique<double[]>(
size_t(S2.
getSize()) + 1);
574ForestDist[I] = std::make_unique<double[]>(
size_t(S2.
getSize()) + 1);
579std::vector<std::pair<NodeId, NodeId>> Matches;
580std::vector<std::pair<SNodeId, SNodeId>> TreePairs;
584 boolRootNodePair =
true;
588 while(!TreePairs.empty()) {
589 SNodeIdLastRow, LastCol, FirstRow, FirstCol, Row, Col;
590std::tie(LastRow, LastCol) = TreePairs.back();
591TreePairs.pop_back();
594computeForestDist(LastRow, LastCol);
597RootNodePair =
false;
605 while(Row > FirstRow || Col > FirstCol) {
606 if(Row > FirstRow &&
607ForestDist[Row - 1][Col] + 1 == ForestDist[Row][Col]) {
609}
else if(Col > FirstCol &&
610ForestDist[Row][Col - 1] + 1 == ForestDist[Row][Col]) {
619assert(DiffImpl.isMatchingPossible(Id1, Id2) &&
620 "These nodes must not be matched.");
621Matches.emplace_back(Id1, Id2);
625TreePairs.emplace_back(Row, Col);
641 static constexpr doubleDeletionCost = 1;
642 static constexpr doubleInsertionCost = 1;
646 returnstd::numeric_limits<double>::max();
650 voidcomputeTreeDist() {
653computeForestDist(Id1, Id2);
656 voidcomputeForestDist(SNodeId Id1, SNodeId Id2) {
657assert(Id1 > 0 && Id2 > 0 &&
"Expecting offsets greater than 0.");
661ForestDist[LMD1][LMD2] = 0;
662 for(SNodeId D1 = LMD1 + 1; D1 <= Id1; ++D1) {
663ForestDist[D1][LMD2] = ForestDist[D1 - 1][LMD2] + DeletionCost;
664 for(SNodeId D2 = LMD2 + 1; D2 <= Id2; ++D2) {
665ForestDist[LMD1][D2] = ForestDist[LMD1][D2 - 1] + InsertionCost;
668 if(DLMD1 == LMD1 && DLMD2 == LMD2) {
669 doubleUpdateCost = getUpdateCost(D1, D2);
671std::min({ForestDist[D1 - 1][D2] + DeletionCost,
672ForestDist[D1][D2 - 1] + InsertionCost,
673ForestDist[D1 - 1][D2 - 1] + UpdateCost});
674TreeDist[D1][D2] = ForestDist[D1][D2];
677std::min({ForestDist[D1 - 1][D2] + DeletionCost,
678ForestDist[D1][D2 - 1] + InsertionCost,
679ForestDist[DLMD1][DLMD2] + TreeDist[D1][D2]});
691 if(
auto*ND = ASTNode.get<
NamedDecl>()) {
692 if(ND->getDeclName().isIdentifier())
693 returnND->getQualifiedNameAsString();
699 if(
auto*ND = ASTNode.get<
NamedDecl>()) {
700 if(ND->getDeclName().isIdentifier())
701 returnND->getName();
711 booloperator()(NodeId Id1, NodeId Id2)
const{
712 return Tree.getNode(Id1).Height <
Tree.getNode(Id2).Height;
720 constSyntaxTree::Impl &
Tree;
722std::vector<NodeId> Container;
723PriorityQueue<NodeId, std::vector<NodeId>, HeightLess> List;
726PriorityList(
constSyntaxTree::Impl &
Tree)
729 voidpush(NodeId
id) { List.push(
id); }
731std::vector<NodeId> pop() {
733std::vector<NodeId> Result;
736 while(peekMax() ==
Max) {
737Result.push_back(List.top());
744 intpeekMax()
const{
747 return Tree.getNode(List.top()).Height;
749 voidopen(NodeId
Id) {
750 for(NodeId Child :
Tree.getNode(
Id).Children)
756boolASTDiff::Impl::identical(NodeId Id1, NodeId Id2)
const{
757 const Node&N1 = T1.getNode(Id1);
758 const Node&N2 = T2.getNode(Id2);
759 if(N1.Children.size() != N2.Children.size() ||
760!isMatchingPossible(Id1, Id2) ||
761T1.getNodeValue(Id1) != T2.getNodeValue(Id2))
763 for(
size_t Id= 0,
E= N1.Children.size();
Id<
E; ++
Id)
764 if(!identical(N1.Children[
Id], N2.Children[
Id]))
769boolASTDiff::Impl::isMatchingPossible(NodeId Id1, NodeId Id2)
const{
770 returnOptions.isMatchingAllowed(T1.getNode(Id1), T2.getNode(Id2));
773boolASTDiff::Impl::haveSameParents(
constMapping &M, NodeId Id1,
775NodeId P1 = T1.getNode(Id1).Parent;
776NodeId P2 = T2.getNode(Id2).Parent;
777 return(P1.isInvalid() && P2.isInvalid()) ||
778(P1.isValid() && P2.isValid() && M.getDst(P1) == P2);
781voidASTDiff::Impl::addOptimalMapping(Mapping &M, NodeId Id1,
783 if(std::max(T1.getNumberOfDescendants(Id1), T2.getNumberOfDescendants(Id2)) >
786ZhangShashaMatcher Matcher(*
this, T1, T2, Id1, Id2);
787std::vector<std::pair<NodeId, NodeId>> R = Matcher.getMatchingNodes();
788 for(
const auto&Tuple : R) {
789NodeId Src = Tuple.first;
790NodeId Dst = Tuple.second;
791 if(!M.hasSrc(Src) && !M.hasDst(Dst))
796doubleASTDiff::Impl::getJaccardSimilarity(
constMapping &M, NodeId Id1,
798 intCommonDescendants = 0;
799 const Node&N1 = T1.getNode(Id1);
801 for(NodeId Src = Id1 + 1; Src <= N1.RightMostDescendant; ++Src) {
802NodeId Dst = M.getDst(Src);
803CommonDescendants +=
int(Dst.isValid() && T2.isInSubtree(Dst, Id2));
806 doubleDenominator = T1.getNumberOfDescendants(Id1) - 1 +
807T2.getNumberOfDescendants(Id2) - 1 - CommonDescendants;
809assert(Denominator >= 0 &&
"Expected non-negative denominator.");
810 if(Denominator == 0)
812 returnCommonDescendants / Denominator;
815NodeId ASTDiff::Impl::findCandidate(
constMapping &M, NodeId Id1)
const{
817 doubleHighestSimilarity = 0.0;
818 for(NodeId Id2 : T2) {
819 if(!isMatchingPossible(Id1, Id2))
823 doubleSimilarity = getJaccardSimilarity(M, Id1, Id2);
824 if(Similarity >= Options.MinSimilarity && Similarity > HighestSimilarity) {
825HighestSimilarity = Similarity;
832voidASTDiff::Impl::matchBottomUp(Mapping &M)
const{
834 for(NodeId Id1 : Postorder) {
835 if(Id1 == T1.getRootId() && !M.hasSrc(T1.getRootId()) &&
836!M.hasDst(T2.getRootId())) {
837 if(isMatchingPossible(T1.getRootId(), T2.getRootId())) {
838M.link(T1.getRootId(), T2.getRootId());
839addOptimalMapping(M, T1.getRootId(), T2.getRootId());
843 boolMatched = M.hasSrc(Id1);
844 const Node&N1 = T1.getNode(Id1);
845 boolMatchedChildren = llvm::any_of(
846N1.Children, [&](NodeId Child) { return M.hasSrc(Child); });
847 if(Matched || !MatchedChildren)
849NodeId Id2 = findCandidate(M, Id1);
852addOptimalMapping(M, Id1, Id2);
857Mapping ASTDiff::Impl::matchTopDown()
const{
861Mapping M(T1.getSize() + T2.getSize());
863L1.push(T1.getRootId());
864L2.push(T2.getRootId());
867 while(std::min(Max1 = L1.peekMax(), Max2 = L2.peekMax()) >
870 for(NodeId
Id: L1.pop())
875 for(NodeId
Id: L2.pop())
879std::vector<NodeId> H1, H2;
882 for(NodeId Id1 : H1) {
883 for(NodeId Id2 : H2) {
884 if(identical(Id1, Id2) && !M.hasSrc(Id1) && !M.hasDst(Id2)) {
885 for(
intI = 0,
E= T1.getNumberOfDescendants(Id1); I <
E; ++I)
886M.link(Id1 + I, Id2 + I);
890 for(NodeId Id1 : H1) {
894 for(NodeId Id2 : H2) {
904: T1(T1), T2(T2), Options(Options) {
910TheMapping = matchTopDown();
911 if(Options.StopAfterTopDown)
913matchBottomUp(TheMapping);
918 if(!M.hasSrc(Id1)) {
919T1.getMutableNode(Id1).Change =
Delete;
920T1.getMutableNode(Id1).Shift -= 1;
924 if(!M.hasDst(Id2)) {
925T2.getMutableNode(Id2).Change =
Insert;
926T2.getMutableNode(Id2).Shift -= 1;
929 for(
NodeIdId1 : T1.NodesBfs) {
930 NodeIdId2 = M.getDst(Id1);
933 if(!haveSameParents(M, Id1, Id2) ||
934T1.findPositionInParent(Id1,
true) !=
935T2.findPositionInParent(Id2,
true)) {
936T1.getMutableNode(Id1).Shift -= 1;
937T2.getMutableNode(Id2).Shift -= 1;
940 for(
NodeIdId2 : T2.NodesBfs) {
941 NodeIdId1 = M.getSrc(Id2);
944 Node&N1 = T1.getMutableNode(Id1);
945 Node&N2 = T2.getMutableNode(Id2);
948 if(!haveSameParents(M, Id1, Id2) ||
949T1.findPositionInParent(Id1,
true) !=
950T2.findPositionInParent(Id2,
true)) {
953 if(T1.getNodeValue(Id1) != T2.getNodeValue(Id2)) {
961: DiffImpl(
std::make_unique<
Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {}
971this, AST.getTranslationUnitDecl(), AST)) {}
992std::pair<unsigned, unsigned>
1000 if(ThisExpr->isImplicit())
1005 return{
Begin, End};
llvm::DenseSet< const void * > Visited
llvm::MachO::Record Record
static Expected< DynTypedNode > getNode(const ast_matchers::BoundNodes &Nodes, StringRef ID)
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
Represents a C++ base or member initializer.
bool isWritten() const
Determine whether this initializer is explicitly written in the source code.
Represents the this expression in C++.
Represents a character-granular source range.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Decl - This represents one declaration (or definition), e.g.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
DeclContext * getDeclContext()
const T * get() const
Retrieve the stored node as type T.
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
This represents a decl that may have a name.
std::string getQualifiedNameAsString() const
A (possibly-)qualified type.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
bool TraverseConstructorInitializer(CXXCtorInitializer *Init)
Recursively visit a constructor initializer.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Stmt - This represents one statement.
QualType getCanonicalTypeInternal() const
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
void computeChangeKinds(Mapping &M)
NodeId getMapped(const std::unique_ptr< SyntaxTree::Impl > &Tree, NodeId Id) const
Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2, const ComparisonOptions &Options)
void computeMapping()
Matches nodes one-by-one based on their similarity.
ASTDiff(SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options)
NodeId getMapped(const SyntaxTree &SourceTree, NodeId Id) const
const Node & getNode(SNodeId Id) const
SNodeId getLeftMostDescendant(SNodeId Id) const
Subtree(const SyntaxTree::Impl &Tree, NodeId SubtreeRoot)
std::vector< SNodeId > KeyRoots
NodeId getPostorderOffset() const
Returns the postorder index of the leftmost descendant in the subtree.
NodeId getIdInRoot(SNodeId Id) const
std::string getNodeValue(SNodeId Id) const
Represents the AST of a TranslationUnit.
std::string getRelativeName(const NamedDecl *ND, const DeclContext *Context) const
int getNumberOfDescendants(NodeId Id) const
bool isValidNodeId(NodeId Id) const
std::vector< NodeId > Leaves
bool isInSubtree(NodeId Id, NodeId SubtreeRoot) const
PreorderIterator begin() const
std::vector< Node > Nodes
Nodes in preorder.
PreorderIterator end() const
int findPositionInParent(NodeId Id, bool Shifted=false) const
const Node & getNode(NodeId Id) const
std::string getStmtValue(const Stmt *S) const
std::vector< int > PostorderIds
std::string getNodeValue(NodeId Id) const
Impl(SyntaxTree *Parent, std::enable_if_t< std::is_base_of_v< Decl, T >, T > *Node, ASTContext &AST)
Impl(SyntaxTree *Parent, std::enable_if_t< std::is_base_of_v< Stmt, T >, T > *Node, ASTContext &AST)
std::string getDeclValue(const Decl *D) const
std::vector< NodeId > NodesBfs
Impl(SyntaxTree *Parent, ASTContext &AST)
Node & getMutableNode(NodeId Id)
SyntaxTree objects represent subtrees of the AST.
const Node & getNode(NodeId Id) const
int findPositionInParent(NodeId Id) const
const ASTContext & getASTContext() const
PreorderIterator begin() const
std::pair< unsigned, unsigned > getSourceRangeOffsets(const Node &N) const
SyntaxTree(ASTContext &AST)
Constructs a tree from a translation unit.
std::unique_ptr< Impl > TreeImpl
PreorderIterator end() const
std::string getNodeValue(NodeId Id) const
Serialize the node attributes to a string representation.
Implementation of Zhang and Shasha's Algorithm for tree edit distance.
ZhangShashaMatcher(const ASTDiff::Impl &DiffImpl, const SyntaxTree::Impl &T1, const SyntaxTree::Impl &T2, NodeId Id1, NodeId Id2)
std::vector< std::pair< NodeId, NodeId > > getMatchingNodes()
static bool isSpecializedNodeExcluded(const Decl *D)
static const DeclContext * getEnclosingDeclContext(ASTContext &AST, const Stmt *S)
DynTypedNode DynTypedNode
static std::vector< NodeId > getSubtreePostorder(const SyntaxTree::Impl &Tree, NodeId Root)
static std::vector< NodeId > getSubtreeBfs(const SyntaxTree::Impl &Tree, NodeId Root)
static bool isNodeExcluded(const SourceManager &SrcMgr, T *N)
static std::string getInitializerValue(const CXXCtorInitializer *Init, const PrintingPolicy &TypePP)
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
@ Other
Other implicit parameter.
bool link(llvm::ArrayRef< const char * > args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput)
Diagnostic wrappers for TextAPI types for error reporting.
Describes how types, statements, expressions, and declarations should be printed.
unsigned AnonymousTagLocations
When printing an anonymous tag name, also print the location of that entity (e.g.,...
Within a tree, this identifies a node by its preorder offset.
Represents a Clang AST node, alongside some additional information.
NodeId RightMostDescendant
std::optional< std::string > getQualifiedIdentifier() const
std::optional< StringRef > getIdentifier() const
ASTNodeKind getType() const
NodeId LeftMostDescendant
StringRef getTypeLabel() const
SmallVector< NodeId, 4 > Children
Identifies a node in a subtree by its postorder offset, starting at 1.
SNodeId operator+(int Other) const
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4