llvm.org GIT mirror llvm / 718a779
[SourceMgr][FileCheck] Obey -color by extending WithColor (Relands r344930, reverted in r344935, and now hopefully fixed for Windows.) While this change specifically targets FileCheck, it affects any tool using the same SourceMgr facilities. Previously, -color was documented in FileCheck's -help output, but -color had no effect. Now, -color obeys its documentation: it forces colors to be used in FileCheck diagnostics even when stderr is not a terminal. -color is especially helpful when combined with FileCheck's -v, which can produce a long series of diagnostics that you might wish to pipe to a pager, such as less -R. The WithColor extensions here will also help to clean up color usage in FileCheck's annotated dump of input, which is proposed in D52999. Reviewed By: JDevlieghere, zturner Differential Revision: https://reviews.llvm.org/D53419 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@345202 91177308-0d34-0410-b5e6-96231b3b80d8 Joel E. Denny 1 year, 20 days ago
6 changed file(s) with 190 addition(s) and 97 deletion(s). Raw diff Collapse all Expand all
114114 directives. This option is deprecated and is only provided for convenience
115115 as old tests are migrated to the new non-overlapping ``CHECK-DAG:``
116116 implementation.
117
118 .. option:: --color
119
120 Use colors in output (autodetected by default).
117121
118122 EXIT STATUS
119123 -----------
2828 Macro,
2929 Error,
3030 Warning,
31 Note
31 Note,
32 Remark
3233 };
3334
3435 /// An RAII object that temporarily switches an output stream to a specific
3536 /// color.
3637 class WithColor {
3738 raw_ostream &OS;
38 /// Determine whether colors should be displayed.
39 bool colorsEnabled(raw_ostream &OS);
39 bool DisableColors;
4040
4141 public:
4242 /// To be used like this: WithColor(OS, HighlightColor::String) << "text";
43 WithColor(raw_ostream &OS, HighlightColor S);
43 /// @param OS The output stream
44 /// @param S Symbolic name for syntax element to color
45 /// @param DisableColors Whether to ignore color changes regardless of -color
46 /// and support in OS
47 WithColor(raw_ostream &OS, HighlightColor S, bool DisableColors = false);
48 /// To be used like this: WithColor(OS, raw_ostream::Black) << "text";
49 /// @param OS The output stream
50 /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
51 /// change only the bold attribute, and keep colors untouched
52 /// @param Bold Bold/brighter text, default false
53 /// @param BG If true, change the background, default: change foreground
54 /// @param DisableColors Whether to ignore color changes regardless of -color
55 /// and support in OS
56 WithColor(raw_ostream &OS,
57 raw_ostream::Colors Color = raw_ostream::SAVEDCOLOR,
58 bool Bold = false, bool BG = false, bool DisableColors = false)
59 : OS(OS), DisableColors(DisableColors) {
60 changeColor(Color, Bold, BG);
61 }
4462 ~WithColor();
4563
4664 raw_ostream &get() { return OS; }
4765 operator raw_ostream &() { return OS; }
66 template WithColor &operator<<(T &O) {
67 OS << O;
68 return *this;
69 }
70 template WithColor &operator<<(const T &O) {
71 OS << O;
72 return *this;
73 }
4874
4975 /// Convenience method for printing "error: " to stderr.
5076 static raw_ostream &error();
5278 static raw_ostream &warning();
5379 /// Convenience method for printing "note: " to stderr.
5480 static raw_ostream ¬e();
81 /// Convenience method for printing "remark: " to stderr.
82 static raw_ostream &remark();
5583
5684 /// Convenience method for printing "error: " to the given stream.
57 static raw_ostream &error(raw_ostream &OS, StringRef Prefix = "");
85 static raw_ostream &error(raw_ostream &OS, StringRef Prefix = "",
86 bool DisableColors = false);
5887 /// Convenience method for printing "warning: " to the given stream.
59 static raw_ostream &warning(raw_ostream &OS, StringRef Prefix = "");
88 static raw_ostream &warning(raw_ostream &OS, StringRef Prefix = "",
89 bool DisableColors = false);
6090 /// Convenience method for printing "note: " to the given stream.
61 static raw_ostream ¬e(raw_ostream &OS, StringRef Prefix = "");
91 static raw_ostream ¬e(raw_ostream &OS, StringRef Prefix = "",
92 bool DisableColors = false);
93 /// Convenience method for printing "remark: " to the given stream.
94 static raw_ostream &remark(raw_ostream &OS, StringRef Prefix = "",
95 bool DisableColors = false);
96
97 /// Determine whether colors are displayed.
98 bool colorsEnabled();
99
100 /// Change the color of text that will be output from this point forward.
101 /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
102 /// change only the bold attribute, and keep colors untouched
103 /// @param Bold Bold/brighter text, default false
104 /// @param BG If true, change the background, default: change foreground
105 WithColor &changeColor(raw_ostream::Colors Color, bool Bold = false,
106 bool BG = false);
107
108 /// Reset the colors to terminal defaults. Call this when you are done
109 /// outputting colored text, or before program exit.
110 WithColor &resetColor();
62111 };
63112
64113 } // end namespace llvm
2323 #include "llvm/Support/MemoryBuffer.h"
2424 #include "llvm/Support/Path.h"
2525 #include "llvm/Support/SMLoc.h"
26 #include "llvm/Support/WithColor.h"
2627 #include "llvm/Support/raw_ostream.h"
2728 #include
2829 #include
369370 return c & 0x80;
370371 }
371372
372 void SMDiagnostic::print(const char *ProgName, raw_ostream &S, bool ShowColors,
373 bool ShowKindLabel) const {
374 // Display colors only if OS supports colors.
375 ShowColors &= S.has_colors();
376
377 if (ShowColors)
378 S.changeColor(raw_ostream::SAVEDCOLOR, true);
379
380 if (ProgName && ProgName[0])
381 S << ProgName << ": ";
382
383 if (!Filename.empty()) {
384 if (Filename == "-")
385 S << "";
386 else
387 S << Filename;
388
389 if (LineNo != -1) {
390 S << ':' << LineNo;
391 if (ColumnNo != -1)
392 S << ':' << (ColumnNo+1);
393 }
394 S << ": ";
373 void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
374 bool ShowColors, bool ShowKindLabel) const {
375 {
376 WithColor S(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors);
377
378 if (ProgName && ProgName[0])
379 S << ProgName << ": ";
380
381 if (!Filename.empty()) {
382 if (Filename == "-")
383 S << "";
384 else
385 S << Filename;
386
387 if (LineNo != -1) {
388 S << ':' << LineNo;
389 if (ColumnNo != -1)
390 S << ':' << (ColumnNo + 1);
391 }
392 S << ": ";
393 }
395394 }
396395
397396 if (ShowKindLabel) {
398397 switch (Kind) {
399398 case SourceMgr::DK_Error:
400 if (ShowColors)
401 S.changeColor(raw_ostream::RED, true);
402 S << "error: ";
399 WithColor::error(OS, "", !ShowColors);
403400 break;
404401 case SourceMgr::DK_Warning:
405 if (ShowColors)
406 S.changeColor(raw_ostream::MAGENTA, true);
407 S << "warning: ";
402 WithColor::warning(OS, "", !ShowColors);
408403 break;
409404 case SourceMgr::DK_Note:
410 if (ShowColors)
411 S.changeColor(raw_ostream::BLACK, true);
412 S << "note: ";
405 WithColor::note(OS, "", !ShowColors);
413406 break;
414407 case SourceMgr::DK_Remark:
415 if (ShowColors)
416 S.changeColor(raw_ostream::BLUE, true);
417 S << "remark: ";
408 WithColor::remark(OS, "", !ShowColors);
418409 break;
419410 }
420
421 if (ShowColors) {
422 S.resetColor();
423 S.changeColor(raw_ostream::SAVEDCOLOR, true);
424 }
425 }
426
427 S << Message << '\n';
428
429 if (ShowColors)
430 S.resetColor();
411 }
412
413 WithColor(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors)
414 << Message << '\n';
431415
432416 if (LineNo == -1 || ColumnNo == -1)
433417 return;
438422 // expanding them later, and bail out rather than show incorrect ranges and
439423 // misaligned fixits for any other odd characters.
440424 if (find_if(LineContents, isNonASCII) != LineContents.end()) {
441 printSourceLine(S, LineContents);
425 printSourceLine(OS, LineContents);
442426 return;
443427 }
444428 size_t NumColumns = LineContents.size();
472456 // least.
473457 CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
474458
475 printSourceLine(S, LineContents);
476
477 if (ShowColors)
478 S.changeColor(raw_ostream::GREEN, true);
479
480 // Print out the caret line, matching tabs in the source line.
481 for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
482 if (i >= LineContents.size() || LineContents[i] != '\t') {
483 S << CaretLine[i];
484 ++OutCol;
485 continue;
486 }
487
488 // Okay, we have a tab. Insert the appropriate number of characters.
489 do {
490 S << CaretLine[i];
491 ++OutCol;
492 } while ((OutCol % TabStop) != 0);
493 }
494 S << '\n';
495
496 if (ShowColors)
497 S.resetColor();
459 printSourceLine(OS, LineContents);
460
461 {
462 WithColor S(OS, raw_ostream::GREEN, true, false, !ShowColors);
463
464 // Print out the caret line, matching tabs in the source line.
465 for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
466 if (i >= LineContents.size() || LineContents[i] != '\t') {
467 S << CaretLine[i];
468 ++OutCol;
469 continue;
470 }
471
472 // Okay, we have a tab. Insert the appropriate number of characters.
473 do {
474 S << CaretLine[i];
475 ++OutCol;
476 } while ((OutCol % TabStop) != 0);
477 }
478 S << '\n';
479 }
498480
499481 // Print out the replacement line, matching tabs in the source line.
500482 if (FixItInsertionLine.empty())
502484
503485 for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i < e; ++i) {
504486 if (i >= LineContents.size() || LineContents[i] != '\t') {
505 S << FixItInsertionLine[i];
487 OS << FixItInsertionLine[i];
506488 ++OutCol;
507489 continue;
508490 }
509491
510492 // Okay, we have a tab. Insert the appropriate number of characters.
511493 do {
512 S << FixItInsertionLine[i];
494 OS << FixItInsertionLine[i];
513495 // FIXME: This is trying not to break up replacements, but then to re-sync
514496 // with the tabs between replacements. This will fail, though, if two
515497 // fix-it replacements are exactly adjacent, or if a fix-it contains a
520502 ++OutCol;
521503 } while (((OutCol % TabStop) != 0) && i != e);
522504 }
523 S << '\n';
524 }
505 OS << '\n';
506 }
1818 cl::desc("Use colors in output (default=autodetect)"),
1919 cl::init(cl::BOU_UNSET));
2020
21 bool WithColor::colorsEnabled(raw_ostream &OS) {
22 if (UseColor == cl::BOU_UNSET)
23 return OS.has_colors();
24 return UseColor == cl::BOU_TRUE;
25 }
26
27 WithColor::WithColor(raw_ostream &OS, HighlightColor Color) : OS(OS) {
21 WithColor::WithColor(raw_ostream &OS, HighlightColor Color, bool DisableColors)
22 : OS(OS), DisableColors(DisableColors) {
2823 // Detect color from terminal type unless the user passed the --color option.
29 if (colorsEnabled(OS)) {
24 if (colorsEnabled()) {
3025 switch (Color) {
3126 case HighlightColor::Address:
3227 OS.changeColor(raw_ostream::YELLOW);
5550 case HighlightColor::Note:
5651 OS.changeColor(raw_ostream::BLACK, true);
5752 break;
53 case HighlightColor::Remark:
54 OS.changeColor(raw_ostream::BLUE, true);
55 break;
5856 }
5957 }
6058 }
6563
6664 raw_ostream &WithColor::note() { return note(errs()); }
6765
68 raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix) {
66 raw_ostream &WithColor::remark() { return remark(errs()); }
67
68 raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix,
69 bool DisableColors) {
6970 if (!Prefix.empty())
7071 OS << Prefix << ": ";
71 return WithColor(OS, HighlightColor::Error).get() << "error: ";
72 return WithColor(OS, HighlightColor::Error, DisableColors).get()
73 << "error: ";
7274 }
7375
74 raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix) {
76 raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix,
77 bool DisableColors) {
7578 if (!Prefix.empty())
7679 OS << Prefix << ": ";
77 return WithColor(OS, HighlightColor::Warning).get() << "warning: ";
80 return WithColor(OS, HighlightColor::Warning, DisableColors).get()
81 << "warning: ";
7882 }
7983
80 raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix) {
84 raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix,
85 bool DisableColors) {
8186 if (!Prefix.empty())
8287 OS << Prefix << ": ";
83 return WithColor(OS, HighlightColor::Note).get() << "note: ";
88 return WithColor(OS, HighlightColor::Note, DisableColors).get() << "note: ";
8489 }
8590
86 WithColor::~WithColor() {
87 if (colorsEnabled(OS))
91 raw_ostream &WithColor::remark(raw_ostream &OS, StringRef Prefix,
92 bool DisableColors) {
93 if (!Prefix.empty())
94 OS << Prefix << ": ";
95 return WithColor(OS, HighlightColor::Remark, DisableColors).get()
96 << "remark: ";
97 }
98
99 bool WithColor::colorsEnabled() {
100 if (DisableColors)
101 return false;
102 if (UseColor == cl::BOU_UNSET)
103 return OS.has_colors();
104 return UseColor == cl::BOU_TRUE;
105 }
106
107 WithColor &WithColor::changeColor(raw_ostream::Colors Color, bool Bold,
108 bool BG) {
109 if (colorsEnabled())
110 OS.changeColor(Color, Bold, BG);
111 return *this;
112 }
113
114 WithColor &WithColor::resetColor() {
115 if (colorsEnabled())
88116 OS.resetColor();
117 return *this;
89118 }
119
120 WithColor::~WithColor() { resetColor(); }
0 ; Create a case that produces a simple diagnostic.
1 ; RUN: echo foo > %t.in
2 ; CHECK: bar
3
4 ; Run without and with -color. In the former case, FileCheck should suppress
5 ; color in its diagnostics because stderr is a file.
6 ; RUN: not FileCheck %s < %t.in 2> %t.no-color
7 ; RUN: not FileCheck -color %s < %t.in 2> %t.color
8
9 ; Check whether color was produced.
10 ; RUN: FileCheck -check-prefix NO-COLOR %s < %t.no-color
11 ; RUN: FileCheck -check-prefix COLOR %s < %t.color
12
13 ; Make sure our NO-COLOR and COLOR patterns are sane: they don't match the
14 ; opposite cases.
15 ; RUN: not FileCheck -check-prefix COLOR %s < %t.no-color
16 ; RUN: not FileCheck -check-prefix NO-COLOR %s < %t.color
17
18 ; I don't know of a good way to check for ANSI color codes, so just make sure
19 ; some new characters show up where those codes should appear.
20 ; NO-COLOR: : error: CHECK: expected string not found in input
21 ; COLOR: : {{.+}}error: {{.+}}CHECK: expected string not found in input
1717
1818 #include "llvm/Support/CommandLine.h"
1919 #include "llvm/Support/InitLLVM.h"
20 #include "llvm/Support/Process.h"
2021 #include "llvm/Support/raw_ostream.h"
2122 #include "llvm/Support/FileCheck.h"
2223 using namespace llvm;
107108 }
108109
109110 int main(int argc, char **argv) {
111 // Enable use of ANSI color codes because FileCheck is using them to
112 // highlight text.
113 llvm::sys::Process::UseANSIEscapeCodes(true);
114
110115 InitLLVM X(argc, argv);
111116 cl::ParseCommandLineOptions(argc, argv);
112117