1 //===- unittests/Frontend/TextDiagnosticTest.cpp - ------------------------===// 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 #include "clang/Frontend/TextDiagnostic.h" 10 #include "clang/Basic/FileManager.h" 11 #include "clang/Basic/LangOptions.h" 12 #include "clang/Basic/SourceManager.h" 13 #include "llvm/Support/SmallVectorMemoryBuffer.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 using namespace clang; 18 19 namespace { 20 21 /// Prints a diagnostic with the given DiagnosticOptions and the given 22 /// SourceLocation and returns the printed diagnostic text. 23 static std::string PrintDiag(const DiagnosticOptions &Opts, FullSourceLoc Loc) { 24 std::string Out; 25 llvm::raw_string_ostream OS(Out); 26 clang::LangOptions LangOpts; 27 // Owned by TextDiagnostic. 28 DiagnosticOptions *DiagOpts = new DiagnosticOptions(Opts); 29 TextDiagnostic Diag(OS, LangOpts, DiagOpts); 30 // Emit a dummy diagnostic that is just 'message'. 31 Diag.emitDiagnostic(Loc, DiagnosticsEngine::Level::Warning, "message", 32 /*Ranges=*/{}, /*FixItHints=*/{}); 33 OS.flush(); 34 return Out; 35 } 36 37 TEST(TextDiagnostic, ShowLine) { 38 // Create dummy FileManager and SourceManager. 39 FileSystemOptions FSOpts; 40 FileManager FileMgr(FSOpts); 41 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs); 42 DiagnosticsEngine DiagEngine(DiagID, new DiagnosticOptions, 43 new IgnoringDiagConsumer()); 44 SourceManager SrcMgr(DiagEngine, FileMgr); 45 46 // Create a dummy file with some contents to produce a test SourceLocation. 47 const llvm::StringRef file_path = "main.cpp"; 48 const llvm::StringRef main_file_contents = "some\nsource\ncode\n"; 49 const clang::FileEntryRef fe = FileMgr.getVirtualFileRef( 50 file_path, 51 /*Size=*/static_cast<off_t>(main_file_contents.size()), 52 /*ModificationTime=*/0); 53 54 llvm::SmallVector<char, 64> buffer; 55 buffer.append(main_file_contents.begin(), main_file_contents.end()); 56 auto file_contents = std::make_unique<llvm::SmallVectorMemoryBuffer>( 57 std::move(buffer), file_path, /*RequiresNullTerminator=*/false); 58 SrcMgr.overrideFileContents(fe, std::move(file_contents)); 59 60 // Create the actual file id and use it as the main file. 61 clang::FileID fid = 62 SrcMgr.createFileID(fe, SourceLocation(), clang::SrcMgr::C_User); 63 SrcMgr.setMainFileID(fid); 64 65 // Create the source location for the test diagnostic. 66 FullSourceLoc Loc(SrcMgr.translateLineCol(fid, /*Line=*/1, /*Col=*/2), 67 SrcMgr); 68 69 DiagnosticOptions DiagOpts; 70 DiagOpts.ShowLine = true; 71 DiagOpts.ShowColumn = true; 72 // Hide printing the source line/caret to make the diagnostic shorter and it's 73 // not relevant for this test. 74 DiagOpts.ShowCarets = false; 75 EXPECT_EQ("main.cpp:1:2: warning: message\n", PrintDiag(DiagOpts, Loc)); 76 77 // Check that ShowLine doesn't influence the Vi/MSVC diagnostic formats as its 78 // a Clang-specific diagnostic option. 79 DiagOpts.setFormat(TextDiagnosticFormat::Vi); 80 DiagOpts.ShowLine = false; 81 EXPECT_EQ("main.cpp +1:2: warning: message\n", PrintDiag(DiagOpts, Loc)); 82 83 DiagOpts.setFormat(TextDiagnosticFormat::MSVC); 84 DiagOpts.ShowLine = false; 85 EXPECT_EQ("main.cpp(1,2): warning: message\n", PrintDiag(DiagOpts, Loc)); 86 87 // Reset back to the Clang format. 88 DiagOpts.setFormat(TextDiagnosticFormat::Clang); 89 90 // Hide line number but show column. 91 DiagOpts.ShowLine = false; 92 EXPECT_EQ("main.cpp:2: warning: message\n", PrintDiag(DiagOpts, Loc)); 93 94 // Show line number but hide column. 95 DiagOpts.ShowLine = true; 96 DiagOpts.ShowColumn = false; 97 EXPECT_EQ("main.cpp:1: warning: message\n", PrintDiag(DiagOpts, Loc)); 98 } 99 100 } // anonymous namespace 101