1 //===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief This file implements a clang-format tool that automatically formats
12 /// (fragments of) C++ code.
14 //===----------------------------------------------------------------------===//
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"
28 static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
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(
36 cl::desc("Coding style, currently supports: LLVM, Google, Chromium."),
38 static cl::opt<bool> Inplace("i",
39 cl::desc("Inplace edit <file>, if specified."));
41 static cl::opt<bool> OutputXML(
42 "output-replacements-xml", cl::desc("Output replacements as XML."));
44 static cl::opt<std::string> FileName(cl::Positional, cl::desc("[<file>]"),
50 static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source,
51 SourceManager &Sources, FileManager &Files) {
52 const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "<stdin>" :
54 Source->getBufferSize(), 0);
55 Sources.overrideFileContents(Entry, Source, true);
56 return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
59 static FormatStyle getStyle() {
60 FormatStyle TheStyle = getGoogleStyle();
62 TheStyle = getLLVMStyle();
63 if (Style == "Chromium")
64 TheStyle = getChromiumStyle();
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";
79 FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files);
80 Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts());
83 if (Offsets.size() != Lengths.size() &&
84 !(Offsets.size() == 1 && Lengths.empty())) {
85 llvm::errs() << "Number of -offset and -length arguments must match.\n";
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]);
93 if (i < Lengths.size()) {
94 End = Start.getLocWithOffset(Lengths[i]);
96 End = Sources.getLocForEndOfFile(ID);
98 Ranges.push_back(CharSourceRange::getCharRange(Start, End));
100 tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges);
102 llvm::outs() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
103 for (tooling::Replacements::const_iterator I = Replaces.begin(),
106 llvm::outs() << "<replacement "
107 << "offset='" << I->getOffset() << "' "
108 << "length='" << I->getLength() << "'>"
109 << I->getReplacementText() << "</replacement>\n";
111 llvm::outs() << "</replacements>\n";
113 Rewriter Rewrite(Sources, LangOptions());
114 tooling::applyAllReplacements(Replaces, Rewrite);
116 if (Replaces.size() == 0)
117 return; // Nothing changed, don't touch the file.
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";
126 Rewrite.getEditBuffer(ID).write(FileStream);
129 Rewrite.getEditBuffer(ID).write(outs());
134 } // namespace format
137 int main(int argc, const char **argv) {
138 llvm::sys::PrintStackTraceOnErrorSignal();
139 cl::ParseCommandLineOptions(
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");
149 cl::PrintHelpMessage();
150 clang::format::format();