Coverage Report

Created: 2022-07-16 07:03

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