diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 17:59:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 17:59:23 +0000 |
| commit | 9a83721404652cea39e9f02ae3e3b5c964602a5c (patch) | |
| tree | 23e9541ce27049a103f6ed046be61592123e02c9 /tools/clang-diff/ClangDiff.cpp | |
| parent | 676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (diff) | |
Notes
Diffstat (limited to 'tools/clang-diff/ClangDiff.cpp')
| -rw-r--r-- | tools/clang-diff/ClangDiff.cpp | 537 |
1 files changed, 0 insertions, 537 deletions
diff --git a/tools/clang-diff/ClangDiff.cpp b/tools/clang-diff/ClangDiff.cpp deleted file mode 100644 index 4e2150aa457d..000000000000 --- a/tools/clang-diff/ClangDiff.cpp +++ /dev/null @@ -1,537 +0,0 @@ -//===- 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<bool> - ASTDump("ast-dump", - cl::desc("Print the internal representation of the AST."), - cl::init(false), cl::cat(ClangDiffCategory)); - -static cl::opt<bool> ASTDumpJson( - "ast-dump-json", - cl::desc("Print the internal representation of the AST as JSON."), - cl::init(false), cl::cat(ClangDiffCategory)); - -static cl::opt<bool> PrintMatches("dump-matches", - cl::desc("Print the matched nodes."), - cl::init(false), cl::cat(ClangDiffCategory)); - -static cl::opt<bool> HtmlDiff("html", - cl::desc("Output a side-by-side diff in HTML."), - cl::init(false), cl::cat(ClangDiffCategory)); - -static cl::opt<std::string> SourcePath(cl::Positional, cl::desc("<source>"), - cl::Required, - cl::cat(ClangDiffCategory)); - -static cl::opt<std::string> DestinationPath(cl::Positional, - cl::desc("<destination>"), - cl::Optional, - cl::cat(ClangDiffCategory)); - -static cl::opt<std::string> StopAfter("stop-diff-after", - cl::desc("<topdown|bottomup>"), - cl::Optional, cl::init(""), - cl::cat(ClangDiffCategory)); - -static cl::opt<int> MaxSize("s", cl::desc("<maxsize>"), cl::Optional, - cl::init(-1), cl::cat(ClangDiffCategory)); - -static cl::opt<std::string> BuildPath("p", cl::desc("Build path"), cl::init(""), - cl::Optional, cl::cat(ClangDiffCategory)); - -static cl::list<std::string> ArgsAfter( - "extra-arg", - cl::desc("Additional argument to append to the compiler command line"), - cl::cat(ClangDiffCategory)); - -static cl::list<std::string> ArgsBefore( - "extra-arg-before", - cl::desc("Additional argument to prepend to the compiler command line"), - cl::cat(ClangDiffCategory)); - -static void addExtraArgs(std::unique_ptr<CompilationDatabase> &Compilations) { - if (!Compilations) - return; - auto AdjustingCompilations = - llvm::make_unique<ArgumentsAdjustingCompilations>( - std::move(Compilations)); - AdjustingCompilations->appendArgumentsAdjuster( - getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN)); - AdjustingCompilations->appendArgumentsAdjuster( - getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END)); - Compilations = std::move(AdjustingCompilations); -} - -static std::unique_ptr<ASTUnit> -getAST(const std::unique_ptr<CompilationDatabase> &CommonCompilations, - const StringRef Filename) { - std::string ErrorMessage; - std::unique_ptr<CompilationDatabase> Compilations; - if (!CommonCompilations) { - Compilations = CompilationDatabase::autoDetectFromSource( - BuildPath.empty() ? Filename : BuildPath, ErrorMessage); - if (!Compilations) { - llvm::errs() - << "Error while trying to load a compilation database, running " - "without flags.\n" - << ErrorMessage; - Compilations = - llvm::make_unique<clang::tooling::FixedCompilationDatabase>( - ".", std::vector<std::string>()); - } - } - addExtraArgs(Compilations); - std::array<std::string, 1> Files = {{Filename}}; - ClangTool Tool(Compilations ? *Compilations : *CommonCompilations, Files); - std::vector<std::unique_ptr<ASTUnit>> ASTs; - Tool.buildASTs(ASTs); - if (ASTs.size() != Files.size()) - return nullptr; - return std::move(ASTs[0]); -} - -static char hexdigit(int N) { return N &= 0xf, N + (N < 10 ? '0' : 'a' - 10); } - -static const char HtmlDiffHeader[] = R"( -<html> -<head> -<meta charset='utf-8'/> -<style> -span.d { color: red; } -span.u { color: #cc00cc; } -span.i { color: green; } -span.m { font-weight: bold; } -span { font-weight: normal; color: black; } -div.code { - width: 48%; - height: 98%; - overflow: scroll; - float: left; - padding: 0 0 0.5% 0.5%; - border: solid 2px LightGrey; - border-radius: 5px; -} -</style> -</head> -<script type='text/javascript'> -highlightStack = [] -function clearHighlight() { - while (highlightStack.length) { - var [l, r] = highlightStack.pop() - document.getElementById(l).style.backgroundColor = 'inherit' - if (r[1] != '-') - document.getElementById(r).style.backgroundColor = 'inherit' - } -} -function highlight(event) { - var id = event.target['id'] - doHighlight(id) -} -function doHighlight(id) { - clearHighlight() - source = document.getElementById(id) - if (!source.attributes['tid']) - return - var mapped = source - while (mapped && mapped.parentElement && mapped.attributes['tid'].value.substr(1) === '-1') - mapped = mapped.parentElement - var tid = null, target = null - if (mapped) { - tid = mapped.attributes['tid'].value - target = document.getElementById(tid) - } - if (source.parentElement && source.parentElement.classList.contains('code')) - return - source.style.backgroundColor = 'lightgrey' - source.scrollIntoView() - if (target) { - if (mapped === source) - target.style.backgroundColor = 'lightgrey' - target.scrollIntoView() - } - highlightStack.push([id, tid]) - location.hash = '#' + id -} -function scrollToBoth() { - doHighlight(location.hash.substr(1)) -} -function changed(elem) { - return elem.classList.length == 0 -} -function nextChangedNode(prefix, increment, number) { - do { - number += increment - var elem = document.getElementById(prefix + number) - } while(elem && !changed(elem)) - return elem ? number : null -} -function handleKey(e) { - var down = e.code === "KeyJ" - var up = e.code === "KeyK" - if (!down && !up) - return - var id = highlightStack[0] ? highlightStack[0][0] : 'R0' - var oldelem = document.getElementById(id) - var number = parseInt(id.substr(1)) - var increment = down ? 1 : -1 - var lastnumber = number - var prefix = id[0] - do { - number = nextChangedNode(prefix, increment, number) - var elem = document.getElementById(prefix + number) - if (up && elem) { - while (elem.parentElement && changed(elem.parentElement)) - elem = elem.parentElement - number = elem.id.substr(1) - } - } while ((down && id !== 'R0' && oldelem.contains(elem))) - if (!number) - number = lastnumber - elem = document.getElementById(prefix + number) - doHighlight(prefix + number) -} -window.onload = scrollToBoth -window.onkeydown = handleKey -</script> -<body> -<div onclick='highlight(event)'> -)"; - -static void printHtml(raw_ostream &OS, char C) { - switch (C) { - case '&': - OS << "&"; - break; - case '<': - OS << "<"; - break; - case '>': - OS << ">"; - break; - case '\'': - OS << "'"; - break; - case '"': - OS << """; - break; - default: - OS << C; - } -} - -static void printHtml(raw_ostream &OS, const StringRef Str) { - for (char C : Str) - printHtml(OS, C); -} - -static std::string getChangeKindAbbr(diff::ChangeKind Kind) { - switch (Kind) { - case diff::None: - return ""; - case diff::Delete: - return "d"; - case diff::Update: - return "u"; - case diff::Insert: - return "i"; - case diff::Move: - return "m"; - case diff::UpdateMove: - return "u m"; - } - llvm_unreachable("Invalid enumeration value."); -} - -static unsigned printHtmlForNode(raw_ostream &OS, const diff::ASTDiff &Diff, - diff::SyntaxTree &Tree, bool IsLeft, - diff::NodeId Id, unsigned Offset) { - const diff::Node &Node = Tree.getNode(Id); - char MyTag, OtherTag; - diff::NodeId LeftId, RightId; - diff::NodeId TargetId = Diff.getMapped(Tree, Id); - if (IsLeft) { - MyTag = 'L'; - OtherTag = 'R'; - LeftId = Id; - RightId = TargetId; - } else { - MyTag = 'R'; - OtherTag = 'L'; - LeftId = TargetId; - RightId = Id; - } - unsigned Begin, End; - std::tie(Begin, End) = Tree.getSourceRangeOffsets(Node); - const SourceManager &SrcMgr = Tree.getASTContext().getSourceManager(); - auto Code = SrcMgr.getBuffer(SrcMgr.getMainFileID())->getBuffer(); - for (; Offset < Begin; ++Offset) - printHtml(OS, Code[Offset]); - OS << "<span id='" << MyTag << Id << "' " - << "tid='" << OtherTag << TargetId << "' "; - OS << "title='"; - printHtml(OS, Node.getTypeLabel()); - OS << "\n" << LeftId << " -> " << RightId; - std::string Value = Tree.getNodeValue(Node); - if (!Value.empty()) { - OS << "\n"; - printHtml(OS, Value); - } - OS << "'"; - if (Node.Change != diff::None) - OS << " class='" << getChangeKindAbbr(Node.Change) << "'"; - OS << ">"; - - for (diff::NodeId Child : Node.Children) - Offset = printHtmlForNode(OS, Diff, Tree, IsLeft, Child, Offset); - - for (; Offset < End; ++Offset) - printHtml(OS, Code[Offset]); - if (Id == Tree.getRootId()) { - End = Code.size(); - for (; Offset < End; ++Offset) - printHtml(OS, Code[Offset]); - } - OS << "</span>"; - return Offset; -} - -static void printJsonString(raw_ostream &OS, const StringRef Str) { - for (signed char C : Str) { - switch (C) { - case '"': - OS << R"(\")"; - break; - case '\\': - OS << R"(\\)"; - break; - case '\n': - OS << R"(\n)"; - break; - case '\t': - OS << R"(\t)"; - break; - default: - if ('\x00' <= C && C <= '\x1f') { - OS << R"(\u00)" << hexdigit(C >> 4) << hexdigit(C); - } else { - OS << C; - } - } - } -} - -static void printNodeAttributes(raw_ostream &OS, diff::SyntaxTree &Tree, - diff::NodeId Id) { - const diff::Node &N = Tree.getNode(Id); - OS << R"("id":)" << int(Id); - OS << R"(,"type":")" << N.getTypeLabel() << '"'; - auto Offsets = Tree.getSourceRangeOffsets(N); - OS << R"(,"begin":)" << Offsets.first; - OS << R"(,"end":)" << Offsets.second; - std::string Value = Tree.getNodeValue(N); - if (!Value.empty()) { - OS << R"(,"value":")"; - printJsonString(OS, Value); - OS << '"'; - } -} - -static void printNodeAsJson(raw_ostream &OS, diff::SyntaxTree &Tree, - diff::NodeId Id) { - const diff::Node &N = Tree.getNode(Id); - OS << "{"; - printNodeAttributes(OS, Tree, Id); - auto Identifier = N.getIdentifier(); - auto QualifiedIdentifier = N.getQualifiedIdentifier(); - if (Identifier) { - OS << R"(,"identifier":")"; - printJsonString(OS, *Identifier); - OS << R"(")"; - if (QualifiedIdentifier && *Identifier != *QualifiedIdentifier) { - OS << R"(,"qualified_identifier":")"; - printJsonString(OS, *QualifiedIdentifier); - OS << R"(")"; - } - } - OS << R"(,"children":[)"; - if (N.Children.size() > 0) { - printNodeAsJson(OS, Tree, N.Children[0]); - for (size_t I = 1, E = N.Children.size(); I < E; ++I) { - OS << ","; - printNodeAsJson(OS, Tree, N.Children[I]); - } - } - OS << "]}"; -} - -static void printNode(raw_ostream &OS, diff::SyntaxTree &Tree, - diff::NodeId Id) { - if (Id.isInvalid()) { - OS << "None"; - return; - } - OS << Tree.getNode(Id).getTypeLabel(); - std::string Value = Tree.getNodeValue(Id); - if (!Value.empty()) - OS << ": " << Value; - OS << "(" << Id << ")"; -} - -static void printTree(raw_ostream &OS, diff::SyntaxTree &Tree) { - for (diff::NodeId Id : Tree) { - for (int I = 0; I < Tree.getNode(Id).Depth; ++I) - OS << " "; - printNode(OS, Tree, Id); - OS << "\n"; - } -} - -static void printDstChange(raw_ostream &OS, diff::ASTDiff &Diff, - diff::SyntaxTree &SrcTree, diff::SyntaxTree &DstTree, - diff::NodeId Dst) { - const diff::Node &DstNode = DstTree.getNode(Dst); - diff::NodeId Src = Diff.getMapped(DstTree, Dst); - switch (DstNode.Change) { - case diff::None: - break; - case diff::Delete: - llvm_unreachable("The destination tree can't have deletions."); - case diff::Update: - OS << "Update "; - printNode(OS, SrcTree, Src); - OS << " to " << DstTree.getNodeValue(Dst) << "\n"; - break; - case diff::Insert: - case diff::Move: - case diff::UpdateMove: - if (DstNode.Change == diff::Insert) - OS << "Insert"; - else if (DstNode.Change == diff::Move) - OS << "Move"; - else if (DstNode.Change == diff::UpdateMove) - OS << "Update and Move"; - OS << " "; - printNode(OS, DstTree, Dst); - OS << " into "; - printNode(OS, DstTree, DstNode.Parent); - OS << " at " << DstTree.findPositionInParent(Dst) << "\n"; - break; - } -} - -int main(int argc, const char **argv) { - std::string ErrorMessage; - std::unique_ptr<CompilationDatabase> CommonCompilations = - FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); - if (!CommonCompilations && !ErrorMessage.empty()) - llvm::errs() << ErrorMessage; - cl::HideUnrelatedOptions(ClangDiffCategory); - if (!cl::ParseCommandLineOptions(argc, argv)) { - cl::PrintOptionValues(); - return 1; - } - - addExtraArgs(CommonCompilations); - - if (ASTDump || ASTDumpJson) { - if (!DestinationPath.empty()) { - llvm::errs() << "Error: Please specify exactly one filename.\n"; - return 1; - } - std::unique_ptr<ASTUnit> AST = getAST(CommonCompilations, SourcePath); - if (!AST) - return 1; - diff::SyntaxTree Tree(AST->getASTContext()); - if (ASTDump) { - printTree(llvm::outs(), Tree); - return 0; - } - llvm::outs() << R"({"filename":")"; - printJsonString(llvm::outs(), SourcePath); - llvm::outs() << R"(","root":)"; - printNodeAsJson(llvm::outs(), Tree, Tree.getRootId()); - llvm::outs() << "}\n"; - return 0; - } - - if (DestinationPath.empty()) { - llvm::errs() << "Error: Exactly two paths are required.\n"; - return 1; - } - - std::unique_ptr<ASTUnit> Src = getAST(CommonCompilations, SourcePath); - std::unique_ptr<ASTUnit> Dst = getAST(CommonCompilations, DestinationPath); - if (!Src || !Dst) - return 1; - - diff::ComparisonOptions Options; - if (MaxSize != -1) - Options.MaxSize = MaxSize; - if (!StopAfter.empty()) { - if (StopAfter == "topdown") - Options.StopAfterTopDown = true; - else if (StopAfter != "bottomup") { - llvm::errs() << "Error: Invalid argument for -stop-after\n"; - return 1; - } - } - diff::SyntaxTree SrcTree(Src->getASTContext()); - diff::SyntaxTree DstTree(Dst->getASTContext()); - diff::ASTDiff Diff(SrcTree, DstTree, Options); - - if (HtmlDiff) { - llvm::outs() << HtmlDiffHeader << "<pre>"; - llvm::outs() << "<div id='L' class='code'>"; - printHtmlForNode(llvm::outs(), Diff, SrcTree, true, SrcTree.getRootId(), 0); - llvm::outs() << "</div>"; - llvm::outs() << "<div id='R' class='code'>"; - printHtmlForNode(llvm::outs(), Diff, DstTree, false, DstTree.getRootId(), - 0); - llvm::outs() << "</div>"; - llvm::outs() << "</pre></div></body></html>\n"; - return 0; - } - - for (diff::NodeId Dst : DstTree) { - diff::NodeId Src = Diff.getMapped(DstTree, Dst); - if (PrintMatches && Src.isValid()) { - llvm::outs() << "Match "; - printNode(llvm::outs(), SrcTree, Src); - llvm::outs() << " to "; - printNode(llvm::outs(), DstTree, Dst); - llvm::outs() << "\n"; - } - printDstChange(llvm::outs(), Diff, SrcTree, DstTree, Dst); - } - for (diff::NodeId Src : SrcTree) { - if (Diff.getMapped(SrcTree, Src).isInvalid()) { - llvm::outs() << "Delete "; - printNode(llvm::outs(), SrcTree, Src); - llvm::outs() << "\n"; - } - } - - return 0; -} |
