18 #include "llvm/ADT/PriorityQueue.h" 22 #include <unordered_set> 25 using namespace clang;
35 Mapping(Mapping &&Other) =
default;
36 Mapping &operator=(Mapping &&Other) =
default;
38 Mapping(
size_t Size) {
39 SrcToDst = llvm::make_unique<NodeId[]>(Size);
40 DstToSrc = llvm::make_unique<NodeId[]>(Size);
43 void link(NodeId Src, NodeId Dst) {
44 SrcToDst[Src] = Dst, DstToSrc[Dst] = Src;
47 NodeId getDst(NodeId Src)
const {
return SrcToDst[Src]; }
48 NodeId getSrc(NodeId Dst)
const {
return DstToSrc[Dst]; }
49 bool hasSrc(NodeId Src)
const {
return getDst(Src).isValid(); }
50 bool hasDst(NodeId Dst)
const {
return getSrc(Dst).isValid(); }
53 std::unique_ptr<NodeId[]> SrcToDst, DstToSrc;
66 void computeMapping();
69 void computeChangeKinds(Mapping &M);
74 return TheMapping.getDst(Id);
75 assert(&*Tree == &T2 &&
"Invalid tree.");
76 return TheMapping.getSrc(Id);
87 bool haveSameParents(
const Mapping &M,
NodeId Id1,
NodeId Id2)
const;
91 void addOptimalMapping(Mapping &M,
NodeId Id1,
NodeId Id2)
const;
95 double getJaccardSimilarity(
const Mapping &M,
NodeId Id1,
NodeId Id2)
const;
98 NodeId findCandidate(
const Mapping &M,
NodeId Id1)
const;
101 Mapping matchTopDown()
const;
104 void matchBottomUp(Mapping &M)
const;
120 typename std::enable_if<std::is_base_of<Stmt, T>::value,
T>::
type *
Node,
122 :
Impl(Parent, dyn_cast<
Stmt>(Node), AST) {}
125 typename std::enable_if<std::is_base_of<Decl, T>::value,
T>::
type *
Node,
127 :
Impl(Parent, dyn_cast<
Decl>(Node), AST) {}
148 int getNumberOfDescendants(
NodeId Id)
const;
150 int findPositionInParent(
NodeId Id,
bool Shifted =
false)
const;
152 std::string getRelativeName(
const NamedDecl *ND,
154 std::string getRelativeName(
const NamedDecl *ND)
const;
156 std::string getNodeValue(
NodeId Id)
const;
157 std::string getNodeValue(
const Node &
Node)
const;
158 std::string getDeclValue(
const Decl *D)
const;
159 std::string getStmtValue(
const Stmt *S)
const;
163 void setLeftMostDescendants();
195 PreorderVisitor(SyntaxTree::Impl &Tree) : Tree(Tree) {}
197 template <
class T> std::tuple<NodeId, NodeId> PreTraverse(
T *ASTNode) {
199 Tree.Nodes.emplace_back();
200 Node &N = Tree.getMutableNode(MyId);
204 assert(!N.ASTNode.getNodeKind().isNone() &&
205 "Expected nodes to have a valid kind.");
206 if (Parent.isValid()) {
207 Node &
P = Tree.getMutableNode(Parent);
208 P.Children.push_back(MyId);
213 return std::make_tuple(MyId, Tree.getNode(MyId).Parent);
215 void PostTraverse(std::tuple<NodeId, NodeId>
State) {
216 NodeId MyId, PreviousParent;
217 std::tie(MyId, PreviousParent) =
State;
218 assert(MyId.isValid() &&
"Expecting to only traverse valid nodes.");
219 Parent = PreviousParent;
221 Node &N = Tree.getMutableNode(MyId);
222 N.RightMostDescendant = Id - 1;
223 assert(N.RightMostDescendant >= 0 &&
224 N.RightMostDescendant < Tree.getSize() &&
225 "Rightmost descendant must be a valid tree node.");
227 Tree.Leaves.push_back(MyId);
229 for (NodeId Child : N.Children)
230 N.Height =
std::max(N.Height, 1 + Tree.getNode(Child).Height);
232 bool TraverseDecl(
Decl *D) {
235 auto SavedState = PreTraverse(D);
237 PostTraverse(SavedState);
240 bool TraverseStmt(
Stmt *S) {
245 auto SavedState = PreTraverse(S);
247 PostTraverse(SavedState);
250 bool TraverseType(
QualType T) {
return true; }
254 auto SavedState = PreTraverse(Init);
256 PostTraverse(SavedState);
263 : Parent(Parent), AST(AST), TypePP(AST.getLangOpts()) {
268 :
Impl(Parent, AST) {
269 PreorderVisitor PreorderWalker(*
this);
270 PreorderWalker.TraverseDecl(N);
275 :
Impl(Parent, AST) {
276 PreorderVisitor PreorderWalker(*
this);
277 PreorderWalker.TraverseStmt(N);
283 std::vector<NodeId> Postorder;
284 std::function<void(NodeId)> Traverse = [&](
NodeId Id) {
288 Postorder.push_back(
Id);
296 std::vector<NodeId> Ids;
299 while (Expanded < Ids.size())
301 Ids.push_back(Child);
305 void SyntaxTree::Impl::initTree() {
306 setLeftMostDescendants();
309 std::function<void(NodeId)> PostorderTraverse = [&](
NodeId Id) {
311 PostorderTraverse(Child);
319 void SyntaxTree::Impl::setLeftMostDescendants() {
323 while ((Parent =
getNode(Cur).Parent).isValid() &&
324 getNode(Parent).Children[0] == Cur) {
345 for (
size_t I = 0, E = Siblings.size(); I < E; ++I) {
348 if (Siblings[I] == Id) {
353 llvm_unreachable(
"Node not found in parent's children.");
362 std::string ContextPrefix;
365 if (
auto *Namespace = dyn_cast<NamespaceDecl>(Context))
366 ContextPrefix = Namespace->getQualifiedNameAsString();
367 else if (
auto *Record = dyn_cast<RecordDecl>(Context))
368 ContextPrefix = Record->getQualifiedNameAsString();
370 if (
auto *Tag = dyn_cast<TagDecl>(Context))
371 ContextPrefix = Tag->getQualifiedNameAsString();
375 if (!ContextPrefix.empty() && StringRef(Val).startswith(ContextPrefix))
376 Val = Val.substr(ContextPrefix.size() + 1);
390 const auto &
P = Parents[0];
391 if (
const auto *D =
P.get<
Decl>())
392 return D->getDeclContext();
406 llvm_unreachable(
"Unknown initializer type");
421 llvm_unreachable(
"Fatal: unhandled AST node.\n");
426 if (
auto *V = dyn_cast<ValueDecl>(D))
428 if (
auto *N = dyn_cast<NamedDecl>(D))
430 if (
auto *
T = dyn_cast<TypedefNameDecl>(D))
431 return Value +
T->getUnderlyingType().getAsString(
TypePP) +
";";
432 if (
auto *
T = dyn_cast<TypeDecl>(D))
433 if (
T->getTypeForDecl())
437 if (
auto *U = dyn_cast<UsingDirectiveDecl>(D))
438 return U->getNominatedNamespace()->getName();
439 if (
auto *A = dyn_cast<AccessSpecDecl>(D)) {
448 if (
auto *U = dyn_cast<UnaryOperator>(S))
450 if (
auto *B = dyn_cast<BinaryOperator>(S))
451 return B->getOpcodeStr();
452 if (
auto *M = dyn_cast<MemberExpr>(S))
454 if (
auto *I = dyn_cast<IntegerLiteral>(S)) {
456 I->getValue().toString(Str, 10,
false);
459 if (
auto *F = dyn_cast<FloatingLiteral>(S)) {
461 F->getValue().toString(Str);
464 if (
auto *D = dyn_cast<DeclRefExpr>(S))
466 if (
auto *String = dyn_cast<StringLiteral>(S))
467 return String->getString();
468 if (
auto *B = dyn_cast<CXXBoolLiteralExpr>(S))
469 return B->getValue() ?
"true" :
"false";
480 operator int()
const {
return Id; }
491 std::vector<NodeId> RootIds;
493 std::vector<SNodeId> LeftMostDescendants;
500 int NumLeaves = setLeftMostDescendants();
501 computeKeyRoots(NumLeaves);
503 int getSize()
const {
return RootIds.size(); }
505 assert(Id > 0 && Id <=
getSize() &&
"Invalid subtree node index.");
506 return RootIds[Id - 1];
509 return Tree.
getNode(getIdInRoot(Id));
512 assert(Id > 0 && Id <=
getSize() &&
"Invalid subtree node index.");
513 return LeftMostDescendants[Id - 1];
525 int setLeftMostDescendants() {
527 LeftMostDescendants.resize(
getSize());
528 for (
int I = 0; I <
getSize(); ++I) {
532 assert(I == Tree.
PostorderIds[getIdInRoot(SI)] - getPostorderOffset() &&
533 "Postorder traversal in subtree should correspond to traversal in " 534 "the root tree by a constant offset.");
536 getPostorderOffset());
540 void computeKeyRoots(
int Leaves) {
541 KeyRoots.resize(Leaves);
542 std::unordered_set<int> Visited;
545 SNodeId LeftDesc = getLeftMostDescendant(I);
546 if (Visited.count(LeftDesc))
548 assert(K >= 0 &&
"K should be non-negative");
550 Visited.insert(LeftDesc);
563 std::unique_ptr<std::unique_ptr<double[]>[]> TreeDist, ForestDist;
568 : DiffImpl(DiffImpl), S1(T1, Id1), S2(T2, Id2) {
569 TreeDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
571 ForestDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
573 for (
int I = 0, E = S1.
getSize() + 1; I < E; ++I) {
574 TreeDist[I] = llvm::make_unique<double[]>(
size_t(S2.
getSize()) + 1);
575 ForestDist[I] = llvm::make_unique<double[]>(
size_t(S2.
getSize()) + 1);
580 std::vector<std::pair<NodeId, NodeId>> Matches;
581 std::vector<std::pair<SNodeId, SNodeId>> TreePairs;
585 bool RootNodePair =
true;
589 while (!TreePairs.empty()) {
590 SNodeId LastRow, LastCol, FirstRow, FirstCol, Row, Col;
591 std::tie(LastRow, LastCol) = TreePairs.back();
592 TreePairs.pop_back();
595 computeForestDist(LastRow, LastCol);
598 RootNodePair =
false;
606 while (Row > FirstRow || Col > FirstCol) {
607 if (Row > FirstRow &&
608 ForestDist[Row - 1][Col] + 1 == ForestDist[Row][Col]) {
610 }
else if (Col > FirstCol &&
611 ForestDist[Row][Col - 1] + 1 == ForestDist[Row][Col]) {
620 assert(DiffImpl.isMatchingPossible(Id1, Id2) &&
621 "These nodes must not be matched.");
622 Matches.emplace_back(Id1, Id2);
626 TreePairs.emplace_back(Row, Col);
642 static constexpr
double DeletionCost = 1;
643 static constexpr
double InsertionCost = 1;
651 void computeTreeDist() {
654 computeForestDist(Id1, Id2);
658 assert(Id1 > 0 && Id2 > 0 &&
"Expecting offsets greater than 0.");
662 ForestDist[LMD1][LMD2] = 0;
663 for (
SNodeId D1 = LMD1 + 1; D1 <= Id1; ++D1) {
664 ForestDist[D1][LMD2] = ForestDist[D1 - 1][LMD2] + DeletionCost;
665 for (
SNodeId D2 = LMD2 + 1; D2 <= Id2; ++D2) {
666 ForestDist[LMD1][D2] = ForestDist[LMD1][D2 - 1] + InsertionCost;
669 if (DLMD1 == LMD1 && DLMD2 == LMD2) {
670 double UpdateCost = getUpdateCost(D1, D2);
672 std::min({ForestDist[D1 - 1][D2] + DeletionCost,
673 ForestDist[D1][D2 - 1] + InsertionCost,
674 ForestDist[D1 - 1][D2 - 1] + UpdateCost});
675 TreeDist[D1][D2] = ForestDist[D1][D2];
678 std::min({ForestDist[D1 - 1][D2] + DeletionCost,
679 ForestDist[D1][D2 - 1] + InsertionCost,
680 ForestDist[DLMD1][DLMD2] + TreeDist[D1][D2]});
688 return ASTNode.getNodeKind();
694 if (
auto *ND = ASTNode.get<
NamedDecl>()) {
695 if (ND->getDeclName().isIdentifier())
696 return ND->getQualifiedNameAsString();
702 if (
auto *ND = ASTNode.get<
NamedDecl>()) {
703 if (ND->getDeclName().isIdentifier())
704 return ND->getName();
725 std::vector<NodeId> Container;
726 PriorityQueue<NodeId, std::vector<NodeId>, HeightLess> List;
730 :
Tree(Tree), Cmp(Tree), List(Cmp, Container) {}
732 void push(
NodeId id) { List.push(
id); }
734 std::vector<NodeId> pop() {
736 std::vector<NodeId> Result;
739 while (peekMax() == Max) {
740 Result.push_back(List.top());
744 std::sort(Result.begin(), Result.end());
747 int peekMax()
const {
750 return Tree.
getNode(List.top()).Height;
759 bool ASTDiff::Impl::identical(
NodeId Id1,
NodeId Id2)
const {
760 const Node &N1 = T1.getNode(Id1);
761 const Node &N2 = T2.getNode(Id2);
763 !isMatchingPossible(Id1, Id2) ||
764 T1.getNodeValue(Id1) != T2.getNodeValue(Id2))
772 bool ASTDiff::Impl::isMatchingPossible(
NodeId Id1,
NodeId Id2)
const {
773 return Options.isMatchingAllowed(T1.getNode(Id1), T2.getNode(Id2));
776 bool ASTDiff::Impl::haveSameParents(
const Mapping &M,
NodeId Id1,
778 NodeId P1 = T1.getNode(Id1).Parent;
779 NodeId P2 = T2.getNode(Id2).Parent;
784 void ASTDiff::Impl::addOptimalMapping(Mapping &M,
NodeId Id1,
786 if (
std::max(T1.getNumberOfDescendants(Id1), T2.getNumberOfDescendants(Id2)) >
791 for (
const auto Tuple : R) {
793 NodeId Dst = Tuple.second;
794 if (!M.hasSrc(Src) && !M.hasDst(Dst))
799 double ASTDiff::Impl::getJaccardSimilarity(
const Mapping &M,
NodeId Id1,
801 int CommonDescendants = 0;
802 const Node &N1 = T1.getNode(Id1);
805 NodeId Dst = M.getDst(Src);
806 CommonDescendants += int(Dst.
isValid() && T2.isInSubtree(Dst, Id2));
809 double Denominator = T1.getNumberOfDescendants(Id1) - 1 +
810 T2.getNumberOfDescendants(Id2) - 1 - CommonDescendants;
812 assert(Denominator >= 0 &&
"Expected non-negative denominator.");
813 if (Denominator == 0)
815 return CommonDescendants / Denominator;
818 NodeId ASTDiff::Impl::findCandidate(
const Mapping &M,
NodeId Id1)
const {
820 double HighestSimilarity = 0.0;
822 if (!isMatchingPossible(Id1, Id2))
826 double Similarity = getJaccardSimilarity(M, Id1, Id2);
827 if (Similarity >= Options.MinSimilarity && Similarity > HighestSimilarity) {
828 HighestSimilarity = Similarity;
835 void ASTDiff::Impl::matchBottomUp(Mapping &M)
const {
837 for (
NodeId Id1 : Postorder) {
838 if (Id1 == T1.getRootId() && !M.hasSrc(T1.getRootId()) &&
839 !M.hasDst(T2.getRootId())) {
840 if (isMatchingPossible(T1.getRootId(), T2.getRootId())) {
841 M.link(T1.getRootId(), T2.getRootId());
842 addOptimalMapping(M, T1.getRootId(), T2.getRootId());
846 bool Matched = M.hasSrc(Id1);
847 const Node &N1 = T1.getNode(Id1);
848 bool MatchedChildren =
850 [&](
NodeId Child) {
return M.hasSrc(Child); });
851 if (Matched || !MatchedChildren)
853 NodeId Id2 = findCandidate(M, Id1);
856 addOptimalMapping(M, Id1, Id2);
861 Mapping ASTDiff::Impl::matchTopDown()
const {
865 Mapping M(T1.getSize() + T2.getSize());
867 L1.push(T1.getRootId());
868 L2.push(T2.getRootId());
871 while (
std::min(Max1 = L1.peekMax(), Max2 = L2.peekMax()) >
883 std::vector<NodeId> H1, H2;
888 if (identical(Id1, Id2) && !M.hasSrc(Id1) && !M.hasDst(Id2)) {
889 for (
int I = 0, E = T1.getNumberOfDescendants(Id1); I < E; ++I)
890 M.link(Id1 + I, Id2 + I);
908 : T1(T1), T2(T2), Options(Options) {
922 if (!M.hasSrc(Id1)) {
923 T1.getMutableNode(Id1).Change =
Delete;
924 T1.getMutableNode(Id1).Shift -= 1;
928 if (!M.hasDst(Id2)) {
929 T2.getMutableNode(Id2).Change =
Insert;
930 T2.getMutableNode(Id2).Shift -= 1;
933 for (
NodeId Id1 : T1.NodesBfs) {
934 NodeId Id2 = M.getDst(Id1);
937 if (!haveSameParents(M, Id1, Id2) ||
938 T1.findPositionInParent(Id1,
true) !=
939 T2.findPositionInParent(Id2,
true)) {
940 T1.getMutableNode(Id1).Shift -= 1;
941 T2.getMutableNode(Id2).Shift -= 1;
944 for (
NodeId Id2 : T2.NodesBfs) {
945 NodeId Id1 = M.getSrc(Id2);
948 Node &N1 = T1.getMutableNode(Id1);
949 Node &N2 = T2.getMutableNode(Id2);
952 if (!haveSameParents(M, Id1, Id2) ||
953 T1.findPositionInParent(Id1,
true) !=
954 T2.findPositionInParent(Id2,
true)) {
957 if (T1.getNodeValue(Id1) != T2.getNodeValue(Id2)) {
965 : DiffImpl(
llvm::make_unique<
Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {}
970 return DiffImpl->getMapped(SourceTree.
TreeImpl, Id);
975 this, AST.getTranslationUnitDecl(), AST)) {}
993 return TreeImpl->findPositionInParent(Id);
996 std::pair<unsigned, unsigned>
1004 if (ThisExpr->isImplicit())
1009 return {
Begin, End};
bool isBaseInitializer() const
Determine whether this initializer is initializing a base class.
llvm::Optional< std::string > getQualifiedIdentifier() const
A (possibly-)qualified type.
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
const Node & getNode(NodeId Id) const
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Stmt - This represents one statement.
const T * get() const
Retrieve the stored node as type T.
NodeId getMapped(const SyntaxTree &SourceTree, NodeId Id) const
Decl - This represents one declaration (or definition), e.g.
bool isInSubtree(NodeId Id, NodeId SubtreeRoot) const
ZhangShashaMatcher(const ASTDiff::Impl &DiffImpl, const SyntaxTree::Impl &T1, const SyntaxTree::Impl &T2, NodeId Id1, NodeId Id2)
bool isWritten() const
Determine whether this initializer is explicitly written in the source code.
ast_type_traits::ASTNodeKind getType() const
static std::vector< NodeId > getSubtreePostorder(const SyntaxTree::Impl &Tree, NodeId Root)
Stmt * IgnoreImplicit()
Skip past any implicit AST nodes which might surround this statement, such as ExprWithCleanups or Imp...
void computeChangeKinds(Mapping &M)
void computeMapping()
Matches nodes one-by-one based on their similarity.
llvm::Optional< StringRef > getIdentifier() const
const Node & getNode(SNodeId Id) const
std::vector< NodeId > NodesBfs
PreorderIterator end() const
std::vector< NodeId > Leaves
Describes how types, statements, expressions, and declarations should be printed. ...
NodeId getMapped(const std::unique_ptr< SyntaxTree::Impl > &Tree, NodeId Id) const
bool isValidNodeId(NodeId Id) const
std::vector< SNodeId > KeyRoots
SNodeId operator+(int Other) const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
TypeSourceInfo * getTypeSourceInfo() const
Returns the declarator information for a base class or delegating initializer.
DynTypedNodeList getParents(const NodeT &Node)
Returns the parents of the given node.
std::string getNodeValue(NodeId Id) const
std::string getNodeValue(SNodeId Id) const
Implementation of Zhang and Shasha's Algorithm for tree edit distance.
Within a tree, this identifies a node by its preorder offset.
NodeId getPostorderOffset() const
Returns the postorder index of the leftmost descendant in the subtree.
ast_type_traits::DynTypedNode ASTNode
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
std::string getNodeValue(NodeId Id) const
Serialize the node attributes to a string representation.
bool isAnyMemberInitializer() const
std::unique_ptr< Impl > TreeImpl
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
FieldDecl * getAnyMember() const
int findPositionInParent(NodeId Id) const
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
std::string getStmtValue(const Stmt *S) const
Represents the this expression in C++.
int getNumberOfDescendants(NodeId Id) const
Impl(SyntaxTree *Parent, ASTContext &AST)
static std::string getInitializerValue(const CXXCtorInitializer *Init, const PrintingPolicy &TypePP)
ASTDiff(SyntaxTree &Src, SyntaxTree &Dst, const ComparisonOptions &Options)
bool isDelegatingInitializer() const
Determine whether this initializer is creating a delegating constructor.
Impl(SyntaxTree *Parent, typename std::enable_if< std::is_base_of< Decl, T >::value, T >::type *Node, ASTContext &AST)
NodeId RightMostDescendant
PreorderIterator end() const
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Identifies a node in a subtree by its postorder offset, starting at 1.
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.
Represents a character-granular source range.
llvm::StringRef getAsString(SyncScope S)
const FunctionProtoType * T
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
static std::vector< NodeId > getSubtreeBfs(const SyntaxTree::Impl &Tree, NodeId Root)
PreorderIterator begin() const
DeclContext * getDeclContext()
const ASTContext & getASTContext() const
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
SourceRange getSourceRange() const
For nodes which represent textual entities in the source code, return their SourceRange.
SourceLocation getEnd() const
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
Encodes a location in the source.
PreorderIterator begin() const
SyntaxTree(ASTContext &AST)
Constructs a tree from a translation unit.
std::string getRelativeName(const NamedDecl *ND, const DeclContext *Context) const
std::vector< int > PostorderIds
StringRef getTypeLabel() const
std::vector< Node > Nodes
Nodes in preorder.
SyntaxTree objects represent subtrees of the AST.
SmallVector< NodeId, 4 > Children
Subtree(const SyntaxTree::Impl &Tree, NodeId SubtreeRoot)
NodeId getIdInRoot(SNodeId Id) const
bool isInMainFile(SourceLocation Loc) const
Returns whether the PresumedLoc for a given SourceLocation is in the main file.
ast_type_traits::DynTypedNode Node
static bool isNodeExcluded(const SourceManager &SrcMgr, T *N)
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
std::pair< unsigned, unsigned > getSourceRangeOffsets(const Node &N) const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Node & getMutableNode(NodeId Id)
int findPositionInParent(NodeId Id, bool Shifted=false) const
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
const Type * getBaseClass() const
If this is a base class initializer, returns the type of the base class.
Represents the AST of a TranslationUnit.
NodeId LeftMostDescendant
Impl(SyntaxTree::Impl &T1, SyntaxTree::Impl &T2, const ComparisonOptions &Options)
A dynamically typed AST node container.
SNodeId getLeftMostDescendant(SNodeId Id) const
QualType getCanonicalTypeInternal() const
Represents a C++ base or member initializer.
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
SourceManager & getSourceManager()
std::string getDeclValue(const Decl *D) const
static const DeclContext * getEnclosingDeclContext(ASTContext &AST, const Stmt *S)
std::vector< std::pair< NodeId, NodeId > > getMatchingNodes()
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
bool AnonymousTagLocations
When printing an anonymous tag name, also print the location of that entity (e.g., "enum <anonymous at t.h:10:5>").
std::string getQualifiedNameAsString() const
const Node & getNode(NodeId Id) const
A trivial tuple used to represent a source range.
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to...
NamedDecl - This represents a decl with a name.
Represents a Clang AST node, alongside some additional information.
SourceLocation getBegin() const
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.
Impl(SyntaxTree *Parent, typename std::enable_if< std::is_base_of< Stmt, T >::value, T >::type *Node, ASTContext &AST)
QualType getType() const
Return the type wrapped by this type source info.
static bool isSpecializedNodeExcluded(CXXCtorInitializer *I)