johannes created this revision.
Herald added a subscriber: klimek.

TemplateName and TemplateArgument are recognised.


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
@@ -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,21 +212,16 @@
   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)};
 }
 
@@ -230,13 +234,13 @@
 
   PreorderVisitor(SyntaxTree::Impl &Tree) : 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,7 +272,7 @@
   bool TraverseDecl(Decl *D) {
     if (isNodeExcluded(Tree.AST, D))
       return true;
-    auto SavedState = PreTraverse(D);
+    auto SavedState = PreTraverse(*D);
     RecursiveASTVisitor<PreorderVisitor>::TraverseDecl(D);
     PostTraverse(SavedState);
     return true;
@@ -278,20 +282,50 @@
       S = S->IgnoreImplicit();
     if (isNodeExcluded(Tree.AST, S))
       return true;
-    auto SavedState = PreTraverse(S);
+    auto SavedState = PreTraverse(*S);
     RecursiveASTVisitor<PreorderVisitor>::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);
+    auto SavedState = PreTraverse(*Init);
     RecursiveASTVisitor<PreorderVisitor>::TraverseConstructorInitializer(Init);
     PostTraverse(SavedState);
     return true;
   }
+// We want nodes to be in the same order as in the source code.
+// So we traverse template parameters before the remainder of the declaration.
+#define DEF_TRAVERSE_TMPL_DECL_(TMPLDECLKIND)                                  \
+  bool Traverse##TMPLDECLKIND##TemplateDecl(TMPLDECLKIND##TemplateDecl *TD) {  \
+    /* No need to check return value, always true. */                          \
+    TraverseTemplateParameterListHelper(TD->getTemplateParameters());          \
+    TraverseDecl(TD->getTemplatedDecl());                                      \
+    return true;                                                               \
+  }
+  DEF_TRAVERSE_TMPL_DECL_(Class)
+  DEF_TRAVERSE_TMPL_DECL_(Var)
+  DEF_TRAVERSE_TMPL_DECL_(Function)
+#undef DEF_TRAVERSE_TMPL_DECL_
+  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+    if (isNodeExcluded(Tree.AST, &ArgLoc))
+      return true;
+    Tree.TemplateArgumentLocations.emplace(Id, ArgLoc.getSourceRange());
+    auto SavedState = PreTraverse(ArgLoc.getArgument());
+    RecursiveASTVisitor<PreorderVisitor>::TraverseTemplateArgumentLoc(ArgLoc);
+    PostTraverse(SavedState);
+    return true;
+  }
+  bool TraverseTemplateName(TemplateName Template) {
+    if (isNodeExcluded(Tree.AST, &Template))
+      return true;
+    auto SavedState = PreTraverse(Template);
+    RecursiveASTVisitor<PreorderVisitor>::TraverseTemplateName(Template);
+    PostTraverse(SavedState);
+    return true;
+  }
 };
 } // end anonymous namespace
 
@@ -441,14 +475,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 +500,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 +578,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 +637,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()));
   }
@@ -1201,7 +1252,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
  • [PATCH] D37003: [cla... Johannes Altmanninger via Phabricator via cfe-commits

Reply via email to