johannes updated this revision to Diff 112673. johannes edited the summary of this revision. johannes added a comment.
use LexicallyOrderedRecursiveASTVisitor https://reviews.llvm.org/D37003 Files: lib/Tooling/ASTDiff/ASTDiff.cpp test/Tooling/Inputs/clang-diff-basic-src.cpp test/Tooling/clang-diff-ast.cpp test/Tooling/clang-diff-basic.cpp test/Tooling/clang-diff-html.test
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: <pre><div id='L' class='code'><span id='L0' tid='R0' title='TranslationUnitDecl CHECK-NEXT: 0 -> 0'> 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{{.*}} to TranslationUnitDecl // CHECK: Match NamespaceDecl: src{{.*}} to NamespaceDecl: dst @@ -68,5 +68,18 @@ F(1, /*b=*/1); } +// CHECK: Update TemplateTypeParmDecl: T{{.*}} to Type +template <class Type, class U = int> +U visit(Type &t) { + int x = t; + return U(); +} + +void tmp() { + long x; + // CHECK: Update TemplateArgument: int{{.*}} to long + visit<long>(x); +} + // CHECK: Delete AccessSpecDecl: public // CHECK: Delete CXXMethodDecl Index: test/Tooling/clang-diff-ast.cpp =================================================================== --- test/Tooling/clang-diff-ast.cpp +++ test/Tooling/clang-diff-ast.cpp @@ -92,3 +92,16 @@ // CHECK-NEXT: FunctionDecl: sentinel void sentinel(); #endif + +// CHECK-NEXT: ClassTemplateDecl: C +// CHECK-NEXT: TemplateTypeParmDecl +// CHECK-NEXT: CXXRecordDecl +template <class T> class C { + // CHECK-NEXT: FieldDecl + T t; +}; + +// CHECK-NEXT: CXXRecordDecl +// CHECK-NEXT: TemplateName +// CHECK-NEXT: TemplateArgument +class I : C<int> {}; 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 <class T, class U = void> +U visit(T &t) { + int x = t; + return U(); +} + +void tmp() { + int x; + visit<int>(x); +} + +int x = 1; Index: lib/Tooling/ASTDiff/ASTDiff.cpp =================================================================== --- lib/Tooling/ASTDiff/ASTDiff.cpp +++ lib/Tooling/ASTDiff/ASTDiff.cpp @@ -15,7 +15,7 @@ #include "clang/AST/DataCollection.h" #include "clang/AST/DeclVisitor.h" -#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/PriorityQueue.h" @@ -149,6 +149,7 @@ // Maps preorder indices to postorder ones. std::vector<int> PostorderIds; std::vector<NodeId> NodesBfs; + std::map<NodeId, SourceRange> TemplateArgumentLocations; int getSize() const { return Nodes.size(); } NodeId getRootId() const { return 0; } @@ -186,6 +187,14 @@ static bool isSpecializedNodeExcluded(CXXCtorInitializer *I) { return !I->isWritten(); } +static bool isSpecializedNodeExcluded(const TemplateArgumentLoc *S) { + return false; +} + +static bool isNodeExcluded(ASTUnit &AST, TemplateName *Template) { + // TODO what if it is from another file + return false; +} template <class T> static bool isNodeExcluded(ASTUnit &AST, T *N) { const SourceManager &SrcMgr = AST.getSourceManager(); @@ -203,40 +212,39 @@ return isSpecializedNodeExcluded(N); } -static SourceRange getSourceRange(const ASTUnit &AST, const DynTypedNode &DTN) { +static SourceRange getSourceExtent(const ASTUnit &AST, SourceRange Range) { const SourceManager &SrcMgr = AST.getSourceManager(); - SourceRange Range = DTN.getSourceRange(); SourceLocation BeginLoc = Range.getBegin(); SourceLocation EndLoc; if (BeginLoc.isMacroID()) EndLoc = SrcMgr.getExpansionRange(BeginLoc).second; else EndLoc = Range.getEnd(); EndLoc = Lexer::getLocForEndOfToken(EndLoc, /*Offset=*/0, SrcMgr, AST.getLangOpts()); - if (auto *ThisExpr = DTN.get<CXXThisExpr>()) { - if (ThisExpr->isImplicit()) - EndLoc = BeginLoc; - } return {SrcMgr.getExpansionLoc(BeginLoc), SrcMgr.getExpansionLoc(EndLoc)}; } namespace { // Sets Height, Parent and Children for each node. -struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> { +struct PreorderVisitor + : public LexicallyOrderedRecursiveASTVisitor<PreorderVisitor> { + using BaseType = LexicallyOrderedRecursiveASTVisitor<PreorderVisitor>; + 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 <class T> std::tuple<NodeId, NodeId> PreTraverse(T *ASTNode) { + template <class T> std::tuple<NodeId, NodeId> PreTraverse(const T &ASTNode) { NodeId MyId = Id; Tree.Nodes.emplace_back(); 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()) { @@ -268,27 +276,44 @@ bool TraverseDecl(Decl *D) { if (isNodeExcluded(Tree.AST, D)) return true; - auto SavedState = PreTraverse(D); - RecursiveASTVisitor<PreorderVisitor>::TraverseDecl(D); + auto SavedState = PreTraverse(*D); + BaseType::TraverseDecl(D); PostTraverse(SavedState); return true; } bool TraverseStmt(Stmt *S) { if (S) S = S->IgnoreImplicit(); if (isNodeExcluded(Tree.AST, S)) return true; - auto SavedState = PreTraverse(S); - RecursiveASTVisitor<PreorderVisitor>::TraverseStmt(S); + auto SavedState = PreTraverse(*S); + BaseType::TraverseStmt(S); PostTraverse(SavedState); return true; } bool TraverseType(QualType T) { return true; } bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { if (isNodeExcluded(Tree.AST, Init)) return true; - auto SavedState = PreTraverse(Init); - RecursiveASTVisitor<PreorderVisitor>::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; } @@ -441,14 +466,22 @@ llvm_unreachable("Unknown initializer type"); } +template <class T> static std::string dumpToString(const T &Object) { + std::string Str; + llvm::raw_string_ostream OS(Str); + Object.dump(OS); + return OS.str(); +} + std::string SyntaxTree::Impl::getNodeValue(NodeId Id) const { return getNodeValue(getNode(Id)); } std::string SyntaxTree::Impl::getNodeValue(const Node &N) const { const DynTypedNode &DTN = N.ASTNode; if (N.isMacro()) { - CharSourceRange Range(getSourceRange(AST, N.ASTNode), false); + CharSourceRange Range(getSourceExtent(AST, N.ASTNode.getSourceRange()), + false); return Lexer::getSourceText(Range, AST.getSourceManager(), AST.getLangOpts()); } @@ -458,7 +491,11 @@ return getDeclValue(D); if (auto *Init = DTN.get<CXXCtorInitializer>()) return getInitializerValue(Init, TypePP); - llvm_unreachable("Fatal: unhandled AST node.\n"); + if (auto *Template = DTN.get<TemplateName>()) + return dumpToString(*Template); + if (auto *Arg = DTN.get<TemplateArgument>()) + return dumpToString(*Arg); + llvm_unreachable("getNodeValue: unhandled AST node.\n"); } std::string SyntaxTree::Impl::getDeclValue(const Decl *D) const { @@ -532,8 +569,12 @@ ConstDeclVisitor<DataCollector>::Visit(D); else if (auto *Init = DTN.get<CXXCtorInitializer>()) addData(getInitializerValue(Init, Tree.TypePP)); + else if (auto *Template = DTN.get<TemplateName>()) + addData(dumpToString(*Template)); + else if (auto *Arg = DTN.get<TemplateArgument>()) + addData(dumpToString(*Arg)); else - llvm_unreachable("Fatal: unhandled AST node.\n"); + llvm_unreachable("DataConsumer: unhandled AST node.\n"); } #define DEF_ADD_DATA(CLASS, CODE) \ @@ -587,7 +628,8 @@ HashType SyntaxTree::Impl::hashNode(const Node &N) const { const DynTypedNode &DTN = N.ASTNode; if (N.isMacro()) { - CharSourceRange Range(getSourceRange(AST, N.ASTNode), false); + CharSourceRange Range(getSourceExtent(AST, N.ASTNode.getSourceRange()), + false); return hashString( Lexer::getSourceText(Range, AST.getSourceManager(), AST.getLangOpts())); } @@ -1200,7 +1242,16 @@ std::pair<unsigned, unsigned> SyntaxTree::getSourceRangeOffsets(const Node &N) const { const SourceManager &SrcMgr = TreeImpl->AST.getSourceManager(); - SourceRange Range = getSourceRange(TreeImpl->AST, N.ASTNode); + SourceRange Range; + if (auto *Arg = N.ASTNode.get<TemplateArgument>()) + Range = TreeImpl->TemplateArgumentLocations.at(&N - &TreeImpl->Nodes[0]); + else { + Range = N.ASTNode.getSourceRange(); + if (auto *ThisExpr = N.ASTNode.get<CXXThisExpr>()) + if (ThisExpr->isImplicit()) + Range.setEnd(Range.getBegin()); + } + Range = getSourceExtent(TreeImpl->AST, Range); unsigned Begin = SrcMgr.getFileOffset(Range.getBegin()); unsigned End = SrcMgr.getFileOffset(Range.getEnd()); return {Begin, End};
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits