xref: /freebsd-src/contrib/llvm-project/clang/tools/clang-format/ClangFormat.cpp (revision 62987288060ff68c817b7056815aa9fb8ba8ecd7)
10b57cec5SDimitry Andric //===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements a clang-format tool that automatically formats
110b57cec5SDimitry Andric /// (fragments of) C++ code.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
15647cbc5dSDimitry Andric #include "../../lib/Format/MatchFilePath.h"
160b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h"
170b57cec5SDimitry Andric #include "clang/Basic/DiagnosticOptions.h"
180b57cec5SDimitry Andric #include "clang/Basic/FileManager.h"
190b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
200b57cec5SDimitry Andric #include "clang/Basic/Version.h"
210b57cec5SDimitry Andric #include "clang/Format/Format.h"
220b57cec5SDimitry Andric #include "clang/Rewrite/Core/Rewriter.h"
23349cc55cSDimitry Andric #include "llvm/ADT/StringSwitch.h"
240b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
250b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
260b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
270b57cec5SDimitry Andric #include "llvm/Support/Process.h"
28349cc55cSDimitry Andric #include <fstream>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace llvm;
310b57cec5SDimitry Andric using clang::tooling::Replacements;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric // Mark all our options with this category, everything else (except for -version
360b57cec5SDimitry Andric // and -help) will be hidden.
370b57cec5SDimitry Andric static cl::OptionCategory ClangFormatCategory("Clang-format options");
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric static cl::list<unsigned>
400b57cec5SDimitry Andric     Offsets("offset",
410b57cec5SDimitry Andric             cl::desc("Format a range starting at this byte offset.\n"
420b57cec5SDimitry Andric                      "Multiple ranges can be formatted by specifying\n"
430b57cec5SDimitry Andric                      "several -offset and -length pairs.\n"
440b57cec5SDimitry Andric                      "Can only be used with one input file."),
450b57cec5SDimitry Andric             cl::cat(ClangFormatCategory));
460b57cec5SDimitry Andric static cl::list<unsigned>
470b57cec5SDimitry Andric     Lengths("length",
480b57cec5SDimitry Andric             cl::desc("Format a range of this length (in bytes).\n"
490b57cec5SDimitry Andric                      "Multiple ranges can be formatted by specifying\n"
500b57cec5SDimitry Andric                      "several -offset and -length pairs.\n"
510b57cec5SDimitry Andric                      "When only a single -offset is specified without\n"
520b57cec5SDimitry Andric                      "-length, clang-format will format up to the end\n"
530b57cec5SDimitry Andric                      "of the file.\n"
540b57cec5SDimitry Andric                      "Can only be used with one input file."),
550b57cec5SDimitry Andric             cl::cat(ClangFormatCategory));
560b57cec5SDimitry Andric static cl::list<std::string>
57a7dea167SDimitry Andric     LineRanges("lines",
58a7dea167SDimitry Andric                cl::desc("<start line>:<end line> - format a range of\n"
590b57cec5SDimitry Andric                         "lines (both 1-based).\n"
600b57cec5SDimitry Andric                         "Multiple ranges can be formatted by specifying\n"
610b57cec5SDimitry Andric                         "several -lines arguments.\n"
620b57cec5SDimitry Andric                         "Can't be used with -offset and -length.\n"
630b57cec5SDimitry Andric                         "Can only be used with one input file."),
640b57cec5SDimitry Andric                cl::cat(ClangFormatCategory));
650b57cec5SDimitry Andric static cl::opt<std::string>
660b57cec5SDimitry Andric     Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
670b57cec5SDimitry Andric           cl::init(clang::format::DefaultFormatStyle),
680b57cec5SDimitry Andric           cl::cat(ClangFormatCategory));
690b57cec5SDimitry Andric static cl::opt<std::string>
700b57cec5SDimitry Andric     FallbackStyle("fallback-style",
710b57cec5SDimitry Andric                   cl::desc("The name of the predefined style used as a\n"
720b57cec5SDimitry Andric                            "fallback in case clang-format is invoked with\n"
730b57cec5SDimitry Andric                            "-style=file, but can not find the .clang-format\n"
74753f127fSDimitry Andric                            "file to use. Defaults to 'LLVM'.\n"
750b57cec5SDimitry Andric                            "Use -fallback-style=none to skip formatting."),
760b57cec5SDimitry Andric                   cl::init(clang::format::DefaultFallbackStyle),
770b57cec5SDimitry Andric                   cl::cat(ClangFormatCategory));
780b57cec5SDimitry Andric 
79a7dea167SDimitry Andric static cl::opt<std::string> AssumeFileName(
80a7dea167SDimitry Andric     "assume-filename",
81753f127fSDimitry Andric     cl::desc("Set filename used to determine the language and to find\n"
82753f127fSDimitry Andric              ".clang-format file.\n"
83753f127fSDimitry Andric              "Only used when reading from stdin.\n"
84753f127fSDimitry Andric              "If this is not passed, the .clang-format file is searched\n"
85753f127fSDimitry Andric              "relative to the current working directory when reading stdin.\n"
8681ad6265SDimitry Andric              "Unrecognized filenames are treated as C++.\n"
8781ad6265SDimitry Andric              "supported:\n"
8881ad6265SDimitry Andric              "  CSharp: .cs\n"
8981ad6265SDimitry Andric              "  Java: .java\n"
9081ad6265SDimitry Andric              "  JavaScript: .mjs .js .ts\n"
9181ad6265SDimitry Andric              "  Json: .json\n"
9281ad6265SDimitry Andric              "  Objective-C: .m .mm\n"
9381ad6265SDimitry Andric              "  Proto: .proto .protodevel\n"
9481ad6265SDimitry Andric              "  TableGen: .td\n"
950fca6ea1SDimitry Andric              "  TextProto: .txtpb .textpb .pb.txt .textproto .asciipb\n"
9681ad6265SDimitry Andric              "  Verilog: .sv .svh .v .vh"),
970b57cec5SDimitry Andric     cl::init("<stdin>"), cl::cat(ClangFormatCategory));
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric static cl::opt<bool> Inplace("i",
1000b57cec5SDimitry Andric                              cl::desc("Inplace edit <file>s, if specified."),
1010b57cec5SDimitry Andric                              cl::cat(ClangFormatCategory));
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric static cl::opt<bool> OutputXML("output-replacements-xml",
1040b57cec5SDimitry Andric                                cl::desc("Output replacements as XML."),
1050b57cec5SDimitry Andric                                cl::cat(ClangFormatCategory));
1060b57cec5SDimitry Andric static cl::opt<bool>
1070b57cec5SDimitry Andric     DumpConfig("dump-config",
1080b57cec5SDimitry Andric                cl::desc("Dump configuration options to stdout and exit.\n"
1090b57cec5SDimitry Andric                         "Can be used with -style option."),
1100b57cec5SDimitry Andric                cl::cat(ClangFormatCategory));
1110b57cec5SDimitry Andric static cl::opt<unsigned>
1120b57cec5SDimitry Andric     Cursor("cursor",
1130b57cec5SDimitry Andric            cl::desc("The position of the cursor when invoking\n"
1140b57cec5SDimitry Andric                     "clang-format from an editor integration"),
1150b57cec5SDimitry Andric            cl::init(0), cl::cat(ClangFormatCategory));
1160b57cec5SDimitry Andric 
11781ad6265SDimitry Andric static cl::opt<bool>
11881ad6265SDimitry Andric     SortIncludes("sort-includes",
11981ad6265SDimitry Andric                  cl::desc("If set, overrides the include sorting behavior\n"
12081ad6265SDimitry Andric                           "determined by the SortIncludes style flag"),
1210b57cec5SDimitry Andric                  cl::cat(ClangFormatCategory));
1220b57cec5SDimitry Andric 
123349cc55cSDimitry Andric static cl::opt<std::string> QualifierAlignment(
124349cc55cSDimitry Andric     "qualifier-alignment",
12581ad6265SDimitry Andric     cl::desc("If set, overrides the qualifier alignment style\n"
12681ad6265SDimitry Andric              "determined by the QualifierAlignment style flag"),
127349cc55cSDimitry Andric     cl::init(""), cl::cat(ClangFormatCategory));
128349cc55cSDimitry Andric 
129bdd1243dSDimitry Andric static cl::opt<std::string> Files(
130bdd1243dSDimitry Andric     "files",
131bdd1243dSDimitry Andric     cl::desc("A file containing a list of files to process, one per line."),
132bdd1243dSDimitry Andric     cl::value_desc("filename"), cl::init(""), cl::cat(ClangFormatCategory));
133349cc55cSDimitry Andric 
1340b57cec5SDimitry Andric static cl::opt<bool>
1350b57cec5SDimitry Andric     Verbose("verbose", cl::desc("If set, shows the list of processed files"),
1360b57cec5SDimitry Andric             cl::cat(ClangFormatCategory));
1370b57cec5SDimitry Andric 
138a7dea167SDimitry Andric // Use --dry-run to match other LLVM tools when you mean do it but don't
139a7dea167SDimitry Andric // actually do it
140a7dea167SDimitry Andric static cl::opt<bool>
141a7dea167SDimitry Andric     DryRun("dry-run",
142a7dea167SDimitry Andric            cl::desc("If set, do not actually make the formatting changes"),
143a7dea167SDimitry Andric            cl::cat(ClangFormatCategory));
144a7dea167SDimitry Andric 
145a7dea167SDimitry Andric // Use -n as a common command as an alias for --dry-run. (git and make use -n)
146a7dea167SDimitry Andric static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"),
147a7dea167SDimitry Andric                              cl::cat(ClangFormatCategory), cl::aliasopt(DryRun),
148a7dea167SDimitry Andric                              cl::NotHidden);
149a7dea167SDimitry Andric 
150a7dea167SDimitry Andric // Emulate being able to turn on/off the warning.
151a7dea167SDimitry Andric static cl::opt<bool>
152a7dea167SDimitry Andric     WarnFormat("Wclang-format-violations",
153a7dea167SDimitry Andric                cl::desc("Warnings about individual formatting changes needed. "
154a7dea167SDimitry Andric                         "Used only with --dry-run or -n"),
155a7dea167SDimitry Andric                cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
156a7dea167SDimitry Andric 
157a7dea167SDimitry Andric static cl::opt<bool>
158a7dea167SDimitry Andric     NoWarnFormat("Wno-clang-format-violations",
159a7dea167SDimitry Andric                  cl::desc("Do not warn about individual formatting changes "
160a7dea167SDimitry Andric                           "needed. Used only with --dry-run or -n"),
161a7dea167SDimitry Andric                  cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
162a7dea167SDimitry Andric 
163a7dea167SDimitry Andric static cl::opt<unsigned> ErrorLimit(
164a7dea167SDimitry Andric     "ferror-limit",
16581ad6265SDimitry Andric     cl::desc("Set the maximum number of clang-format errors to emit\n"
16681ad6265SDimitry Andric              "before stopping (0 = no limit).\n"
16781ad6265SDimitry Andric              "Used only with --dry-run or -n"),
168a7dea167SDimitry Andric     cl::init(0), cl::cat(ClangFormatCategory));
169a7dea167SDimitry Andric 
170a7dea167SDimitry Andric static cl::opt<bool>
171a7dea167SDimitry Andric     WarningsAsErrors("Werror",
172a7dea167SDimitry Andric                      cl::desc("If set, changes formatting warnings to errors"),
173a7dea167SDimitry Andric                      cl::cat(ClangFormatCategory));
174a7dea167SDimitry Andric 
175e8d8bef9SDimitry Andric namespace {
176e8d8bef9SDimitry Andric enum class WNoError { Unknown };
177e8d8bef9SDimitry Andric }
178e8d8bef9SDimitry Andric 
179e8d8bef9SDimitry Andric static cl::bits<WNoError> WNoErrorList(
180e8d8bef9SDimitry Andric     "Wno-error",
181e8d8bef9SDimitry Andric     cl::desc("If set don't error out on the specified warning type."),
182e8d8bef9SDimitry Andric     cl::values(
183e8d8bef9SDimitry Andric         clEnumValN(WNoError::Unknown, "unknown",
184e8d8bef9SDimitry Andric                    "If set, unknown format options are only warned about.\n"
185e8d8bef9SDimitry Andric                    "This can be used to enable formatting, even if the\n"
186e8d8bef9SDimitry Andric                    "configuration contains unknown (newer) options.\n"
187e8d8bef9SDimitry Andric                    "Use with caution, as this might lead to dramatically\n"
188e8d8bef9SDimitry Andric                    "differing format depending on an option being\n"
189e8d8bef9SDimitry Andric                    "supported or not.")),
190e8d8bef9SDimitry Andric     cl::cat(ClangFormatCategory));
191e8d8bef9SDimitry Andric 
192a7dea167SDimitry Andric static cl::opt<bool>
193a7dea167SDimitry Andric     ShowColors("fcolor-diagnostics",
194a7dea167SDimitry Andric                cl::desc("If set, and on a color-capable terminal controls "
195a7dea167SDimitry Andric                         "whether or not to print diagnostics in color"),
196a7dea167SDimitry Andric                cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
197a7dea167SDimitry Andric 
198a7dea167SDimitry Andric static cl::opt<bool>
199a7dea167SDimitry Andric     NoShowColors("fno-color-diagnostics",
200a7dea167SDimitry Andric                  cl::desc("If set, and on a color-capable terminal controls "
201a7dea167SDimitry Andric                           "whether or not to print diagnostics in color"),
202a7dea167SDimitry Andric                  cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
203a7dea167SDimitry Andric 
2045f757f3fSDimitry Andric static cl::list<std::string> FileNames(cl::Positional,
2055f757f3fSDimitry Andric                                        cl::desc("[@<file>] [<file> ...]"),
2060b57cec5SDimitry Andric                                        cl::cat(ClangFormatCategory));
2070b57cec5SDimitry Andric 
2080fca6ea1SDimitry Andric static cl::opt<bool> FailOnIncompleteFormat(
2090fca6ea1SDimitry Andric     "fail-on-incomplete-format",
2100fca6ea1SDimitry Andric     cl::desc("If set, fail with exit code 1 on incomplete format."),
2110fca6ea1SDimitry Andric     cl::init(false), cl::cat(ClangFormatCategory));
2120fca6ea1SDimitry Andric 
213*62987288SDimitry Andric static cl::opt<bool> ListIgnored("list-ignored",
214*62987288SDimitry Andric                                  cl::desc("List ignored files."),
215*62987288SDimitry Andric                                  cl::cat(ClangFormatCategory), cl::Hidden);
216*62987288SDimitry Andric 
2170b57cec5SDimitry Andric namespace clang {
2180b57cec5SDimitry Andric namespace format {
2190b57cec5SDimitry Andric 
220e8d8bef9SDimitry Andric static FileID createInMemoryFile(StringRef FileName, MemoryBufferRef Source,
2210b57cec5SDimitry Andric                                  SourceManager &Sources, FileManager &Files,
2220b57cec5SDimitry Andric                                  llvm::vfs::InMemoryFileSystem *MemFS) {
2230b57cec5SDimitry Andric   MemFS->addFileNoOwn(FileName, 0, Source);
224e8d8bef9SDimitry Andric   auto File = Files.getOptionalFileRef(FileName);
225e8d8bef9SDimitry Andric   assert(File && "File not added to MemFS?");
226e8d8bef9SDimitry Andric   return Sources.createFileID(*File, SourceLocation(), SrcMgr::C_User);
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric // Parses <start line>:<end line> input to a pair of line numbers.
2300b57cec5SDimitry Andric // Returns true on error.
2310b57cec5SDimitry Andric static bool parseLineRange(StringRef Input, unsigned &FromLine,
2320b57cec5SDimitry Andric                            unsigned &ToLine) {
2330b57cec5SDimitry Andric   std::pair<StringRef, StringRef> LineRange = Input.split(':');
2340b57cec5SDimitry Andric   return LineRange.first.getAsInteger(0, FromLine) ||
2350b57cec5SDimitry Andric          LineRange.second.getAsInteger(0, ToLine);
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric static bool fillRanges(MemoryBuffer *Code,
2390b57cec5SDimitry Andric                        std::vector<tooling::Range> &Ranges) {
2400b57cec5SDimitry Andric   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
2410b57cec5SDimitry Andric       new llvm::vfs::InMemoryFileSystem);
2420b57cec5SDimitry Andric   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
2430b57cec5SDimitry Andric   DiagnosticsEngine Diagnostics(
2440b57cec5SDimitry Andric       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
2450b57cec5SDimitry Andric       new DiagnosticOptions);
2460b57cec5SDimitry Andric   SourceManager Sources(Diagnostics, Files);
247e8d8bef9SDimitry Andric   FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
2480b57cec5SDimitry Andric                                  InMemoryFileSystem.get());
2490b57cec5SDimitry Andric   if (!LineRanges.empty()) {
2500b57cec5SDimitry Andric     if (!Offsets.empty() || !Lengths.empty()) {
2510b57cec5SDimitry Andric       errs() << "error: cannot use -lines with -offset/-length\n";
2520b57cec5SDimitry Andric       return true;
2530b57cec5SDimitry Andric     }
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric     for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) {
2560b57cec5SDimitry Andric       unsigned FromLine, ToLine;
2570b57cec5SDimitry Andric       if (parseLineRange(LineRanges[i], FromLine, ToLine)) {
2580b57cec5SDimitry Andric         errs() << "error: invalid <start line>:<end line> pair\n";
2590b57cec5SDimitry Andric         return true;
2600b57cec5SDimitry Andric       }
261753f127fSDimitry Andric       if (FromLine < 1) {
262753f127fSDimitry Andric         errs() << "error: start line should be at least 1\n";
263753f127fSDimitry Andric         return true;
264753f127fSDimitry Andric       }
2650b57cec5SDimitry Andric       if (FromLine > ToLine) {
266753f127fSDimitry Andric         errs() << "error: start line should not exceed end line\n";
2670b57cec5SDimitry Andric         return true;
2680b57cec5SDimitry Andric       }
2690b57cec5SDimitry Andric       SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1);
2700b57cec5SDimitry Andric       SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX);
2710b57cec5SDimitry Andric       if (Start.isInvalid() || End.isInvalid())
2720b57cec5SDimitry Andric         return true;
2730b57cec5SDimitry Andric       unsigned Offset = Sources.getFileOffset(Start);
2740b57cec5SDimitry Andric       unsigned Length = Sources.getFileOffset(End) - Offset;
2750b57cec5SDimitry Andric       Ranges.push_back(tooling::Range(Offset, Length));
2760b57cec5SDimitry Andric     }
2770b57cec5SDimitry Andric     return false;
2780b57cec5SDimitry Andric   }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric   if (Offsets.empty())
2810b57cec5SDimitry Andric     Offsets.push_back(0);
2820b57cec5SDimitry Andric   if (Offsets.size() != Lengths.size() &&
2830b57cec5SDimitry Andric       !(Offsets.size() == 1 && Lengths.empty())) {
2840b57cec5SDimitry Andric     errs() << "error: number of -offset and -length arguments must match.\n";
2850b57cec5SDimitry Andric     return true;
2860b57cec5SDimitry Andric   }
2870b57cec5SDimitry Andric   for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {
2880b57cec5SDimitry Andric     if (Offsets[i] >= Code->getBufferSize()) {
2890b57cec5SDimitry Andric       errs() << "error: offset " << Offsets[i] << " is outside the file\n";
2900b57cec5SDimitry Andric       return true;
2910b57cec5SDimitry Andric     }
2920b57cec5SDimitry Andric     SourceLocation Start =
2930b57cec5SDimitry Andric         Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]);
2940b57cec5SDimitry Andric     SourceLocation End;
2950b57cec5SDimitry Andric     if (i < Lengths.size()) {
2960b57cec5SDimitry Andric       if (Offsets[i] + Lengths[i] > Code->getBufferSize()) {
2970b57cec5SDimitry Andric         errs() << "error: invalid length " << Lengths[i]
2980b57cec5SDimitry Andric                << ", offset + length (" << Offsets[i] + Lengths[i]
2990b57cec5SDimitry Andric                << ") is outside the file.\n";
3000b57cec5SDimitry Andric         return true;
3010b57cec5SDimitry Andric       }
3020b57cec5SDimitry Andric       End = Start.getLocWithOffset(Lengths[i]);
3030b57cec5SDimitry Andric     } else {
3040b57cec5SDimitry Andric       End = Sources.getLocForEndOfFile(ID);
3050b57cec5SDimitry Andric     }
3060b57cec5SDimitry Andric     unsigned Offset = Sources.getFileOffset(Start);
3070b57cec5SDimitry Andric     unsigned Length = Sources.getFileOffset(End) - Offset;
3080b57cec5SDimitry Andric     Ranges.push_back(tooling::Range(Offset, Length));
3090b57cec5SDimitry Andric   }
3100b57cec5SDimitry Andric   return false;
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric static void outputReplacementXML(StringRef Text) {
3140b57cec5SDimitry Andric   // FIXME: When we sort includes, we need to make sure the stream is correct
3150b57cec5SDimitry Andric   // utf-8.
3160b57cec5SDimitry Andric   size_t From = 0;
3170b57cec5SDimitry Andric   size_t Index;
3180b57cec5SDimitry Andric   while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) {
3190b57cec5SDimitry Andric     outs() << Text.substr(From, Index - From);
3200b57cec5SDimitry Andric     switch (Text[Index]) {
3210b57cec5SDimitry Andric     case '\n':
3220b57cec5SDimitry Andric       outs() << "&#10;";
3230b57cec5SDimitry Andric       break;
3240b57cec5SDimitry Andric     case '\r':
3250b57cec5SDimitry Andric       outs() << "&#13;";
3260b57cec5SDimitry Andric       break;
3270b57cec5SDimitry Andric     case '<':
3280b57cec5SDimitry Andric       outs() << "&lt;";
3290b57cec5SDimitry Andric       break;
3300b57cec5SDimitry Andric     case '&':
3310b57cec5SDimitry Andric       outs() << "&amp;";
3320b57cec5SDimitry Andric       break;
3330b57cec5SDimitry Andric     default:
3340b57cec5SDimitry Andric       llvm_unreachable("Unexpected character encountered!");
3350b57cec5SDimitry Andric     }
3360b57cec5SDimitry Andric     From = Index + 1;
3370b57cec5SDimitry Andric   }
3380b57cec5SDimitry Andric   outs() << Text.substr(From);
3390b57cec5SDimitry Andric }
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric static void outputReplacementsXML(const Replacements &Replaces) {
3420b57cec5SDimitry Andric   for (const auto &R : Replaces) {
3430fca6ea1SDimitry Andric     outs() << "<replacement "
3440fca6ea1SDimitry Andric            << "offset='" << R.getOffset() << "' "
3450b57cec5SDimitry Andric            << "length='" << R.getLength() << "'>";
3460b57cec5SDimitry Andric     outputReplacementXML(R.getReplacementText());
3470b57cec5SDimitry Andric     outs() << "</replacement>\n";
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
351a7dea167SDimitry Andric static bool
352a7dea167SDimitry Andric emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName,
353a7dea167SDimitry Andric                         const std::unique_ptr<llvm::MemoryBuffer> &Code) {
354480093f4SDimitry Andric   if (Replaces.empty())
355a7dea167SDimitry Andric     return false;
356a7dea167SDimitry Andric 
357a7dea167SDimitry Andric   unsigned Errors = 0;
358a7dea167SDimitry Andric   if (WarnFormat && !NoWarnFormat) {
3590fca6ea1SDimitry Andric     SourceMgr Mgr;
360480093f4SDimitry Andric     const char *StartBuf = Code->getBufferStart();
361480093f4SDimitry Andric 
362480093f4SDimitry Andric     Mgr.AddNewSourceBuffer(
363480093f4SDimitry Andric         MemoryBuffer::getMemBuffer(StartBuf, AssumedFileName), SMLoc());
364a7dea167SDimitry Andric     for (const auto &R : Replaces) {
365480093f4SDimitry Andric       SMDiagnostic Diag = Mgr.GetMessage(
366480093f4SDimitry Andric           SMLoc::getFromPointer(StartBuf + R.getOffset()),
367480093f4SDimitry Andric           WarningsAsErrors ? SourceMgr::DiagKind::DK_Error
368480093f4SDimitry Andric                            : SourceMgr::DiagKind::DK_Warning,
369480093f4SDimitry Andric           "code should be clang-formatted [-Wclang-format-violations]");
370480093f4SDimitry Andric 
371480093f4SDimitry Andric       Diag.print(nullptr, llvm::errs(), (ShowColors && !NoShowColors));
372480093f4SDimitry Andric       if (ErrorLimit && ++Errors >= ErrorLimit)
373a7dea167SDimitry Andric         break;
374a7dea167SDimitry Andric     }
375a7dea167SDimitry Andric   }
376a7dea167SDimitry Andric   return WarningsAsErrors;
377a7dea167SDimitry Andric }
378a7dea167SDimitry Andric 
379a7dea167SDimitry Andric static void outputXML(const Replacements &Replaces,
380a7dea167SDimitry Andric                       const Replacements &FormatChanges,
381a7dea167SDimitry Andric                       const FormattingAttemptStatus &Status,
382a7dea167SDimitry Andric                       const cl::opt<unsigned> &Cursor,
383a7dea167SDimitry Andric                       unsigned CursorPosition) {
384a7dea167SDimitry Andric   outs() << "<?xml version='1.0'?>\n<replacements "
385a7dea167SDimitry Andric             "xml:space='preserve' incomplete_format='"
386a7dea167SDimitry Andric          << (Status.FormatComplete ? "false" : "true") << "'";
387a7dea167SDimitry Andric   if (!Status.FormatComplete)
388a7dea167SDimitry Andric     outs() << " line='" << Status.Line << "'";
389a7dea167SDimitry Andric   outs() << ">\n";
39081ad6265SDimitry Andric   if (Cursor.getNumOccurrences() != 0) {
391a7dea167SDimitry Andric     outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition)
392a7dea167SDimitry Andric            << "</cursor>\n";
39381ad6265SDimitry Andric   }
394a7dea167SDimitry Andric 
395a7dea167SDimitry Andric   outputReplacementsXML(Replaces);
396a7dea167SDimitry Andric   outs() << "</replacements>\n";
397a7dea167SDimitry Andric }
398a7dea167SDimitry Andric 
399349cc55cSDimitry Andric class ClangFormatDiagConsumer : public DiagnosticConsumer {
400349cc55cSDimitry Andric   virtual void anchor() {}
401349cc55cSDimitry Andric 
402349cc55cSDimitry Andric   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
403349cc55cSDimitry Andric                         const Diagnostic &Info) override {
404349cc55cSDimitry Andric 
405349cc55cSDimitry Andric     SmallVector<char, 16> vec;
406349cc55cSDimitry Andric     Info.FormatDiagnostic(vec);
407349cc55cSDimitry Andric     errs() << "clang-format error:" << vec << "\n";
408349cc55cSDimitry Andric   }
409349cc55cSDimitry Andric };
410349cc55cSDimitry Andric 
411a7dea167SDimitry Andric // Returns true on error.
4120fca6ea1SDimitry Andric static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
41374626c16SDimitry Andric   const bool IsSTDIN = FileName == "-";
4145f757f3fSDimitry Andric   if (!OutputXML && Inplace && IsSTDIN) {
415a7dea167SDimitry Andric     errs() << "error: cannot use -i when reading from stdin.\n";
416a7dea167SDimitry Andric     return false;
417a7dea167SDimitry Andric   }
418a7dea167SDimitry Andric   // On Windows, overwriting a file with an open file mapping doesn't work,
419a7dea167SDimitry Andric   // so read the whole file into memory when formatting in-place.
420a7dea167SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
4210fca6ea1SDimitry Andric       !OutputXML && Inplace
4220fca6ea1SDimitry Andric           ? MemoryBuffer::getFileAsStream(FileName)
4230fca6ea1SDimitry Andric           : MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/true);
424a7dea167SDimitry Andric   if (std::error_code EC = CodeOrErr.getError()) {
425a7dea167SDimitry Andric     errs() << EC.message() << "\n";
426a7dea167SDimitry Andric     return true;
427a7dea167SDimitry Andric   }
428a7dea167SDimitry Andric   std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get());
429a7dea167SDimitry Andric   if (Code->getBufferSize() == 0)
430a7dea167SDimitry Andric     return false; // Empty files are formatted correctly.
431a7dea167SDimitry Andric 
432a7dea167SDimitry Andric   StringRef BufStr = Code->getBuffer();
433a7dea167SDimitry Andric 
434480093f4SDimitry Andric   const char *InvalidBOM = SrcMgr::ContentCache::getInvalidBOM(BufStr);
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric   if (InvalidBOM) {
4370b57cec5SDimitry Andric     errs() << "error: encoding with unsupported byte order mark \""
4380b57cec5SDimitry Andric            << InvalidBOM << "\" detected";
4395f757f3fSDimitry Andric     if (!IsSTDIN)
4400b57cec5SDimitry Andric       errs() << " in file '" << FileName << "'";
4410b57cec5SDimitry Andric     errs() << ".\n";
4420b57cec5SDimitry Andric     return true;
4430b57cec5SDimitry Andric   }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   std::vector<tooling::Range> Ranges;
4460b57cec5SDimitry Andric   if (fillRanges(Code.get(), Ranges))
4470b57cec5SDimitry Andric     return true;
4485f757f3fSDimitry Andric   StringRef AssumedFileName = IsSTDIN ? AssumeFileName : FileName;
449480093f4SDimitry Andric   if (AssumedFileName.empty()) {
450480093f4SDimitry Andric     llvm::errs() << "error: empty filenames are not allowed\n";
451480093f4SDimitry Andric     return true;
452480093f4SDimitry Andric   }
4530b57cec5SDimitry Andric 
4540fca6ea1SDimitry Andric   Expected<FormatStyle> FormatStyle =
455e8d8bef9SDimitry Andric       getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
456e8d8bef9SDimitry Andric                nullptr, WNoErrorList.isSet(WNoError::Unknown));
4570b57cec5SDimitry Andric   if (!FormatStyle) {
4580fca6ea1SDimitry Andric     llvm::errs() << toString(FormatStyle.takeError()) << "\n";
4590b57cec5SDimitry Andric     return true;
4600b57cec5SDimitry Andric   }
4610b57cec5SDimitry Andric 
462349cc55cSDimitry Andric   StringRef QualifierAlignmentOrder = QualifierAlignment;
463349cc55cSDimitry Andric 
464349cc55cSDimitry Andric   FormatStyle->QualifierAlignment =
465349cc55cSDimitry Andric       StringSwitch<FormatStyle::QualifierAlignmentStyle>(
466349cc55cSDimitry Andric           QualifierAlignmentOrder.lower())
467349cc55cSDimitry Andric           .Case("right", FormatStyle::QAS_Right)
468349cc55cSDimitry Andric           .Case("left", FormatStyle::QAS_Left)
469349cc55cSDimitry Andric           .Default(FormatStyle->QualifierAlignment);
470349cc55cSDimitry Andric 
47181ad6265SDimitry Andric   if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) {
472349cc55cSDimitry Andric     FormatStyle->QualifierOrder = {"const", "volatile", "type"};
47381ad6265SDimitry Andric   } else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) {
474349cc55cSDimitry Andric     FormatStyle->QualifierOrder = {"type", "const", "volatile"};
47581ad6265SDimitry Andric   } else if (QualifierAlignmentOrder.contains("type")) {
476349cc55cSDimitry Andric     FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom;
477349cc55cSDimitry Andric     SmallVector<StringRef> Qualifiers;
478349cc55cSDimitry Andric     QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1,
479349cc55cSDimitry Andric                                   /*KeepEmpty=*/false);
480349cc55cSDimitry Andric     FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()};
481349cc55cSDimitry Andric   }
482349cc55cSDimitry Andric 
483fe6060f1SDimitry Andric   if (SortIncludes.getNumOccurrences() != 0) {
484fe6060f1SDimitry Andric     if (SortIncludes)
485fe6060f1SDimitry Andric       FormatStyle->SortIncludes = FormatStyle::SI_CaseSensitive;
486fe6060f1SDimitry Andric     else
487fe6060f1SDimitry Andric       FormatStyle->SortIncludes = FormatStyle::SI_Never;
488fe6060f1SDimitry Andric   }
4890b57cec5SDimitry Andric   unsigned CursorPosition = Cursor;
4900b57cec5SDimitry Andric   Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges,
4910b57cec5SDimitry Andric                                        AssumedFileName, &CursorPosition);
492fe6060f1SDimitry Andric 
493fe6060f1SDimitry Andric   // To format JSON insert a variable to trick the code into thinking its
494fe6060f1SDimitry Andric   // JavaScript.
4950eae32dcSDimitry Andric   if (FormatStyle->isJson() && !FormatStyle->DisableFormat) {
496fe6060f1SDimitry Andric     auto Err = Replaces.add(tooling::Replacement(
497fe6060f1SDimitry Andric         tooling::Replacement(AssumedFileName, 0, 0, "x = ")));
49881ad6265SDimitry Andric     if (Err)
499fe6060f1SDimitry Andric       llvm::errs() << "Bad Json variable insertion\n";
500fe6060f1SDimitry Andric   }
501fe6060f1SDimitry Andric 
5020b57cec5SDimitry Andric   auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces);
5030b57cec5SDimitry Andric   if (!ChangedCode) {
5040fca6ea1SDimitry Andric     llvm::errs() << toString(ChangedCode.takeError()) << "\n";
5050b57cec5SDimitry Andric     return true;
5060b57cec5SDimitry Andric   }
5070b57cec5SDimitry Andric   // Get new affected ranges after sorting `#includes`.
5080b57cec5SDimitry Andric   Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
5090b57cec5SDimitry Andric   FormattingAttemptStatus Status;
510a7dea167SDimitry Andric   Replacements FormatChanges =
511a7dea167SDimitry Andric       reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status);
5120b57cec5SDimitry Andric   Replaces = Replaces.merge(FormatChanges);
513a7dea167SDimitry Andric   if (OutputXML || DryRun) {
51481ad6265SDimitry Andric     if (DryRun)
515a7dea167SDimitry Andric       return emitReplacementWarnings(Replaces, AssumedFileName, Code);
516a7dea167SDimitry Andric     outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
5170b57cec5SDimitry Andric   } else {
5180b57cec5SDimitry Andric     IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
5190b57cec5SDimitry Andric         new llvm::vfs::InMemoryFileSystem);
5200b57cec5SDimitry Andric     FileManager Files(FileSystemOptions(), InMemoryFileSystem);
521349cc55cSDimitry Andric 
522349cc55cSDimitry Andric     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
523349cc55cSDimitry Andric     ClangFormatDiagConsumer IgnoreDiagnostics;
5240b57cec5SDimitry Andric     DiagnosticsEngine Diagnostics(
525349cc55cSDimitry Andric         IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
526349cc55cSDimitry Andric         &IgnoreDiagnostics, false);
5270b57cec5SDimitry Andric     SourceManager Sources(Diagnostics, Files);
528e8d8bef9SDimitry Andric     FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
5290b57cec5SDimitry Andric                                    InMemoryFileSystem.get());
5300b57cec5SDimitry Andric     Rewriter Rewrite(Sources, LangOptions());
5310b57cec5SDimitry Andric     tooling::applyAllReplacements(Replaces, Rewrite);
5320b57cec5SDimitry Andric     if (Inplace) {
5330b57cec5SDimitry Andric       if (Rewrite.overwriteChangedFiles())
5340b57cec5SDimitry Andric         return true;
5350b57cec5SDimitry Andric     } else {
5360b57cec5SDimitry Andric       if (Cursor.getNumOccurrences() != 0) {
5370b57cec5SDimitry Andric         outs() << "{ \"Cursor\": "
5380b57cec5SDimitry Andric                << FormatChanges.getShiftedCodePosition(CursorPosition)
5390b57cec5SDimitry Andric                << ", \"IncompleteFormat\": "
5400b57cec5SDimitry Andric                << (Status.FormatComplete ? "false" : "true");
5410b57cec5SDimitry Andric         if (!Status.FormatComplete)
5420b57cec5SDimitry Andric           outs() << ", \"Line\": " << Status.Line;
5430b57cec5SDimitry Andric         outs() << " }\n";
5440b57cec5SDimitry Andric       }
5450b57cec5SDimitry Andric       Rewrite.getEditBuffer(ID).write(outs());
5460b57cec5SDimitry Andric     }
5470b57cec5SDimitry Andric   }
5480fca6ea1SDimitry Andric   return ErrorOnIncompleteFormat && !Status.FormatComplete;
5490b57cec5SDimitry Andric }
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric } // namespace format
5520b57cec5SDimitry Andric } // namespace clang
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric static void PrintVersion(raw_ostream &OS) {
5550b57cec5SDimitry Andric   OS << clang::getClangToolFullVersion("clang-format") << '\n';
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric 
558a7dea167SDimitry Andric // Dump the configuration.
55974626c16SDimitry Andric static int dumpConfig() {
5600b57cec5SDimitry Andric   std::unique_ptr<llvm::MemoryBuffer> Code;
56174626c16SDimitry Andric   // We can't read the code to detect the language if there's no file name.
56274626c16SDimitry Andric   if (!FileNames.empty()) {
5635f757f3fSDimitry Andric     // Read in the code in case the filename alone isn't enough to detect the
5645f757f3fSDimitry Andric     // language.
5650b57cec5SDimitry Andric     ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
5660fca6ea1SDimitry Andric         MemoryBuffer::getFileOrSTDIN(FileNames[0], /*IsText=*/true);
5670b57cec5SDimitry Andric     if (std::error_code EC = CodeOrErr.getError()) {
5680b57cec5SDimitry Andric       llvm::errs() << EC.message() << "\n";
5690b57cec5SDimitry Andric       return 1;
5700b57cec5SDimitry Andric     }
5710b57cec5SDimitry Andric     Code = std::move(CodeOrErr.get());
57274626c16SDimitry Andric   }
5730fca6ea1SDimitry Andric   Expected<clang::format::FormatStyle> FormatStyle = clang::format::getStyle(
5740fca6ea1SDimitry Andric       Style,
5750fca6ea1SDimitry Andric       FileNames.empty() || FileNames[0] == "-" ? AssumeFileName : FileNames[0],
5765f757f3fSDimitry Andric       FallbackStyle, Code ? Code->getBuffer() : "");
5770b57cec5SDimitry Andric   if (!FormatStyle) {
5780fca6ea1SDimitry Andric     llvm::errs() << toString(FormatStyle.takeError()) << "\n";
5790b57cec5SDimitry Andric     return 1;
5800b57cec5SDimitry Andric   }
5810b57cec5SDimitry Andric   std::string Config = clang::format::configurationAsText(*FormatStyle);
5820b57cec5SDimitry Andric   outs() << Config << "\n";
5830b57cec5SDimitry Andric   return 0;
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric 
586297eecfbSDimitry Andric using String = SmallString<128>;
587297eecfbSDimitry Andric static String IgnoreDir;             // Directory of .clang-format-ignore file.
588297eecfbSDimitry Andric static String PrevDir;               // Directory of previous `FilePath`.
589297eecfbSDimitry Andric static SmallVector<String> Patterns; // Patterns in .clang-format-ignore file.
590297eecfbSDimitry Andric 
591647cbc5dSDimitry Andric // Check whether `FilePath` is ignored according to the nearest
592647cbc5dSDimitry Andric // .clang-format-ignore file based on the rules below:
593647cbc5dSDimitry Andric // - A blank line is skipped.
594647cbc5dSDimitry Andric // - Leading and trailing spaces of a line are trimmed.
595647cbc5dSDimitry Andric // - A line starting with a hash (`#`) is a comment.
596647cbc5dSDimitry Andric // - A non-comment line is a single pattern.
597647cbc5dSDimitry Andric // - The slash (`/`) is used as the directory separator.
598647cbc5dSDimitry Andric // - A pattern is relative to the directory of the .clang-format-ignore file (or
599647cbc5dSDimitry Andric //   the root directory if the pattern starts with a slash).
600647cbc5dSDimitry Andric // - A pattern is negated if it starts with a bang (`!`).
601647cbc5dSDimitry Andric static bool isIgnored(StringRef FilePath) {
602647cbc5dSDimitry Andric   using namespace llvm::sys::fs;
603647cbc5dSDimitry Andric   if (!is_regular_file(FilePath))
604647cbc5dSDimitry Andric     return false;
605647cbc5dSDimitry Andric 
606297eecfbSDimitry Andric   String Path;
607297eecfbSDimitry Andric   String AbsPath{FilePath};
608647cbc5dSDimitry Andric 
609297eecfbSDimitry Andric   using namespace llvm::sys::path;
610647cbc5dSDimitry Andric   make_absolute(AbsPath);
611647cbc5dSDimitry Andric   remove_dots(AbsPath, /*remove_dot_dot=*/true);
612647cbc5dSDimitry Andric 
613297eecfbSDimitry Andric   if (StringRef Dir{parent_path(AbsPath)}; PrevDir != Dir) {
614297eecfbSDimitry Andric     PrevDir = Dir;
615647cbc5dSDimitry Andric 
616297eecfbSDimitry Andric     for (;;) {
617297eecfbSDimitry Andric       Path = Dir;
618647cbc5dSDimitry Andric       append(Path, ".clang-format-ignore");
619297eecfbSDimitry Andric       if (is_regular_file(Path))
620297eecfbSDimitry Andric         break;
621297eecfbSDimitry Andric       Dir = parent_path(Dir);
622297eecfbSDimitry Andric       if (Dir.empty())
623297eecfbSDimitry Andric         return false;
624297eecfbSDimitry Andric     }
625297eecfbSDimitry Andric 
626297eecfbSDimitry Andric     IgnoreDir = convert_to_slash(Dir);
627647cbc5dSDimitry Andric 
628647cbc5dSDimitry Andric     std::ifstream IgnoreFile{Path.c_str()};
629647cbc5dSDimitry Andric     if (!IgnoreFile.good())
630647cbc5dSDimitry Andric       return false;
631647cbc5dSDimitry Andric 
632297eecfbSDimitry Andric     Patterns.clear();
633647cbc5dSDimitry Andric 
634297eecfbSDimitry Andric     for (std::string Line; std::getline(IgnoreFile, Line);) {
635297eecfbSDimitry Andric       if (const auto Pattern{StringRef{Line}.trim()};
636297eecfbSDimitry Andric           // Skip empty and comment lines.
637297eecfbSDimitry Andric           !Pattern.empty() && Pattern[0] != '#') {
638297eecfbSDimitry Andric         Patterns.push_back(Pattern);
639297eecfbSDimitry Andric       }
640297eecfbSDimitry Andric     }
641297eecfbSDimitry Andric   }
642297eecfbSDimitry Andric 
643297eecfbSDimitry Andric   if (IgnoreDir.empty())
644297eecfbSDimitry Andric     return false;
645297eecfbSDimitry Andric 
646297eecfbSDimitry Andric   const auto Pathname{convert_to_slash(AbsPath)};
647297eecfbSDimitry Andric   for (const auto &Pat : Patterns) {
648297eecfbSDimitry Andric     const bool IsNegated = Pat[0] == '!';
649297eecfbSDimitry Andric     StringRef Pattern{Pat};
650647cbc5dSDimitry Andric     if (IsNegated)
651647cbc5dSDimitry Andric       Pattern = Pattern.drop_front();
652647cbc5dSDimitry Andric 
653647cbc5dSDimitry Andric     if (Pattern.empty())
654647cbc5dSDimitry Andric       continue;
655647cbc5dSDimitry Andric 
656647cbc5dSDimitry Andric     Pattern = Pattern.ltrim();
657297eecfbSDimitry Andric 
658297eecfbSDimitry Andric     // `Pattern` is relative to `IgnoreDir` unless it starts with a slash.
659297eecfbSDimitry Andric     // This doesn't support patterns containing drive names (e.g. `C:`).
660647cbc5dSDimitry Andric     if (Pattern[0] != '/') {
661297eecfbSDimitry Andric       Path = IgnoreDir;
662647cbc5dSDimitry Andric       append(Path, Style::posix, Pattern);
663647cbc5dSDimitry Andric       remove_dots(Path, /*remove_dot_dot=*/true, Style::posix);
664297eecfbSDimitry Andric       Pattern = Path;
665647cbc5dSDimitry Andric     }
666647cbc5dSDimitry Andric 
667647cbc5dSDimitry Andric     if (clang::format::matchFilePath(Pattern, Pathname) == !IsNegated)
668647cbc5dSDimitry Andric       return true;
669647cbc5dSDimitry Andric   }
670647cbc5dSDimitry Andric 
671647cbc5dSDimitry Andric   return false;
672647cbc5dSDimitry Andric }
673647cbc5dSDimitry Andric 
674a7dea167SDimitry Andric int main(int argc, const char **argv) {
6750fca6ea1SDimitry Andric   InitLLVM X(argc, argv);
676a7dea167SDimitry Andric 
677a7dea167SDimitry Andric   cl::HideUnrelatedOptions(ClangFormatCategory);
678a7dea167SDimitry Andric 
679a7dea167SDimitry Andric   cl::SetVersionPrinter(PrintVersion);
680a7dea167SDimitry Andric   cl::ParseCommandLineOptions(
681a7dea167SDimitry Andric       argc, argv,
682fe6060f1SDimitry Andric       "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
683fe6060f1SDimitry Andric       "code.\n\n"
684a7dea167SDimitry Andric       "If no arguments are specified, it formats the code from standard input\n"
685a7dea167SDimitry Andric       "and writes the result to the standard output.\n"
686a7dea167SDimitry Andric       "If <file>s are given, it reformats the files. If -i is specified\n"
687a7dea167SDimitry Andric       "together with <file>s, the files are edited in-place. Otherwise, the\n"
688a7dea167SDimitry Andric       "result is written to the standard output.\n");
689a7dea167SDimitry Andric 
690a7dea167SDimitry Andric   if (Help) {
691a7dea167SDimitry Andric     cl::PrintHelpMessage();
692a7dea167SDimitry Andric     return 0;
693a7dea167SDimitry Andric   }
694a7dea167SDimitry Andric 
69581ad6265SDimitry Andric   if (DumpConfig)
69674626c16SDimitry Andric     return dumpConfig();
697a7dea167SDimitry Andric 
698349cc55cSDimitry Andric   if (!Files.empty()) {
699349cc55cSDimitry Andric     std::ifstream ExternalFileOfFiles{std::string(Files)};
700349cc55cSDimitry Andric     std::string Line;
701349cc55cSDimitry Andric     unsigned LineNo = 1;
702349cc55cSDimitry Andric     while (std::getline(ExternalFileOfFiles, Line)) {
703349cc55cSDimitry Andric       FileNames.push_back(Line);
704349cc55cSDimitry Andric       LineNo++;
705349cc55cSDimitry Andric     }
706349cc55cSDimitry Andric     errs() << "Clang-formating " << LineNo << " files\n";
707349cc55cSDimitry Andric   }
708349cc55cSDimitry Andric 
70974626c16SDimitry Andric   if (FileNames.empty())
7100fca6ea1SDimitry Andric     return clang::format::format("-", FailOnIncompleteFormat);
71174626c16SDimitry Andric 
71274626c16SDimitry Andric   if (FileNames.size() > 1 &&
713a7dea167SDimitry Andric       (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
7140b57cec5SDimitry Andric     errs() << "error: -offset, -length and -lines can only be used for "
7150b57cec5SDimitry Andric               "single file.\n";
7160b57cec5SDimitry Andric     return 1;
7170b57cec5SDimitry Andric   }
718349cc55cSDimitry Andric 
719349cc55cSDimitry Andric   unsigned FileNo = 1;
7205f757f3fSDimitry Andric   bool Error = false;
7210b57cec5SDimitry Andric   for (const auto &FileName : FileNames) {
722*62987288SDimitry Andric     const bool Ignored = isIgnored(FileName);
723*62987288SDimitry Andric     if (ListIgnored) {
724*62987288SDimitry Andric       if (Ignored)
725*62987288SDimitry Andric         outs() << FileName << '\n';
726*62987288SDimitry Andric       continue;
727*62987288SDimitry Andric     }
728*62987288SDimitry Andric     if (Ignored)
729647cbc5dSDimitry Andric       continue;
73081ad6265SDimitry Andric     if (Verbose) {
731349cc55cSDimitry Andric       errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
732349cc55cSDimitry Andric              << FileName << "\n";
73381ad6265SDimitry Andric     }
7340fca6ea1SDimitry Andric     Error |= clang::format::format(FileName, FailOnIncompleteFormat);
7350b57cec5SDimitry Andric   }
7360b57cec5SDimitry Andric   return Error ? 1 : 0;
7370b57cec5SDimitry Andric }
738