johannes updated this revision to Diff 121642.
johannes added a comment.

update


https://reviews.llvm.org/D36997

Files:
  include/clang/Tooling/ASTDiff/ASTDiff.h
  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
  tools/clang-diff/ClangDiff.cpp

Index: tools/clang-diff/ClangDiff.cpp
===================================================================
--- tools/clang-diff/ClangDiff.cpp
+++ tools/clang-diff/ClangDiff.cpp
@@ -467,7 +467,7 @@
     std::unique_ptr<ASTUnit> AST = getAST(CommonCompilations, SourcePath);
     if (!AST)
       return 1;
-    diff::SyntaxTree Tree(AST->getASTContext());
+    diff::SyntaxTree Tree(*AST);
     if (ASTDump) {
       printTree(llvm::outs(), Tree);
       return 0;
@@ -503,8 +503,8 @@
       return 1;
     }
   }
-  diff::SyntaxTree SrcTree(Src->getASTContext());
-  diff::SyntaxTree DstTree(Dst->getASTContext());
+  diff::SyntaxTree SrcTree(*Src);
+  diff::SyntaxTree DstTree(*Dst);
   diff::ASTDiff Diff(SrcTree, DstTree, Options);
 
   if (HtmlDiff) {
Index: test/Tooling/clang-diff-basic.cpp
===================================================================
--- test/Tooling/clang-diff-basic.cpp
+++ test/Tooling/clang-diff-basic.cpp
@@ -53,5 +53,20 @@
 void f1() {{ (void) __func__;;; }}
 }
 
+// macros are always compared by their full textual value
+
+#define M1 return 1 + 1
+#define M2 return 2 * 2
+#define F(a, b) return a + b;
+
+int f2() {
+  // CHECK: Match Macro: M1{{.*}} to Macro: M1
+  M1;
+  // CHECK: Update Macro: M1{{.*}} to M2
+  M2;
+  // CHECK: Update Macro: F(1, 1){{.*}} to F(1, /*b=*/1)
+  F(1, /*b=*/1);
+}
+
 // 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
@@ -72,12 +72,14 @@
 };
 
 #define M (void)1
-#define MA(a, b) (void)a, b
-// CHECK: FunctionDecl
-// CHECK-NEXT: CompoundStmt
+#define F(a, b) (void)a, b
 void macros() {
+  // CHECK: Macro: M(
   M;
-  MA(1, 2);
+  // two expressions, therefore it occurs twice
+  // CHECK-NEXT: Macro: F(1, 2)(
+  // CHECK-NEXT: Macro: F(1, 2)(
+  F(1, 2);
 }
 
 #ifndef GUARD
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
@@ -31,3 +31,13 @@
 int um = 1 * 2 + 3;
 
 void f1() {{ (void) __func__;;; }}
+
+#define M1 return 1 + 1
+#define M2 return 1 + 2
+#define F(a, b) return a + b;
+
+int f2() {
+  M1;
+  M1;
+  F(1, 1);
+}
Index: lib/Tooling/ASTDiff/ASTDiff.cpp
===================================================================
--- lib/Tooling/ASTDiff/ASTDiff.cpp
+++ lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -28,7 +28,7 @@
 namespace diff {
 
 bool ComparisonOptions::isMatchingAllowed(NodeRef N1, NodeRef N2) const {
-  return N1.getType().isSame(N2.getType());
+  return (N1.isMacro() && N2.isMacro()) || N1.getType().isSame(N2.getType());
 }
 
 class ASTDiff::Impl {
@@ -114,23 +114,23 @@
 /// Represents the AST of a TranslationUnit.
 class SyntaxTree::Impl {
 public:
-  Impl(SyntaxTree *Parent, ASTContext &AST);
+  Impl(SyntaxTree *Parent, ASTUnit &AST);
   /// Constructs a tree from an AST node.
-  Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST);
-  Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST);
+  Impl(SyntaxTree *Parent, Decl *N, ASTUnit &AST);
+  Impl(SyntaxTree *Parent, Stmt *N, ASTUnit &AST);
   template <class T>
   Impl(SyntaxTree *Parent,
        typename std::enable_if<std::is_base_of<Stmt, T>::value, T>::type *Node,
-       ASTContext &AST)
+       ASTUnit &AST)
       : Impl(Parent, dyn_cast<Stmt>(Node), AST) {}
   template <class T>
   Impl(SyntaxTree *Parent,
        typename std::enable_if<std::is_base_of<Decl, T>::value, T>::type *Node,
-       ASTContext &AST)
+       ASTUnit &AST)
       : Impl(Parent, dyn_cast<Decl>(Node), AST) {}
 
   SyntaxTree *Parent;
-  ASTContext &AST;
+  ASTUnit &AST;
   PrintingPolicy TypePP;
   /// Nodes in preorder.
   std::vector<Node> Nodes;
