xref: /llvm-project/clang/tools/clang-diff/ClangDiff.cpp (revision 849f20e4a2f3ee41e2527413674d8da44a8512a2)
1a75b2cacSAlex Lorenz //===- ClangDiff.cpp - compare source files by AST nodes ------*- C++ -*- -===//
2a75b2cacSAlex Lorenz //
3a75b2cacSAlex Lorenz //                     The LLVM Compiler Infrastructure
4a75b2cacSAlex Lorenz //
5a75b2cacSAlex Lorenz // This file is distributed under the University of Illinois Open Source
6a75b2cacSAlex Lorenz // License. See LICENSE.TXT for details.
7a75b2cacSAlex Lorenz //
8a75b2cacSAlex Lorenz //===----------------------------------------------------------------------===//
9a75b2cacSAlex Lorenz //
10a75b2cacSAlex Lorenz // This file implements a tool for syntax tree based comparison using
11a75b2cacSAlex Lorenz // Tooling/ASTDiff.
12a75b2cacSAlex Lorenz //
13a75b2cacSAlex Lorenz //===----------------------------------------------------------------------===//
14a75b2cacSAlex Lorenz 
15a75b2cacSAlex Lorenz #include "clang/Tooling/ASTDiff/ASTDiff.h"
16a75b2cacSAlex Lorenz #include "clang/Tooling/CommonOptionsParser.h"
17a75b2cacSAlex Lorenz #include "clang/Tooling/Tooling.h"
18a75b2cacSAlex Lorenz #include "llvm/Support/CommandLine.h"
19a75b2cacSAlex Lorenz 
20a75b2cacSAlex Lorenz using namespace llvm;
21a75b2cacSAlex Lorenz using namespace clang;
22a75b2cacSAlex Lorenz using namespace clang::tooling;
23a75b2cacSAlex Lorenz 
24a75b2cacSAlex Lorenz static cl::OptionCategory ClangDiffCategory("clang-diff options");
25a75b2cacSAlex Lorenz 
26a75b2cacSAlex Lorenz static cl::opt<bool>
27914a958eSJohannes Altmanninger     ASTDump("ast-dump",
28a75b2cacSAlex Lorenz             cl::desc("Print the internal representation of the AST as JSON."),
29a75b2cacSAlex Lorenz             cl::init(false), cl::cat(ClangDiffCategory));
30a75b2cacSAlex Lorenz 
31a75b2cacSAlex Lorenz static cl::opt<std::string> SourcePath(cl::Positional, cl::desc("<source>"),
32a75b2cacSAlex Lorenz                                        cl::Required,
33a75b2cacSAlex Lorenz                                        cl::cat(ClangDiffCategory));
34a75b2cacSAlex Lorenz 
35a75b2cacSAlex Lorenz static cl::opt<std::string> DestinationPath(cl::Positional,
36a75b2cacSAlex Lorenz                                             cl::desc("<destination>"),
37a75b2cacSAlex Lorenz                                             cl::Optional,
38a75b2cacSAlex Lorenz                                             cl::cat(ClangDiffCategory));
39a75b2cacSAlex Lorenz 
40*849f20e4SJohannes Altmanninger static cl::opt<int> MaxSize("s", cl::desc("<maxsize>"), cl::Optional,
41*849f20e4SJohannes Altmanninger                             cl::init(-1), cl::cat(ClangDiffCategory));
42*849f20e4SJohannes Altmanninger 
43*849f20e4SJohannes Altmanninger static cl::opt<std::string> BuildPath("p", cl::desc("Build path"), cl::init(""),
44*849f20e4SJohannes Altmanninger                                       cl::Optional, cl::cat(ClangDiffCategory));
45*849f20e4SJohannes Altmanninger 
46*849f20e4SJohannes Altmanninger static cl::list<std::string> ArgsAfter(
47*849f20e4SJohannes Altmanninger     "extra-arg",
48*849f20e4SJohannes Altmanninger     cl::desc("Additional argument to append to the compiler command line"),
49*849f20e4SJohannes Altmanninger     cl::cat(ClangDiffCategory));
50*849f20e4SJohannes Altmanninger 
51*849f20e4SJohannes Altmanninger static cl::list<std::string> ArgsBefore(
52*849f20e4SJohannes Altmanninger     "extra-arg-before",
53*849f20e4SJohannes Altmanninger     cl::desc("Additional argument to prepend to the compiler command line"),
54*849f20e4SJohannes Altmanninger     cl::cat(ClangDiffCategory));
55*849f20e4SJohannes Altmanninger 
56*849f20e4SJohannes Altmanninger static void addExtraArgs(std::unique_ptr<CompilationDatabase> &Compilations) {
57*849f20e4SJohannes Altmanninger   if (!Compilations)
58*849f20e4SJohannes Altmanninger     return;
59*849f20e4SJohannes Altmanninger   auto AdjustingCompilations =
60*849f20e4SJohannes Altmanninger       llvm::make_unique<ArgumentsAdjustingCompilations>(
61*849f20e4SJohannes Altmanninger           std::move(Compilations));
62*849f20e4SJohannes Altmanninger   AdjustingCompilations->appendArgumentsAdjuster(
63*849f20e4SJohannes Altmanninger       getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN));
64*849f20e4SJohannes Altmanninger   AdjustingCompilations->appendArgumentsAdjuster(
65*849f20e4SJohannes Altmanninger       getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
66*849f20e4SJohannes Altmanninger   Compilations = std::move(AdjustingCompilations);
67*849f20e4SJohannes Altmanninger }
68*849f20e4SJohannes Altmanninger 
69*849f20e4SJohannes Altmanninger static std::unique_ptr<ASTUnit>
70*849f20e4SJohannes Altmanninger getAST(const std::unique_ptr<CompilationDatabase> &CommonCompilations,
71*849f20e4SJohannes Altmanninger        const StringRef Filename) {
72a75b2cacSAlex Lorenz   std::string ErrorMessage;
73a75b2cacSAlex Lorenz   std::unique_ptr<CompilationDatabase> Compilations;
74*849f20e4SJohannes Altmanninger   if (!CommonCompilations) {
75*849f20e4SJohannes Altmanninger     Compilations = CompilationDatabase::autoDetectFromSource(
76*849f20e4SJohannes Altmanninger         BuildPath.empty() ? Filename : BuildPath, ErrorMessage);
77a75b2cacSAlex Lorenz     if (!Compilations) {
78a75b2cacSAlex Lorenz       llvm::errs()
79a75b2cacSAlex Lorenz           << "Error while trying to load a compilation database, running "
80a75b2cacSAlex Lorenz              "without flags.\n"
81a75b2cacSAlex Lorenz           << ErrorMessage;
82*849f20e4SJohannes Altmanninger       Compilations =
83*849f20e4SJohannes Altmanninger           llvm::make_unique<clang::tooling::FixedCompilationDatabase>(
84a75b2cacSAlex Lorenz               ".", std::vector<std::string>());
85a75b2cacSAlex Lorenz     }
86*849f20e4SJohannes Altmanninger   }
87*849f20e4SJohannes Altmanninger   addExtraArgs(Compilations);
88a75b2cacSAlex Lorenz   std::array<std::string, 1> Files = {{Filename}};
89*849f20e4SJohannes Altmanninger   ClangTool Tool(Compilations ? *Compilations : *CommonCompilations, Files);
90a75b2cacSAlex Lorenz   std::vector<std::unique_ptr<ASTUnit>> ASTs;
91a75b2cacSAlex Lorenz   Tool.buildASTs(ASTs);
92a75b2cacSAlex Lorenz   if (ASTs.size() != Files.size())
93a75b2cacSAlex Lorenz     return nullptr;
94a75b2cacSAlex Lorenz   return std::move(ASTs[0]);
95a75b2cacSAlex Lorenz }
96a75b2cacSAlex Lorenz 
97a75b2cacSAlex Lorenz int main(int argc, const char **argv) {
98*849f20e4SJohannes Altmanninger   std::string ErrorMessage;
99*849f20e4SJohannes Altmanninger   std::unique_ptr<CompilationDatabase> CommonCompilations =
100*849f20e4SJohannes Altmanninger       FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
101*849f20e4SJohannes Altmanninger   if (!CommonCompilations && !ErrorMessage.empty())
102*849f20e4SJohannes Altmanninger     llvm::errs() << ErrorMessage;
103a75b2cacSAlex Lorenz   cl::HideUnrelatedOptions(ClangDiffCategory);
104a75b2cacSAlex Lorenz   if (!cl::ParseCommandLineOptions(argc, argv)) {
105a75b2cacSAlex Lorenz     cl::PrintOptionValues();
106a75b2cacSAlex Lorenz     return 1;
107a75b2cacSAlex Lorenz   }
108a75b2cacSAlex Lorenz 
109*849f20e4SJohannes Altmanninger   addExtraArgs(CommonCompilations);
110*849f20e4SJohannes Altmanninger 
111914a958eSJohannes Altmanninger   if (ASTDump) {
112a75b2cacSAlex Lorenz     if (!DestinationPath.empty()) {
113a75b2cacSAlex Lorenz       llvm::errs() << "Error: Please specify exactly one filename.\n";
114a75b2cacSAlex Lorenz       return 1;
115a75b2cacSAlex Lorenz     }
116*849f20e4SJohannes Altmanninger     std::unique_ptr<ASTUnit> AST = getAST(CommonCompilations, SourcePath);
117a75b2cacSAlex Lorenz     if (!AST)
118a75b2cacSAlex Lorenz       return 1;
119a75b2cacSAlex Lorenz     diff::SyntaxTree Tree(AST->getASTContext());
120a75b2cacSAlex Lorenz     Tree.printAsJson(llvm::outs());
121a75b2cacSAlex Lorenz     return 0;
122a75b2cacSAlex Lorenz   }
123a75b2cacSAlex Lorenz 
124a75b2cacSAlex Lorenz   if (DestinationPath.empty()) {
125a75b2cacSAlex Lorenz     llvm::errs() << "Error: Exactly two paths are required.\n";
126a75b2cacSAlex Lorenz     return 1;
127a75b2cacSAlex Lorenz   }
128a75b2cacSAlex Lorenz 
129*849f20e4SJohannes Altmanninger   std::unique_ptr<ASTUnit> Src = getAST(CommonCompilations, SourcePath);
130*849f20e4SJohannes Altmanninger   std::unique_ptr<ASTUnit> Dst = getAST(CommonCompilations, DestinationPath);
131a75b2cacSAlex Lorenz   if (!Src || !Dst)
132a75b2cacSAlex Lorenz     return 1;
133a75b2cacSAlex Lorenz 
134a75b2cacSAlex Lorenz   diff::ComparisonOptions Options;
135*849f20e4SJohannes Altmanninger   if (MaxSize != -1)
136*849f20e4SJohannes Altmanninger     Options.MaxSize = MaxSize;
137a75b2cacSAlex Lorenz   diff::SyntaxTree SrcTree(Src->getASTContext());
138a75b2cacSAlex Lorenz   diff::SyntaxTree DstTree(Dst->getASTContext());
139a75b2cacSAlex Lorenz   diff::ASTDiff DiffTool(SrcTree, DstTree, Options);
140a75b2cacSAlex Lorenz   for (const auto &Match : DiffTool.getMatches())
141a75b2cacSAlex Lorenz     DiffTool.printMatch(llvm::outs(), Match);
142a75b2cacSAlex Lorenz   for (const auto &Change : DiffTool.getChanges())
143a75b2cacSAlex Lorenz     DiffTool.printChange(llvm::outs(), Change);
144a75b2cacSAlex Lorenz 
145a75b2cacSAlex Lorenz   return 0;
146a75b2cacSAlex Lorenz }
147