//===- ClangDiff.cpp - compare source files by AST nodes ------*- C++ -*- -===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements a tool for syntax tree based comparison using // Tooling/ASTDiff. // //===----------------------------------------------------------------------===// #include "clang/Tooling/ASTDiff/ASTDiff.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" using namespace llvm; using namespace clang; using namespace clang::tooling; static cl::OptionCategory ClangDiffCategory("clang-diff options"); static cl::opt DumpAST("ast-dump", cl::desc("Print the internal representation of the AST as JSON."), cl::init(false), cl::cat(ClangDiffCategory)); static cl::opt NoCompilationDatabase( "no-compilation-database", cl::desc( "Do not attempt to load build settings from a compilation database"), cl::init(false), cl::cat(ClangDiffCategory)); static cl::opt SourcePath(cl::Positional, cl::desc(""), cl::Required, cl::cat(ClangDiffCategory)); static cl::opt DestinationPath(cl::Positional, cl::desc(""), cl::Optional, cl::cat(ClangDiffCategory)); static std::unique_ptr getAST(const StringRef Filename) { std::string ErrorMessage; std::unique_ptr Compilations; if (!NoCompilationDatabase) Compilations = CompilationDatabase::autoDetectFromSource(Filename, ErrorMessage); if (!Compilations) { if (!NoCompilationDatabase) llvm::errs() << "Error while trying to load a compilation database, running " "without flags.\n" << ErrorMessage; Compilations = llvm::make_unique( ".", std::vector()); } std::array Files = {{Filename}}; ClangTool Tool(*Compilations, Files); std::vector> ASTs; Tool.buildASTs(ASTs); if (ASTs.size() != Files.size()) return nullptr; return std::move(ASTs[0]); } int main(int argc, const char **argv) { cl::HideUnrelatedOptions(ClangDiffCategory); if (!cl::ParseCommandLineOptions(argc, argv)) { cl::PrintOptionValues(); return 1; } if (DumpAST) { if (!DestinationPath.empty()) { llvm::errs() << "Error: Please specify exactly one filename.\n"; return 1; } std::unique_ptr AST = getAST(SourcePath); if (!AST) return 1; diff::SyntaxTree Tree(AST->getASTContext()); Tree.printAsJson(llvm::outs()); return 0; } if (DestinationPath.empty()) { llvm::errs() << "Error: Exactly two paths are required.\n"; return 1; } std::unique_ptr Src = getAST(SourcePath); std::unique_ptr Dst = getAST(DestinationPath); if (!Src || !Dst) return 1; diff::ComparisonOptions Options; diff::SyntaxTree SrcTree(Src->getASTContext()); diff::SyntaxTree DstTree(Dst->getASTContext()); diff::ASTDiff DiffTool(SrcTree, DstTree, Options); for (const auto &Match : DiffTool.getMatches()) DiffTool.printMatch(llvm::outs(), Match); for (const auto &Change : DiffTool.getChanges()) DiffTool.printChange(llvm::outs(), Change); return 0; }