@@ -181,21 +181,40 @@
   return !I->isWritten();
 }
 
-template <class T> static bool isNodeExcluded(const SourceManager &SM, T *N) {
+template <class T> static bool isNodeExcluded(ASTUnit &AST, T *N) {
+  const SourceManager &SM = AST.getSourceManager();
   if (!N)
     return true;
   SourceLocation SLoc = N->getSourceRange().getBegin();
   if (SLoc.isValid()) {
     // Ignore everything from other files.
     if (!SM.isInMainFile(SLoc))
       return true;
-    // Ignore macros.
-    if (SLoc != SM.getSpellingLoc(SLoc))
+    const Preprocessor &PP = AST.getPreprocessor();
+    if (SLoc.isMacroID() && !PP.isAtStartOfMacroExpansion(SLoc))
       return true;
   }
   return isSpecializedNodeExcluded(N);
 }
 
+static SourceRange getSourceRange(const ASTUnit &AST, const DynTypedNode &DTN) {
+  const SourceManager &SM = AST.getSourceManager();
+  SourceRange Range = DTN.getSourceRange();
+  SourceLocation BeginLoc = Range.getBegin();
+  SourceLocation EndLoc;
+  if (BeginLoc.isMacroID())
+    EndLoc = SM.getExpansionRange(BeginLoc).second;
+  else
+    EndLoc = Range.getEnd();
+  EndLoc =
+      Lexer::getLocForEndOfToken(EndLoc, /*Offset=*/0, SM, AST.getLangOpts());
+  if (auto *ThisExpr = DTN.get<CXXThisExpr>()) {
+    if (ThisExpr->isImplicit())
+      EndLoc = BeginLoc;
+  }
+  return {SM.getExpansionLoc(BeginLoc), SM.getExpansionLoc(EndLoc)};
+}
+
 namespace {
 // Sets Height, Parent and Children for each node.
 struct PreorderVisitor : public RecursiveASTVisitor<PreorderVisitor> {
@@ -241,7 +260,7 @@
       N.Height = std::max(N.Height, 1 + Tree.getNode(Child).Height);
   }
   bool TraverseDecl(Decl *D) {
-    if (isNodeExcluded(Tree.AST.getSourceManager(), D))
+    if (isNodeExcluded(Tree.AST, D))
       return true;
     auto SavedState = PreTraverse(D);
     RecursiveASTVisitor<PreorderVisitor>::TraverseDecl(D);
@@ -251,16 +270,16 @@
   bool TraverseStmt(Stmt *S) {
     if (S)
       S = S->IgnoreImplicit();
-    if (isNodeExcluded(Tree.AST.getSourceManager(), S))
+    if (isNodeExcluded(Tree.AST, S))
       return true;
     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.getSourceManager(), Init))
+    if (isNodeExcluded(Tree.AST, Init))
       return true;
     auto SavedState = PreTraverse(Init);
     RecursiveASTVisitor<PreorderVisitor>::TraverseConstructorInitializer(Init);
@@ -270,20 +289,20 @@
 };
 } // end anonymous namespace
 
-SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTContext &AST)
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, ASTUnit &AST)
     : Parent(Parent), AST(AST), TypePP(AST.getLangOpts()), Leaves(*this),
       NodesBfs(*this) {
   TypePP.AnonymousTagLocations = false;
 }
 
-SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTContext &AST)
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, Decl *N, ASTUnit &AST)
     : Impl(Parent, AST) {
   PreorderVisitor PreorderWalker(*this);
   PreorderWalker.TraverseDecl(N);
   initTree();
 }
 
-SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST)
+SyntaxTree::Impl::Impl(SyntaxTree *Parent, Stmt *N, ASTUnit &AST)
     : Impl(Parent, AST) {
   PreorderVisitor PreorderWalker(*this);
   PreorderWalker.TraverseStmt(N);
@@ -373,10 +392,9 @@
   return getRelativeName(ND, ND->getDeclContext());
 }
 
