]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/clang-format/ClangFormat.cpp
Vendor import of clang trunk r178860:
[FreeBSD/FreeBSD.git] / tools / clang-format / ClangFormat.cpp
1 //===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
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 /// \file
11 /// \brief This file implements a clang-format tool that automatically formats
12 /// (fragments of) C++ code.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #include "clang/Basic/Diagnostic.h"
17 #include "clang/Basic/DiagnosticOptions.h"
18 #include "clang/Basic/FileManager.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "clang/Format/Format.h"
21 #include "clang/Lex/Lexer.h"
22 #include "clang/Rewrite/Core/Rewriter.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/Signals.h"
25
26 using namespace llvm;
27
28 static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
29
30 static cl::list<int> Offsets(
31     "offset", cl::desc("Format a range starting at this file offset."));
32 static cl::list<int> Lengths(
33     "length", cl::desc("Format a range of this length, -1 for end of file."));
34 static cl::opt<std::string> Style(
35     "style",
36     cl::desc("Coding style, currently supports: LLVM, Google, Chromium."),
37     cl::init("LLVM"));
38 static cl::opt<bool> Inplace("i",
39                              cl::desc("Inplace edit <file>, if specified."));
40
41 static cl::opt<bool> OutputXML(
42     "output-replacements-xml", cl::desc("Output replacements as XML."));
43
44 static cl::opt<std::string> FileName(cl::Positional, cl::desc("[<file>]"),
45                                      cl::init("-"));
46
47 namespace clang {
48 namespace format {
49
50 static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source,
51                                  SourceManager &Sources, FileManager &Files) {
52   const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "<stdin>" :
53                                                     FileName,
54                                                 Source->getBufferSize(), 0);
55   Sources.overrideFileContents(Entry, Source, true);
56   return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
57 }
58
59 static FormatStyle getStyle() {
60   FormatStyle TheStyle = getGoogleStyle();
61   if (Style == "LLVM")
62     TheStyle = getLLVMStyle();
63   if (Style == "Chromium")
64     TheStyle = getChromiumStyle();
65   return TheStyle;
66 }
67
68 static void format() {
69   FileManager Files((FileSystemOptions()));
70   DiagnosticsEngine Diagnostics(
71       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
72       new DiagnosticOptions);
73   SourceManager Sources(Diagnostics, Files);
74   OwningPtr<MemoryBuffer> Code;
75   if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) {
76     llvm::errs() << ec.message() << "\n";
77     return;
78   }
79   FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files);
80   Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts());
81   if (Offsets.empty())
82     Offsets.push_back(0);
83   if (Offsets.size() != Lengths.size() &&
84       !(Offsets.size() == 1 && Lengths.empty())) {
85     llvm::errs() << "Number of -offset and -length arguments must match.\n";
86     return;
87   }
88   std::vector<CharSourceRange> Ranges;
89   for (cl::list<int>::size_type i = 0, e = Offsets.size(); i != e; ++i) {
90     SourceLocation Start =
91         Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]);
92     SourceLocation End;
93     if (i < Lengths.size()) {
94       End = Start.getLocWithOffset(Lengths[i]);
95     } else {
96       End = Sources.getLocForEndOfFile(ID);
97     }
98     Ranges.push_back(CharSourceRange::getCharRange(Start, End));
99   }
100   tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges);
101   if (OutputXML) {
102     llvm::outs() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
103     for (tooling::Replacements::const_iterator I = Replaces.begin(),
104                                                E = Replaces.end();
105          I != E; ++I) {
106       llvm::outs() << "<replacement "
107                    << "offset='" << I->getOffset() << "' "
108                    << "length='" << I->getLength() << "'>"
109                    << I->getReplacementText() << "</replacement>\n";
110     }
111     llvm::outs() << "</replacements>\n";
112   } else {
113     Rewriter Rewrite(Sources, LangOptions());
114     tooling::applyAllReplacements(Replaces, Rewrite);
115     if (Inplace) {
116       if (Replaces.size() == 0)
117         return; // Nothing changed, don't touch the file.
118
119       std::string ErrorInfo;
120       llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo,
121                                       llvm::raw_fd_ostream::F_Binary);
122       if (!ErrorInfo.empty()) {
123         llvm::errs() << "Error while writing file: " << ErrorInfo << "\n";
124         return;
125       }
126       Rewrite.getEditBuffer(ID).write(FileStream);
127       FileStream.flush();
128     } else {
129       Rewrite.getEditBuffer(ID).write(outs());
130     }
131   }
132 }
133
134 }  // namespace format
135 }  // namespace clang
136
137 int main(int argc, const char **argv) {
138   llvm::sys::PrintStackTraceOnErrorSignal();
139   cl::ParseCommandLineOptions(
140       argc, argv,
141       "A tool to format C/C++/Obj-C code.\n\n"
142       "Currently supports LLVM and Google style guides.\n"
143       "If no arguments are specified, it formats the code from standard input\n"
144       "and writes the result to the standard output.\n"
145       "If <file> is given, it reformats the file. If -i is specified together\n"
146       "with <file>, the file is edited in-place. Otherwise, the result is\n"
147       "written to the standard output.\n");
148   if (Help)
149     cl::PrintHelpMessage();
150   clang::format::format();
151   return 0;
152 }