Coverage Report

Created: 2021-09-21 08:58

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