-static const DeclContext *getEnclosingDeclContext(ASTContext &AST,
-                                                  const Stmt *S) {
+static const DeclContext *getEnclosingDeclContext(ASTUnit &AST, const Stmt *S) {
   while (S) {
-    const auto &Parents = AST.getParents(*S);
+    const auto &Parents = AST.getASTContext().getParents(*S);
     if (Parents.empty())
       return nullptr;
     const auto &P = Parents[0];
@@ -401,6 +419,11 @@
 std::string SyntaxTree::Impl::getNodeValue(NodeRef N) const {
   assert(&N.Tree == this);
   const DynTypedNode &DTN = N.ASTNode;
+  if (N.isMacro()) {
+    CharSourceRange Range(getSourceRange(AST, N.ASTNode), false);
+    return Lexer::getSourceText(Range, AST.getSourceManager(),
+                                AST.getLangOpts());
+  }
   if (auto *S = DTN.get<Stmt>())
     return getStmtValue(S);
   if (auto *D = DTN.get<Decl>())
@@ -688,17 +711,29 @@
   return ASTNode.getNodeKind();
 }
 
-StringRef Node::getTypeLabel() const { return getType().asStringRef(); }
+StringRef Node::getTypeLabel() const {
+  if (isMacro())
+    return "Macro";
+  return getType().asStringRef();
+}
+
+bool Node::isMacro() const {
+  return ASTNode.getSourceRange().getBegin().isMacroID();
+}
 
 llvm::Optional<std::string> Node::getQualifiedIdentifier() const {
+  if (isMacro())
+    return llvm::None;
   if (auto *ND = ASTNode.get<NamedDecl>()) {
     if (ND->getDeclName().isIdentifier())
       return ND->getQualifiedNameAsString();
   }
   return llvm::None;
 }
 
 llvm::Optional<StringRef> Node::getIdentifier() const {
+  if (isMacro())
+    return llvm::None;
   if (auto *ND = ASTNode.get<NamedDecl>()) {
     if (ND->getDeclName().isIdentifier())
       return ND->getName();
@@ -723,16 +758,9 @@
 
 std::pair<unsigned, unsigned> Node::getSourceRangeOffsets() const {
   const SourceManager &SM = Tree.AST.getSourceManager();
-  SourceRange Range = ASTNode.getSourceRange();
-  SourceLocation BeginLoc = Range.getBegin();
-  SourceLocation EndLoc = Lexer::getLocForEndOfToken(
-      Range.getEnd(), /*Offset=*/0, SM, Tree.AST.getLangOpts());
-  if (auto *ThisExpr = ASTNode.get<CXXThisExpr>()) {
-    if (ThisExpr->isImplicit())
-      EndLoc = BeginLoc;
-  }
-  unsigned Begin = SM.getFileOffset(SM.getExpansionLoc(BeginLoc));
-  unsigned End = SM.getFileOffset(SM.getExpansionLoc(EndLoc));
+  SourceRange Range = getSourceRange(Tree.AST, ASTNode);
+  unsigned Begin = SM.getFileOffset(Range.getBegin());
+  unsigned End = SM.getFileOffset(Range.getEnd());
   return {Begin, End};
 }
 
@@ -1083,13 +1111,17 @@
   return DiffImpl->getMapped(N);
 }
 
-SyntaxTree::SyntaxTree(ASTContext &AST)
+SyntaxTree::SyntaxTree(ASTUnit &AST)
     : TreeImpl(llvm::make_unique<SyntaxTree::Impl>(
-          this, AST.getTranslationUnitDecl(), AST)) {}
+          this, AST.getASTContext().getTranslationUnitDecl(), AST)) {}
 
 SyntaxTree::~SyntaxTree() = default;
 
-const ASTContext &SyntaxTree::getASTContext() const { return TreeImpl->AST; }
+ASTUnit &SyntaxTree::getASTUnit() const { return TreeImpl->AST; }
+
+const ASTContext &SyntaxTree::getASTContext() const {
+  return TreeImpl->AST.getASTContext();
+}
 
 NodeRef SyntaxTree::getNode(NodeId Id) const { return TreeImpl->getNode(Id); }
 
Index: include/clang/Tooling/ASTDiff/ASTDiff.h
===================================================================
--- include/clang/Tooling/ASTDiff/ASTDiff.h
+++ include/clang/Tooling/ASTDiff/ASTDiff.h
@@ -20,6 +20,7 @@
 #ifndef LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H
 #define LLVM_CLANG_TOOLING_ASTDIFF_ASTDIFF_H
 
+#include "clang/Frontend/ASTUnit.h"
 #include "clang/Tooling/ASTDiff/ASTDiffInternal.h"
 
 namespace clang {
@@ -73,14 +74,15 @@
 class SyntaxTree {
 public:
   /// Constructs a tree from a translation unit.
-  SyntaxTree(ASTContext &AST);
+  SyntaxTree(ASTUnit &AST);
   /// Constructs a tree from any AST node.
   template <class T>
-  SyntaxTree(T *Node, ASTContext &AST)
+  SyntaxTree(T *Node, ASTUnit &AST)
       : TreeImpl(llvm::make_unique<Impl>(this, Node, AST)) {}
   SyntaxTree(SyntaxTree &&Other) = default;
   ~SyntaxTree();
 
+  ASTUnit &getASTUnit() const;
   const ASTContext &getASTContext() const;
   StringRef getFilename() const;
 
@@ -120,6 +122,7 @@
   ast_type_traits::ASTNodeKind getType() const;
   StringRef getTypeLabel() const;
   bool isLeaf() const { return Children.empty(); }
+  bool isMacro() const;
   llvm::Optional<StringRef> getIdentifier() const;
   llvm::Optional<std::string> getQualifiedIdentifier() const;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to