1 //===- ClangDiff.cpp - compare source files by AST nodes ------*- C++ -*- -===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements a tool for syntax tree based comparison using 11 // Tooling/ASTDiff. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/Tooling/ASTDiff/ASTDiff.h" 16 #include "clang/Tooling/CommonOptionsParser.h" 17 #include "clang/Tooling/Tooling.h" 18 #include "llvm/Support/CommandLine.h" 19 20 using namespace llvm; 21 using namespace clang; 22 using namespace clang::tooling; 23 24 static cl::OptionCategory ClangDiffCategory("clang-diff options"); 25 26 static cl::opt<bool> 27 ASTDump("ast-dump", 28 cl::desc("Print the internal representation of the AST as JSON."), 29 cl::init(false), cl::cat(ClangDiffCategory)); 30 31 static cl::opt<bool> NoCompilationDatabase( 32 "no-compilation-database", 33 cl::desc( 34 "Do not attempt to load build settings from a compilation database"), 35 cl::init(false), cl::cat(ClangDiffCategory)); 36 37 static cl::opt<std::string> SourcePath(cl::Positional, cl::desc("<source>"), 38 cl::Required, 39 cl::cat(ClangDiffCategory)); 40 41 static cl::opt<std::string> DestinationPath(cl::Positional, 42 cl::desc("<destination>"), 43 cl::Optional, 44 cl::cat(ClangDiffCategory)); 45 46 static std::unique_ptr<ASTUnit> getAST(const StringRef Filename) { 47 std::string ErrorMessage; 48 std::unique_ptr<CompilationDatabase> Compilations; 49 if (!NoCompilationDatabase) 50 Compilations = 51 CompilationDatabase::autoDetectFromSource(Filename, ErrorMessage); 52 if (!Compilations) { 53 if (!NoCompilationDatabase) 54 llvm::errs() 55 << "Error while trying to load a compilation database, running " 56 "without flags.\n" 57 << ErrorMessage; 58 Compilations = llvm::make_unique<clang::tooling::FixedCompilationDatabase>( 59 ".", std::vector<std::string>()); 60 } 61 std::array<std::string, 1> Files = {{Filename}}; 62 ClangTool Tool(*Compilations, Files); 63 std::vector<std::unique_ptr<ASTUnit>> ASTs; 64 Tool.buildASTs(ASTs); 65 if (ASTs.size() != Files.size()) 66 return nullptr; 67 return std::move(ASTs[0]); 68 } 69 70 int main(int argc, const char **argv) { 71 cl::HideUnrelatedOptions(ClangDiffCategory); 72 if (!cl::ParseCommandLineOptions(argc, argv)) { 73 cl::PrintOptionValues(); 74 return 1; 75 } 76 77 if (ASTDump) { 78 if (!DestinationPath.empty()) { 79 llvm::errs() << "Error: Please specify exactly one filename.\n"; 80 return 1; 81 } 82 std::unique_ptr<ASTUnit> AST = getAST(SourcePath); 83 if (!AST) 84 return 1; 85 diff::SyntaxTree Tree(AST->getASTContext()); 86 Tree.printAsJson(llvm::outs()); 87 return 0; 88 } 89 90 if (DestinationPath.empty()) { 91 llvm::errs() << "Error: Exactly two paths are required.\n"; 92 return 1; 93 } 94 95 std::unique_ptr<ASTUnit> Src = getAST(SourcePath); 96 std::unique_ptr<ASTUnit> Dst = getAST(DestinationPath); 97 if (!Src || !Dst) 98 return 1; 99 100 diff::ComparisonOptions Options; 101 diff::SyntaxTree SrcTree(Src->getASTContext()); 102 diff::SyntaxTree DstTree(Dst->getASTContext()); 103 diff::ASTDiff DiffTool(SrcTree, DstTree, Options); 104 for (const auto &Match : DiffTool.getMatches()) 105 DiffTool.printMatch(llvm::outs(), Match); 106 for (const auto &Change : DiffTool.getChanges()) 107 DiffTool.printChange(llvm::outs(), Change); 108 109 return 0; 110 } 111