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 - SyntaxTree(T *Node, ASTContext &AST) + SyntaxTree(T *Node, ASTUnit &AST) : TreeImpl(llvm::make_unique(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 getIdentifier() const; llvm::Optional getQualifiedIdentifier() const; 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 Impl(SyntaxTree *Parent, typename std::enable_if::value, T>::type *Node, - ASTContext &AST) + ASTUnit &AST) : Impl(Parent, dyn_cast(Node), AST) {} template Impl(SyntaxTree *Parent, typename std::enable_if::value, T>::type *Node, - ASTContext &AST) + ASTUnit &AST) : Impl(Parent, dyn_cast(Node), AST) {} SyntaxTree *Parent; - ASTContext * + ASTUnit * PrintingPolicy TypePP; /// Nodes in preorder. std::vector Nodes; @@ -181,7 +181,8 @@ return !I->isWritten(); } -template static bool isNodeExcluded(const SourceManager &SM, T *N) { +template static bool isNodeExcluded(ASTUnit &AST, T *N) { + const SourceManager &SM = AST.getSourceManager(); if (!N) return true; SourceLocation SLoc = N->getSourceRange().getBegin(); @@ -189,13 +190,31 @@ // 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()) { + 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 { @@ -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::TraverseDecl(D); @@ -251,7 +270,7 @@ 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::TraverseStmt(S); @@ -260,7 +279,7 @@ } 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::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()) return getStmtValue(S); if (auto *D = DTN.get()) @@ -688,9 +711,19 @@ 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 Node::getQualifiedIdentifier() const { + if (isMacro()) + return llvm::None; if (auto *ND = ASTNode.get()) { if (ND->getDeclName().isIdentifier()) return ND->getQualifiedNameAsString(); @@ -699,6 +732,8 @@ } llvm::Optional Node::getIdentifier() const { + if (isMacro()) + return llvm::None; if (auto *ND = ASTNode.get()) { if (ND->getDeclName().isIdentifier()) return ND->getName(); @@ -723,16 +758,9 @@ std::pair 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()) { - 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( - 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: 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: 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/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: tools/clang-diff/ClangDiff.cpp =================================================================== --- tools/clang-diff/ClangDiff.cpp +++ tools/clang-diff/ClangDiff.cpp @@ -467,7 +467,7 @@ std::unique_ptr 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) {