Index: lib/Tooling/ASTDiff/ASTDiff.cpp =================================================================== --- lib/Tooling/ASTDiff/ASTDiff.cpp +++ lib/Tooling/ASTDiff/ASTDiff.cpp @@ -13,7 +13,7 @@ #include "clang/Tooling/ASTDiff/ASTDiff.h" -#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/PriorityQueue.h" #include "llvm/Support/MD5.h" @@ -141,6 +141,7 @@ // Maps preorder indices to postorder ones. std::vector PostorderIds; NodeList NodesBfs; + std::map TemplateArgumentLocations; int getSize() const { return Nodes.size(); } NodeRef getRoot() const { return getNode(getRootId()); } @@ -175,6 +176,13 @@ static bool isSpecializedNodeExcluded(CXXCtorInitializer *I) { return !I->isWritten(); } +static bool isSpecializedNodeExcluded(const TemplateArgumentLoc *S) { + return false; +} + +static bool isNodeExcluded(ASTUnit &AST, TemplateName *Template) { + return false; +} template static bool isNodeExcluded(ASTUnit &AST, T *N) { const SourceManager &SM = AST.getSourceManager(); @@ -194,20 +202,24 @@ namespace { // Sets Height, Parent and Children for each node. -struct PreorderVisitor : public RecursiveASTVisitor { +struct PreorderVisitor + : public LexicallyOrderedRecursiveASTVisitor { + using BaseType = LexicallyOrderedRecursiveASTVisitor; + int Id = 0, Depth = 0; NodeId Parent; SyntaxTree::Impl &Tree; - PreorderVisitor(SyntaxTree::Impl &Tree) : Tree(Tree) {} + PreorderVisitor(SyntaxTree::Impl &Tree) + : BaseType(Tree.AST.getSourceManager()), Tree(Tree) {} - template std::tuple PreTraverse(T *ASTNode) { + template std::tuple PreTraverse(const T &ASTNode) { NodeId MyId = Id; Tree.Nodes.emplace_back(Tree); Node &N = Tree.getMutableNode(MyId); N.Parent = Parent; N.Depth = Depth; - N.ASTNode = DynTypedNode::create(*ASTNode); + N.ASTNode = DynTypedNode::create(ASTNode); assert(!N.ASTNode.getNodeKind().isNone() && "Expected nodes to have a valid kind."); if (Parent.isValid()) { @@ -239,8 +251,8 @@ bool TraverseDecl(Decl *D) { if (isNodeExcluded(Tree.AST, D)) return true; - auto SavedState = PreTraverse(D); - RecursiveASTVisitor::TraverseDecl(D); + auto SavedState = PreTraverse(*D); + BaseType::TraverseDecl(D); PostTraverse(SavedState); return true; } @@ -249,8 +261,8 @@ S = S->IgnoreImplicit(); if (isNodeExcluded(Tree.AST, S)) return true; - auto SavedState = PreTraverse(S); - RecursiveASTVisitor::TraverseStmt(S); + auto SavedState = PreTraverse(*S); + BaseType::TraverseStmt(S); PostTraverse(SavedState); return true; } @@ -258,8 +270,25 @@ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { if (isNodeExcluded(Tree.AST, Init)) return true; - auto SavedState = PreTraverse(Init); - RecursiveASTVisitor::TraverseConstructorInitializer(Init); + auto SavedState = PreTraverse(*Init); + BaseType::TraverseConstructorInitializer(Init); + PostTraverse(SavedState); + return true; + } + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { + if (isNodeExcluded(Tree.AST, &ArgLoc)) + return true; + Tree.TemplateArgumentLocations.emplace(Id, ArgLoc.getSourceRange()); + auto SavedState = PreTraverse(ArgLoc.getArgument()); + BaseType::TraverseTemplateArgumentLoc(ArgLoc); + PostTraverse(SavedState); + return true; + } + bool TraverseTemplateName(TemplateName Template) { + if (isNodeExcluded(Tree.AST, &Template)) + return true; + auto SavedState = PreTraverse(Template); + BaseType::TraverseTemplateName(Template); PostTraverse(SavedState); return true; } Index: test/Tooling/Inputs/clang-diff-basic-src.cpp =================================================================== --- test/Tooling/Inputs/clang-diff-basic-src.cpp +++ test/Tooling/Inputs/clang-diff-basic-src.cpp @@ -41,3 +41,16 @@ M1; F(1, 1); } + +template +U visit(T &t) { + int x = t; + return U(); +} + +void tmp() { + int x; + visit(x); +} + +int x = 1; Index: test/Tooling/clang-diff-ast.cpp =================================================================== --- test/Tooling/clang-diff-ast.cpp +++ test/Tooling/clang-diff-ast.cpp @@ -93,3 +93,16 @@ // CHECK-NEXT: FunctionDecl(64) void sentinel(); #endif + +// CHECK-NEXT: ClassTemplateDecl(65) +// CHECK-NEXT: TemplateTypeParmDecl(66) +// CHECK-NEXT: CXXRecordDecl(67) +template class C { + // CHECK-NEXT: FieldDecl(68) + T t; +}; + +// CHECK-NEXT: CXXRecordDecl(69) +// CHECK-NEXT: TemplateName(70) +// CHECK-NEXT: TemplateArgument(71) +class I : C {}; Index: test/Tooling/clang-diff-basic.cpp =================================================================== --- test/Tooling/clang-diff-basic.cpp +++ test/Tooling/clang-diff-basic.cpp @@ -1,4 +1,4 @@ -// RUN: clang-diff -dump-matches %S/Inputs/clang-diff-basic-src.cpp %s -- | FileCheck %s +// RUN: clang-diff -dump-matches %S/Inputs/clang-diff-basic-src.cpp %s -- -std=c++11 | FileCheck %s // CHECK: Match TranslationUnitDecl(0) to TranslationUnitDecl(0) // CHECK: Match NamespaceDecl(1) to NamespaceDecl(1) @@ -68,5 +68,18 @@ F(1, /*b=*/1); } +// CHECK: Match TemplateTypeParmDecl(77) +template +U visit(Type &t) { + int x = t; + return U(); +} + +void tmp() { + long x; + // CHECK: Match TemplateArgument(93) + visit(x); +} + // CHECK: Delete AccessSpecDecl(39) // CHECK: Delete CXXMethodDecl(42) Index: test/Tooling/clang-diff-html.test =================================================================== --- test/Tooling/clang-diff-html.test +++ test/Tooling/clang-diff-html.test @@ -1,4 +1,4 @@ -RUN: clang-diff -html %S/Inputs/clang-diff-basic-src.cpp %S/clang-diff-basic.cpp -- | FileCheck %s +RUN: clang-diff -html %S/Inputs/clang-diff-basic-src.cpp %S/clang-diff-basic.cpp -- -std=c++11 | FileCheck %s CHECK: