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() << " "; 3230b57cec5SDimitry Andric break; 3240b57cec5SDimitry Andric case '\r': 3250b57cec5SDimitry Andric outs() << " "; 3260b57cec5SDimitry Andric break; 3270b57cec5SDimitry Andric case '<': 3280b57cec5SDimitry Andric outs() << "<"; 3290b57cec5SDimitry Andric break; 3300b57cec5SDimitry Andric case '&': 3310b57cec5SDimitry Andric outs() << "&"; 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