xref: /openbsd-src/gnu/llvm/clang/tools/clang-format/ClangFormat.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick ///
9e5dd7070Spatrick /// \file
10e5dd7070Spatrick /// This file implements a clang-format tool that automatically formats
11e5dd7070Spatrick /// (fragments of) C++ code.
12e5dd7070Spatrick ///
13e5dd7070Spatrick //===----------------------------------------------------------------------===//
14e5dd7070Spatrick 
15e5dd7070Spatrick #include "clang/Basic/Diagnostic.h"
16e5dd7070Spatrick #include "clang/Basic/DiagnosticOptions.h"
17e5dd7070Spatrick #include "clang/Basic/FileManager.h"
18e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
19e5dd7070Spatrick #include "clang/Basic/Version.h"
20e5dd7070Spatrick #include "clang/Format/Format.h"
21e5dd7070Spatrick #include "clang/Rewrite/Core/Rewriter.h"
22*12c85518Srobert #include "llvm/ADT/StringSwitch.h"
23e5dd7070Spatrick #include "llvm/Support/CommandLine.h"
24e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
25e5dd7070Spatrick #include "llvm/Support/InitLLVM.h"
26e5dd7070Spatrick #include "llvm/Support/Process.h"
27*12c85518Srobert #include <fstream>
28e5dd7070Spatrick 
29e5dd7070Spatrick using namespace llvm;
30e5dd7070Spatrick using clang::tooling::Replacements;
31e5dd7070Spatrick 
32e5dd7070Spatrick static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
33e5dd7070Spatrick 
34e5dd7070Spatrick // Mark all our options with this category, everything else (except for -version
35e5dd7070Spatrick // and -help) will be hidden.
36e5dd7070Spatrick static cl::OptionCategory ClangFormatCategory("Clang-format options");
37e5dd7070Spatrick 
38e5dd7070Spatrick static cl::list<unsigned>
39e5dd7070Spatrick     Offsets("offset",
40e5dd7070Spatrick             cl::desc("Format a range starting at this byte offset.\n"
41e5dd7070Spatrick                      "Multiple ranges can be formatted by specifying\n"
42e5dd7070Spatrick                      "several -offset and -length pairs.\n"
43e5dd7070Spatrick                      "Can only be used with one input file."),
44e5dd7070Spatrick             cl::cat(ClangFormatCategory));
45e5dd7070Spatrick static cl::list<unsigned>
46e5dd7070Spatrick     Lengths("length",
47e5dd7070Spatrick             cl::desc("Format a range of this length (in bytes).\n"
48e5dd7070Spatrick                      "Multiple ranges can be formatted by specifying\n"
49e5dd7070Spatrick                      "several -offset and -length pairs.\n"
50e5dd7070Spatrick                      "When only a single -offset is specified without\n"
51e5dd7070Spatrick                      "-length, clang-format will format up to the end\n"
52e5dd7070Spatrick                      "of the file.\n"
53e5dd7070Spatrick                      "Can only be used with one input file."),
54e5dd7070Spatrick             cl::cat(ClangFormatCategory));
55e5dd7070Spatrick static cl::list<std::string>
56e5dd7070Spatrick     LineRanges("lines",
57e5dd7070Spatrick                cl::desc("<start line>:<end line> - format a range of\n"
58e5dd7070Spatrick                         "lines (both 1-based).\n"
59e5dd7070Spatrick                         "Multiple ranges can be formatted by specifying\n"
60e5dd7070Spatrick                         "several -lines arguments.\n"
61e5dd7070Spatrick                         "Can't be used with -offset and -length.\n"
62e5dd7070Spatrick                         "Can only be used with one input file."),
63e5dd7070Spatrick                cl::cat(ClangFormatCategory));
64e5dd7070Spatrick static cl::opt<std::string>
65e5dd7070Spatrick     Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
66e5dd7070Spatrick           cl::init(clang::format::DefaultFormatStyle),
67e5dd7070Spatrick           cl::cat(ClangFormatCategory));
68e5dd7070Spatrick static cl::opt<std::string>
69e5dd7070Spatrick     FallbackStyle("fallback-style",
70e5dd7070Spatrick                   cl::desc("The name of the predefined style used as a\n"
71e5dd7070Spatrick                            "fallback in case clang-format is invoked with\n"
72e5dd7070Spatrick                            "-style=file, but can not find the .clang-format\n"
73*12c85518Srobert                            "file to use. Defaults to 'LLVM'.\n"
74e5dd7070Spatrick                            "Use -fallback-style=none to skip formatting."),
75e5dd7070Spatrick                   cl::init(clang::format::DefaultFallbackStyle),
76e5dd7070Spatrick                   cl::cat(ClangFormatCategory));
77e5dd7070Spatrick 
78e5dd7070Spatrick static cl::opt<std::string> AssumeFileName(
79e5dd7070Spatrick     "assume-filename",
80*12c85518Srobert     cl::desc("Set filename used to determine the language and to find\n"
81*12c85518Srobert              ".clang-format file.\n"
82*12c85518Srobert              "Only used when reading from stdin.\n"
83*12c85518Srobert              "If this is not passed, the .clang-format file is searched\n"
84*12c85518Srobert              "relative to the current working directory when reading stdin.\n"
85*12c85518Srobert              "Unrecognized filenames are treated as C++.\n"
86*12c85518Srobert              "supported:\n"
87*12c85518Srobert              "  CSharp: .cs\n"
88*12c85518Srobert              "  Java: .java\n"
89*12c85518Srobert              "  JavaScript: .mjs .js .ts\n"
90*12c85518Srobert              "  Json: .json\n"
91*12c85518Srobert              "  Objective-C: .m .mm\n"
92*12c85518Srobert              "  Proto: .proto .protodevel\n"
93*12c85518Srobert              "  TableGen: .td\n"
94*12c85518Srobert              "  TextProto: .textpb .pb.txt .textproto .asciipb\n"
95*12c85518Srobert              "  Verilog: .sv .svh .v .vh"),
96e5dd7070Spatrick     cl::init("<stdin>"), cl::cat(ClangFormatCategory));
97e5dd7070Spatrick 
98e5dd7070Spatrick static cl::opt<bool> Inplace("i",
99e5dd7070Spatrick                              cl::desc("Inplace edit <file>s, if specified."),
100e5dd7070Spatrick                              cl::cat(ClangFormatCategory));
101e5dd7070Spatrick 
102e5dd7070Spatrick static cl::opt<bool> OutputXML("output-replacements-xml",
103e5dd7070Spatrick                                cl::desc("Output replacements as XML."),
104e5dd7070Spatrick                                cl::cat(ClangFormatCategory));
105e5dd7070Spatrick static cl::opt<bool>
106e5dd7070Spatrick     DumpConfig("dump-config",
107e5dd7070Spatrick                cl::desc("Dump configuration options to stdout and exit.\n"
108e5dd7070Spatrick                         "Can be used with -style option."),
109e5dd7070Spatrick                cl::cat(ClangFormatCategory));
110e5dd7070Spatrick static cl::opt<unsigned>
111e5dd7070Spatrick     Cursor("cursor",
112e5dd7070Spatrick            cl::desc("The position of the cursor when invoking\n"
113e5dd7070Spatrick                     "clang-format from an editor integration"),
114e5dd7070Spatrick            cl::init(0), cl::cat(ClangFormatCategory));
115e5dd7070Spatrick 
116*12c85518Srobert static cl::opt<bool>
117*12c85518Srobert     SortIncludes("sort-includes",
118*12c85518Srobert                  cl::desc("If set, overrides the include sorting behavior\n"
119*12c85518Srobert                           "determined by the SortIncludes style flag"),
120e5dd7070Spatrick                  cl::cat(ClangFormatCategory));
121e5dd7070Spatrick 
122*12c85518Srobert static cl::opt<std::string> QualifierAlignment(
123*12c85518Srobert     "qualifier-alignment",
124*12c85518Srobert     cl::desc("If set, overrides the qualifier alignment style\n"
125*12c85518Srobert              "determined by the QualifierAlignment style flag"),
126*12c85518Srobert     cl::init(""), cl::cat(ClangFormatCategory));
127*12c85518Srobert 
128*12c85518Srobert static cl::opt<std::string> Files(
129*12c85518Srobert     "files",
130*12c85518Srobert     cl::desc("A file containing a list of files to process, one per line."),
131*12c85518Srobert     cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory));
132*12c85518Srobert 
133e5dd7070Spatrick static cl::opt<bool>
134e5dd7070Spatrick     Verbose("verbose", cl::desc("If set, shows the list of processed files"),
135e5dd7070Spatrick             cl::cat(ClangFormatCategory));
136e5dd7070Spatrick 
137e5dd7070Spatrick // Use --dry-run to match other LLVM tools when you mean do it but don't
138e5dd7070Spatrick // actually do it
139e5dd7070Spatrick static cl::opt<bool>
140e5dd7070Spatrick     DryRun("dry-run",
141e5dd7070Spatrick            cl::desc("If set, do not actually make the formatting changes"),
142e5dd7070Spatrick            cl::cat(ClangFormatCategory));
143e5dd7070Spatrick 
144e5dd7070Spatrick // Use -n as a common command as an alias for --dry-run. (git and make use -n)
145e5dd7070Spatrick static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"),
146e5dd7070Spatrick                              cl::cat(ClangFormatCategory), cl::aliasopt(DryRun),
147e5dd7070Spatrick                              cl::NotHidden);
148e5dd7070Spatrick 
149e5dd7070Spatrick // Emulate being able to turn on/off the warning.
150e5dd7070Spatrick static cl::opt<bool>
151e5dd7070Spatrick     WarnFormat("Wclang-format-violations",
152e5dd7070Spatrick                cl::desc("Warnings about individual formatting changes needed. "
153e5dd7070Spatrick                         "Used only with --dry-run or -n"),
154e5dd7070Spatrick                cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
155e5dd7070Spatrick 
156e5dd7070Spatrick static cl::opt<bool>
157e5dd7070Spatrick     NoWarnFormat("Wno-clang-format-violations",
158e5dd7070Spatrick                  cl::desc("Do not warn about individual formatting changes "
159e5dd7070Spatrick                           "needed. Used only with --dry-run or -n"),
160e5dd7070Spatrick                  cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
161e5dd7070Spatrick 
162e5dd7070Spatrick static cl::opt<unsigned> ErrorLimit(
163e5dd7070Spatrick     "ferror-limit",
164*12c85518Srobert     cl::desc("Set the maximum number of clang-format errors to emit\n"
165*12c85518Srobert              "before stopping (0 = no limit).\n"
166*12c85518Srobert              "Used only with --dry-run or -n"),
167e5dd7070Spatrick     cl::init(0), cl::cat(ClangFormatCategory));
168e5dd7070Spatrick 
169e5dd7070Spatrick static cl::opt<bool>
170e5dd7070Spatrick     WarningsAsErrors("Werror",
171e5dd7070Spatrick                      cl::desc("If set, changes formatting warnings to errors"),
172e5dd7070Spatrick                      cl::cat(ClangFormatCategory));
173e5dd7070Spatrick 
174a9ac8606Spatrick namespace {
175a9ac8606Spatrick enum class WNoError { Unknown };
176a9ac8606Spatrick }
177a9ac8606Spatrick 
178a9ac8606Spatrick static cl::bits<WNoError> WNoErrorList(
179a9ac8606Spatrick     "Wno-error",
180a9ac8606Spatrick     cl::desc("If set don't error out on the specified warning type."),
181a9ac8606Spatrick     cl::values(
182a9ac8606Spatrick         clEnumValN(WNoError::Unknown, "unknown",
183a9ac8606Spatrick                    "If set, unknown format options are only warned about.\n"
184a9ac8606Spatrick                    "This can be used to enable formatting, even if the\n"
185a9ac8606Spatrick                    "configuration contains unknown (newer) options.\n"
186a9ac8606Spatrick                    "Use with caution, as this might lead to dramatically\n"
187a9ac8606Spatrick                    "differing format depending on an option being\n"
188a9ac8606Spatrick                    "supported or not.")),
189a9ac8606Spatrick     cl::cat(ClangFormatCategory));
190a9ac8606Spatrick 
191e5dd7070Spatrick static cl::opt<bool>
192e5dd7070Spatrick     ShowColors("fcolor-diagnostics",
193e5dd7070Spatrick                cl::desc("If set, and on a color-capable terminal controls "
194e5dd7070Spatrick                         "whether or not to print diagnostics in color"),
195e5dd7070Spatrick                cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
196e5dd7070Spatrick 
197e5dd7070Spatrick static cl::opt<bool>
198e5dd7070Spatrick     NoShowColors("fno-color-diagnostics",
199e5dd7070Spatrick                  cl::desc("If set, and on a color-capable terminal controls "
200e5dd7070Spatrick                           "whether or not to print diagnostics in color"),
201e5dd7070Spatrick                  cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
202e5dd7070Spatrick 
203e5dd7070Spatrick static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"),
204e5dd7070Spatrick                                        cl::cat(ClangFormatCategory));
205e5dd7070Spatrick 
206e5dd7070Spatrick namespace clang {
207e5dd7070Spatrick namespace format {
208e5dd7070Spatrick 
createInMemoryFile(StringRef FileName,MemoryBufferRef Source,SourceManager & Sources,FileManager & Files,llvm::vfs::InMemoryFileSystem * MemFS)209a9ac8606Spatrick static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source,
210e5dd7070Spatrick                                  SourceManager &Sources, FileManager &Files,
211e5dd7070Spatrick                                  llvm::vfs::InMemoryFileSystem *MemFS) {
212e5dd7070Spatrick   MemFS->addFileNoOwn(FileName, 0, Source);
213a9ac8606Spatrick   auto File = Files.getOptionalFileRef(FileName);
214a9ac8606Spatrick   assert(File && "File not added to MemFS?");
215a9ac8606Spatrick   return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User);
216e5dd7070Spatrick }
217e5dd7070Spatrick 
218e5dd7070Spatrick // Parses <start line>:<end line> input to a pair of line numbers.
219e5dd7070Spatrick // Returns true on error.
parseLineRange(StringRef Input,unsigned & FromLine,unsigned & ToLine)220e5dd7070Spatrick static bool parseLineRange(StringRef Input, unsigned &FromLine,
221e5dd7070Spatrick                            unsigned &ToLine) {
222e5dd7070Spatrick   std::pair<StringRef, StringRef> LineRange = Input.split(':');
223e5dd7070Spatrick   return LineRange.first.getAsInteger(0, FromLine) ||
224e5dd7070Spatrick          LineRange.second.getAsInteger(0, ToLine);
225e5dd7070Spatrick }
226e5dd7070Spatrick 
fillRanges(MemoryBuffer * Code,std::vector<tooling::Range> & Ranges)227e5dd7070Spatrick static bool fillRanges(MemoryBuffer *Code,
228e5dd7070Spatrick                        std::vector<tooling::Range> &Ranges) {
229e5dd7070Spatrick   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
230e5dd7070Spatrick       new llvm::vfs::InMemoryFileSystem);
231e5dd7070Spatrick   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
232e5dd7070Spatrick   DiagnosticsEngine Diagnostics(
233e5dd7070Spatrick       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
234e5dd7070Spatrick       new DiagnosticOptions);
235e5dd7070Spatrick   SourceManager Sources(Diagnostics, Files);
236a9ac8606Spatrick   FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
237e5dd7070Spatrick                                  InMemoryFileSystem.get());
238e5dd7070Spatrick   if (!LineRanges.empty()) {
239e5dd7070Spatrick     if (!Offsets.empty() || !Lengths.empty()) {
240e5dd7070Spatrick       errs() << "error: cannot use -lines with -offset/-length\n";
241e5dd7070Spatrick       return true;
242e5dd7070Spatrick     }
243e5dd7070Spatrick 
244e5dd7070Spatrick     for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) {
245e5dd7070Spatrick       unsigned FromLine, ToLine;
246e5dd7070Spatrick       if (parseLineRange(LineRanges[i], FromLine, ToLine)) {
247e5dd7070Spatrick         errs() << "error: invalid <start line>:<end line> pair\n";
248e5dd7070Spatrick         return true;
249e5dd7070Spatrick       }
250*12c85518Srobert       if (FromLine < 1) {
251*12c85518Srobert         errs() << "error: start line should be at least 1\n";
252*12c85518Srobert         return true;
253*12c85518Srobert       }
254e5dd7070Spatrick       if (FromLine > ToLine) {
255*12c85518Srobert         errs() << "error: start line should not exceed end line\n";
256e5dd7070Spatrick         return true;
257e5dd7070Spatrick       }
258e5dd7070Spatrick       SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
259e5dd7070Spatrick       SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX);
260e5dd7070Spatrick       if (Start.isInvalid() || End.isInvalid())
261e5dd7070Spatrick         return true;
262e5dd7070Spatrick       unsigned Offset = Sources.getFileOffset(Start);
263e5dd7070Spatrick       unsigned Length = Sources.getFileOffset(End) - Offset;
264e5dd7070Spatrick       Ranges.push_back(tooling::Range(Offset, Length));
265e5dd7070Spatrick     }
266e5dd7070Spatrick     return false;
267e5dd7070Spatrick   }
268e5dd7070Spatrick 
269e5dd7070Spatrick   if (Offsets.empty())
270e5dd7070Spatrick     Offsets.push_back(0);
271e5dd7070Spatrick   if (Offsets.size() != Lengths.size() &&
272e5dd7070Spatrick       !(Offsets.size() == 1 && Lengths.empty())) {
273e5dd7070Spatrick     errs() << "error: number of -offset and -length arguments must match.\n";
274e5dd7070Spatrick     return true;
275e5dd7070Spatrick   }
276e5dd7070Spatrick   for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
277e5dd7070Spatrick     if (Offsets[i] >= Code->getBufferSize()) {
278e5dd7070Spatrick       errs() << "error: offset " << Offsets[i] << " is outside the file\n";
279e5dd7070Spatrick       return true;
280e5dd7070Spatrick     }
281e5dd7070Spatrick     SourceLocation Start =
282e5dd7070Spatrick         Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]);
283e5dd7070Spatrick     SourceLocation End;
284e5dd7070Spatrick     if (i < Lengths.size()) {
285e5dd7070Spatrick       if (Offsets[i] + Lengths[i] > Code->getBufferSize()) {
286e5dd7070Spatrick         errs() << "error: invalid length " << Lengths[i]
287e5dd7070Spatrick                << ", offset + length (" << Offsets[i] + Lengths[i]
288e5dd7070Spatrick                << ") is outside the file.\n";
289e5dd7070Spatrick         return true;
290e5dd7070Spatrick       }
291e5dd7070Spatrick       End = Start.getLocWithOffset(Lengths[i]);
292e5dd7070Spatrick     } else {
293e5dd7070Spatrick       End = Sources.getLocForEndOfFile(ID);
294e5dd7070Spatrick     }
295e5dd7070Spatrick     unsigned Offset = Sources.getFileOffset(Start);
296e5dd7070Spatrick     unsigned Length = Sources.getFileOffset(End) - Offset;
297e5dd7070Spatrick     Ranges.push_back(tooling::Range(Offset, Length));
298e5dd7070Spatrick   }
299e5dd7070Spatrick   return false;
300e5dd7070Spatrick }
301e5dd7070Spatrick 
outputReplacementXML(StringRef Text)302e5dd7070Spatrick static void outputReplacementXML(StringRef Text) {
303e5dd7070Spatrick   // FIXME: When we sort includes, we need to make sure the stream is correct
304e5dd7070Spatrick   // utf-8.
305e5dd7070Spatrick   size_t From = 0;
306e5dd7070Spatrick   size_t Index;
307e5dd7070Spatrick   while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) {
308e5dd7070Spatrick     outs() << Text.substr(From, Index - From);
309e5dd7070Spatrick     switch (Text[Index]) {
310e5dd7070Spatrick     case '\n':
311e5dd7070Spatrick       outs() << "&#10;";
312e5dd7070Spatrick       break;
313e5dd7070Spatrick     case '\r':
314e5dd7070Spatrick       outs() << "&#13;";
315e5dd7070Spatrick       break;
316e5dd7070Spatrick     case '<':
317e5dd7070Spatrick       outs() << "&lt;";
318e5dd7070Spatrick       break;
319e5dd7070Spatrick     case '&':
320e5dd7070Spatrick       outs() << "&amp;";
321e5dd7070Spatrick       break;
322e5dd7070Spatrick     default:
323e5dd7070Spatrick       llvm_unreachable("Unexpected character encountered!");
324e5dd7070Spatrick     }
325e5dd7070Spatrick     From = Index + 1;
326e5dd7070Spatrick   }
327e5dd7070Spatrick   outs() << Text.substr(From);
328e5dd7070Spatrick }
329e5dd7070Spatrick 
outputReplacementsXML(const Replacements & Replaces)330e5dd7070Spatrick static void outputReplacementsXML(const Replacements &Replaces) {
331e5dd7070Spatrick   for (const auto &R : Replaces) {
332e5dd7070Spatrick     outs() << "<replacement "
333e5dd7070Spatrick            << "offset='" << R.getOffset() << "' "
334e5dd7070Spatrick            << "length='" << R.getLength() << "'>";
335e5dd7070Spatrick     outputReplacementXML(R.getReplacementText());
336e5dd7070Spatrick     outs() << "</replacement>\n";
337e5dd7070Spatrick   }
338e5dd7070Spatrick }
339e5dd7070Spatrick 
340e5dd7070Spatrick static bool
emitReplacementWarnings(const Replacements & Replaces,StringRef AssumedFileName,const std::unique_ptr<llvm::MemoryBuffer> & Code)341e5dd7070Spatrick emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName,
342e5dd7070Spatrick                         const std::unique_ptr<llvm::MemoryBuffer> &Code) {
343e5dd7070Spatrick   if (Replaces.empty())
344e5dd7070Spatrick     return false;
345e5dd7070Spatrick 
346e5dd7070Spatrick   unsigned Errors = 0;
347e5dd7070Spatrick   if (WarnFormat && !NoWarnFormat) {
348e5dd7070Spatrick     llvm::SourceMgr Mgr;
349e5dd7070Spatrick     const char *StartBuf = Code->getBufferStart();
350e5dd7070Spatrick 
351e5dd7070Spatrick     Mgr.AddNewSourceBuffer(
352e5dd7070Spatrick         MemoryBuffer::getMemBuffer(StartBuf, AssumedFileName), SMLoc());
353e5dd7070Spatrick     for (const auto &R : Replaces) {
354e5dd7070Spatrick       SMDiagnostic Diag = Mgr.GetMessage(
355e5dd7070Spatrick           SMLoc::getFromPointer(StartBuf + R.getOffset()),
356e5dd7070Spatrick           WarningsAsErrors ? SourceMgr::DiagKind::DK_Error
357e5dd7070Spatrick                            : SourceMgr::DiagKind::DK_Warning,
358e5dd7070Spatrick           "code should be clang-formatted [-Wclang-format-violations]");
359e5dd7070Spatrick 
360e5dd7070Spatrick       Diag.print(nullptr, llvm::errs(), (ShowColors && !NoShowColors));
361e5dd7070Spatrick       if (ErrorLimit && ++Errors >= ErrorLimit)
362e5dd7070Spatrick         break;
363e5dd7070Spatrick     }
364e5dd7070Spatrick   }
365e5dd7070Spatrick   return WarningsAsErrors;
366e5dd7070Spatrick }
367e5dd7070Spatrick 
outputXML(const Replacements & Replaces,const Replacements & FormatChanges,const FormattingAttemptStatus & Status,const cl::opt<unsigned> & Cursor,unsigned CursorPosition)368e5dd7070Spatrick static void outputXML(const Replacements &Replaces,
369e5dd7070Spatrick                       const Replacements &FormatChanges,
370e5dd7070Spatrick                       const FormattingAttemptStatus &Status,
371e5dd7070Spatrick                       const cl::opt<unsigned> &Cursor,
372e5dd7070Spatrick                       unsigned CursorPosition) {
373e5dd7070Spatrick   outs() << "<?xml version='1.0'?>\n<replacements "
374e5dd7070Spatrick             "xml:space='preserve' incomplete_format='"
375e5dd7070Spatrick          << (Status.FormatComplete ? "false" : "true") << "'";
376e5dd7070Spatrick   if (!Status.FormatComplete)
377e5dd7070Spatrick     outs() << " line='" << Status.Line << "'";
378e5dd7070Spatrick   outs() << ">\n";
379*12c85518Srobert   if (Cursor.getNumOccurrences() != 0) {
380e5dd7070Spatrick     outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition)
381e5dd7070Spatrick            << "</cursor>\n";
382*12c85518Srobert   }
383e5dd7070Spatrick 
384e5dd7070Spatrick   outputReplacementsXML(Replaces);
385e5dd7070Spatrick   outs() << "</replacements>\n";
386e5dd7070Spatrick }
387e5dd7070Spatrick 
388*12c85518Srobert class ClangFormatDiagConsumer : public DiagnosticConsumer {
anchor()389*12c85518Srobert   virtual void anchor() {}
390*12c85518Srobert 
HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,const Diagnostic & Info)391*12c85518Srobert   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
392*12c85518Srobert                         const Diagnostic &Info) override {
393*12c85518Srobert 
394*12c85518Srobert     SmallVector<char, 16> vec;
395*12c85518Srobert     Info.FormatDiagnostic(vec);
396*12c85518Srobert     errs() << "clang-format error:" << vec << "\n";
397*12c85518Srobert   }
398*12c85518Srobert };
399*12c85518Srobert 
400e5dd7070Spatrick // Returns true on error.
format(StringRef FileName)401e5dd7070Spatrick static bool format(StringRef FileName) {
402e5dd7070Spatrick   if (!OutputXML && Inplace && FileName == "-") {
403e5dd7070Spatrick     errs() << "error: cannot use -i when reading from stdin.\n";
404e5dd7070Spatrick     return false;
405e5dd7070Spatrick   }
406e5dd7070Spatrick   // On Windows, overwriting a file with an open file mapping doesn't work,
407e5dd7070Spatrick   // so read the whole file into memory when formatting in-place.
408e5dd7070Spatrick   ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
409e5dd7070Spatrick       !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName)
410e5dd7070Spatrick                             : MemoryBuffer::getFileOrSTDIN(FileName);
411e5dd7070Spatrick   if (std::error_code EC = CodeOrErr.getError()) {
412e5dd7070Spatrick     errs() << EC.message() << "\n";
413e5dd7070Spatrick     return true;
414e5dd7070Spatrick   }
415e5dd7070Spatrick   std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
416e5dd7070Spatrick   if (Code->getBufferSize() == 0)
417e5dd7070Spatrick     return false; // Empty files are formatted correctly.
418e5dd7070Spatrick 
419e5dd7070Spatrick   StringRef BufStr = Code->getBuffer();
420e5dd7070Spatrick 
421e5dd7070Spatrick   const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr);
422e5dd7070Spatrick 
423e5dd7070Spatrick   if (InvalidBOM) {
424e5dd7070Spatrick     errs() << "error: encoding with unsupported byte order mark \""
425e5dd7070Spatrick            << InvalidBOM << "\" detected";
426e5dd7070Spatrick     if (FileName != "-")
427e5dd7070Spatrick       errs() << " in file '" << FileName << "'";
428e5dd7070Spatrick     errs() << ".\n";
429e5dd7070Spatrick     return true;
430e5dd7070Spatrick   }
431e5dd7070Spatrick 
432e5dd7070Spatrick   std::vector<tooling::Range> Ranges;
433e5dd7070Spatrick   if (fillRanges(Code.get(), Ranges))
434e5dd7070Spatrick     return true;
435e5dd7070Spatrick   StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName;
436e5dd7070Spatrick   if (AssumedFileName.empty()) {
437e5dd7070Spatrick     llvm::errs() << "error: empty filenames are not allowed\n";
438e5dd7070Spatrick     return true;
439e5dd7070Spatrick   }
440e5dd7070Spatrick 
441e5dd7070Spatrick   llvm::Expected<FormatStyle> FormatStyle =
442a9ac8606Spatrick       getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
443a9ac8606Spatrick                nullptr, WNoErrorList.isSet(WNoError::Unknown));
444e5dd7070Spatrick   if (!FormatStyle) {
445e5dd7070Spatrick     llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
446e5dd7070Spatrick     return true;
447e5dd7070Spatrick   }
448e5dd7070Spatrick 
449*12c85518Srobert   StringRef QualifierAlignmentOrder = QualifierAlignment;
450*12c85518Srobert 
451*12c85518Srobert   FormatStyle->QualifierAlignment =
452*12c85518Srobert       StringSwitch<FormatStyle::QualifierAlignmentStyle>(
453*12c85518Srobert           QualifierAlignmentOrder.lower())
454*12c85518Srobert           .Case("right", FormatStyle::QAS_Right)
455*12c85518Srobert           .Case("left", FormatStyle::QAS_Left)
456*12c85518Srobert           .Default(FormatStyle->QualifierAlignment);
457*12c85518Srobert 
458*12c85518Srobert   if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
459*12c85518Srobert     FormatStyle->QualifierOrder = {"const", "volatile", "type"};
460*12c85518Srobert   } else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
461*12c85518Srobert     FormatStyle->QualifierOrder = {"type", "const", "volatile"};
462*12c85518Srobert   } else if (QualifierAlignmentOrder.contains("type")) {
463*12c85518Srobert     FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
464*12c85518Srobert     SmallVector<StringRef> Qualifiers;
465*12c85518Srobert     QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
466*12c85518Srobert                                   /*KeepEmpty=*/false);
467*12c85518Srobert     FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
468*12c85518Srobert   }
469*12c85518Srobert 
470a9ac8606Spatrick   if (SortIncludes.getNumOccurrences() != 0) {
471a9ac8606Spatrick     if (SortIncludes)
472a9ac8606Spatrick       FormatStyle->SortIncludes = FormatStyle::SI_CaseSensitive;
473a9ac8606Spatrick     else
474a9ac8606Spatrick       FormatStyle->SortIncludes = FormatStyle::SI_Never;
475a9ac8606Spatrick   }
476e5dd7070Spatrick   unsigned CursorPosition = Cursor;
477e5dd7070Spatrick   Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges,
478e5dd7070Spatrick                                        AssumedFileName, &CursorPosition);
479a9ac8606Spatrick 
480a9ac8606Spatrick   // To format JSON insert a variable to trick the code into thinking its
481a9ac8606Spatrick   // JavaScript.
482*12c85518Srobert   if (FormatStyle->isJson() && !FormatStyle->DisableFormat) {
483a9ac8606Spatrick     auto Err = Replaces.add(tooling::Replacement(
484a9ac8606Spatrick         tooling::Replacement(AssumedFileName, 0, 0, "x = ")));
485*12c85518Srobert     if (Err)
486a9ac8606Spatrick       llvm::errs() << "Bad Json variable insertion\n";
487a9ac8606Spatrick   }
488a9ac8606Spatrick 
489e5dd7070Spatrick   auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
490e5dd7070Spatrick   if (!ChangedCode) {
491e5dd7070Spatrick     llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
492e5dd7070Spatrick     return true;
493e5dd7070Spatrick   }
494e5dd7070Spatrick   // Get new affected ranges after sorting `#includes`.
495e5dd7070Spatrick   Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
496e5dd7070Spatrick   FormattingAttemptStatus Status;
497e5dd7070Spatrick   Replacements FormatChanges =
498e5dd7070Spatrick       reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status);
499e5dd7070Spatrick   Replaces = Replaces.merge(FormatChanges);
500e5dd7070Spatrick   if (OutputXML || DryRun) {
501*12c85518Srobert     if (DryRun)
502e5dd7070Spatrick       return emitReplacementWarnings(Replaces, AssumedFileName, Code);
503*12c85518Srobert     else
504e5dd7070Spatrick       outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
505e5dd7070Spatrick   } else {
506e5dd7070Spatrick     IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
507e5dd7070Spatrick         new llvm::vfs::InMemoryFileSystem);
508e5dd7070Spatrick     FileManager Files(FileSystemOptions(), InMemoryFileSystem);
509*12c85518Srobert 
510*12c85518Srobert     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
511*12c85518Srobert     ClangFormatDiagConsumer IgnoreDiagnostics;
512e5dd7070Spatrick     DiagnosticsEngine Diagnostics(
513*12c85518Srobert         IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
514*12c85518Srobert         &IgnoreDiagnostics, false);
515e5dd7070Spatrick     SourceManager Sources(Diagnostics, Files);
516a9ac8606Spatrick     FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
517e5dd7070Spatrick                                    InMemoryFileSystem.get());
518e5dd7070Spatrick     Rewriter Rewrite(Sources, LangOptions());
519e5dd7070Spatrick     tooling::applyAllReplacements(Replaces, Rewrite);
520e5dd7070Spatrick     if (Inplace) {
521e5dd7070Spatrick       if (Rewrite.overwriteChangedFiles())
522e5dd7070Spatrick         return true;
523e5dd7070Spatrick     } else {
524e5dd7070Spatrick       if (Cursor.getNumOccurrences() != 0) {
525e5dd7070Spatrick         outs() << "{ \"Cursor\": "
526e5dd7070Spatrick                << FormatChanges.getShiftedCodePosition(CursorPosition)
527e5dd7070Spatrick                << ", \"IncompleteFormat\": "
528e5dd7070Spatrick                << (Status.FormatComplete ? "false" : "true");
529e5dd7070Spatrick         if (!Status.FormatComplete)
530e5dd7070Spatrick           outs() << ", \"Line\": " << Status.Line;
531e5dd7070Spatrick         outs() << " }\n";
532e5dd7070Spatrick       }
533e5dd7070Spatrick       Rewrite.getEditBuffer(ID).write(outs());
534e5dd7070Spatrick     }
535e5dd7070Spatrick   }
536e5dd7070Spatrick   return false;
537e5dd7070Spatrick }
538e5dd7070Spatrick 
539e5dd7070Spatrick } // namespace format
540e5dd7070Spatrick } // namespace clang
541e5dd7070Spatrick 
PrintVersion(raw_ostream & OS)542e5dd7070Spatrick static void PrintVersion(raw_ostream &OS) {
543e5dd7070Spatrick   OS << clang::getClangToolFullVersion("clang-format") << '\n';
544e5dd7070Spatrick }
545e5dd7070Spatrick 
546e5dd7070Spatrick // Dump the configuration.
dumpConfig()547e5dd7070Spatrick static int dumpConfig() {
548e5dd7070Spatrick   StringRef FileName;
549e5dd7070Spatrick   std::unique_ptr<llvm::MemoryBuffer> Code;
550e5dd7070Spatrick   if (FileNames.empty()) {
551e5dd7070Spatrick     // We can't read the code to detect the language if there's no
552e5dd7070Spatrick     // file name, so leave Code empty here.
553e5dd7070Spatrick     FileName = AssumeFileName;
554e5dd7070Spatrick   } else {
555e5dd7070Spatrick     // Read in the code in case the filename alone isn't enough to
556e5dd7070Spatrick     // detect the language.
557e5dd7070Spatrick     ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
558e5dd7070Spatrick         MemoryBuffer::getFileOrSTDIN(FileNames[0]);
559e5dd7070Spatrick     if (std::error_code EC = CodeOrErr.getError()) {
560e5dd7070Spatrick       llvm::errs() << EC.message() << "\n";
561e5dd7070Spatrick       return 1;
562e5dd7070Spatrick     }
563e5dd7070Spatrick     FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0];
564e5dd7070Spatrick     Code = std::move(CodeOrErr.get());
565e5dd7070Spatrick   }
566e5dd7070Spatrick   llvm::Expected<clang::format::FormatStyle> FormatStyle =
567e5dd7070Spatrick       clang::format::getStyle(Style, FileName, FallbackStyle,
568e5dd7070Spatrick                               Code ? Code->getBuffer() : "");
569e5dd7070Spatrick   if (!FormatStyle) {
570e5dd7070Spatrick     llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
571e5dd7070Spatrick     return 1;
572e5dd7070Spatrick   }
573e5dd7070Spatrick   std::string Config = clang::format::configurationAsText(*FormatStyle);
574e5dd7070Spatrick   outs() << Config << "\n";
575e5dd7070Spatrick   return 0;
576e5dd7070Spatrick }
577e5dd7070Spatrick 
main(int argc,const char ** argv)578e5dd7070Spatrick int main(int argc, const char **argv) {
579e5dd7070Spatrick   llvm::InitLLVM X(argc, argv);
580e5dd7070Spatrick 
581e5dd7070Spatrick   cl::HideUnrelatedOptions(ClangFormatCategory);
582e5dd7070Spatrick 
583e5dd7070Spatrick   cl::SetVersionPrinter(PrintVersion);
584e5dd7070Spatrick   cl::ParseCommandLineOptions(
585e5dd7070Spatrick       argc, argv,
586a9ac8606Spatrick       "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
587a9ac8606Spatrick       "code.\n\n"
588e5dd7070Spatrick       "If no arguments are specified, it formats the code from standard input\n"
589e5dd7070Spatrick       "and writes the result to the standard output.\n"
590e5dd7070Spatrick       "If <file>s are given, it reformats the files. If -i is specified\n"
591e5dd7070Spatrick       "together with <file>s, the files are edited in-place. Otherwise, the\n"
592e5dd7070Spatrick       "result is written to the standard output.\n");
593e5dd7070Spatrick 
594e5dd7070Spatrick   if (Help) {
595e5dd7070Spatrick     cl::PrintHelpMessage();
596e5dd7070Spatrick     return 0;
597e5dd7070Spatrick   }
598e5dd7070Spatrick 
599*12c85518Srobert   if (DumpConfig)
600e5dd7070Spatrick     return dumpConfig();
601*12c85518Srobert 
602*12c85518Srobert   if (!Files.empty()) {
603*12c85518Srobert     std::ifstream ExternalFileOfFiles{std::string(Files)};
604*12c85518Srobert     std::string Line;
605*12c85518Srobert     unsigned LineNo = 1;
606*12c85518Srobert     while (std::getline(ExternalFileOfFiles, Line)) {
607*12c85518Srobert       FileNames.push_back(Line);
608*12c85518Srobert       LineNo++;
609*12c85518Srobert     }
610*12c85518Srobert     errs() << "Clang-formating " << LineNo << " files\n";
611e5dd7070Spatrick   }
612e5dd7070Spatrick 
613e5dd7070Spatrick   bool Error = false;
614e5dd7070Spatrick   if (FileNames.empty()) {
615e5dd7070Spatrick     Error = clang::format::format("-");
616e5dd7070Spatrick     return Error ? 1 : 0;
617e5dd7070Spatrick   }
618e5dd7070Spatrick   if (FileNames.size() != 1 &&
619e5dd7070Spatrick       (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
620e5dd7070Spatrick     errs() << "error: -offset, -length and -lines can only be used for "
621e5dd7070Spatrick               "single file.\n";
622e5dd7070Spatrick     return 1;
623e5dd7070Spatrick   }
624*12c85518Srobert 
625*12c85518Srobert   unsigned FileNo = 1;
626e5dd7070Spatrick   for (const auto &FileName : FileNames) {
627*12c85518Srobert     if (Verbose) {
628*12c85518Srobert       errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
629*12c85518Srobert              << FileName << "\n";
630*12c85518Srobert     }
631e5dd7070Spatrick     Error |= clang::format::format(FileName);
632e5dd7070Spatrick   }
633e5dd7070Spatrick   return Error ? 1 : 0;
634e5dd7070Spatrick }
635