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 return Out; 34 } 35 36 TEST(TextDiagnostic, ShowLine) { 37 // Create dummy FileManager and SourceManager. 38 FileSystemOptions FSOpts; 39 FileManager FileMgr(FSOpts); 40 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs); 41 DiagnosticsEngine DiagEngine(DiagID, new DiagnosticOptions, 42 new IgnoringDiagConsumer()); 43 SourceManager SrcMgr(DiagEngine, FileMgr); 44 45 // Create a dummy file with some contents to produce a test SourceLocation. 46 const llvm::StringRef file_path = "main.cpp"; 47 const llvm::StringRef main_file_contents = "some\nsource\ncode\n"; 48 const clang::FileEntryRef fe = FileMgr.getVirtualFileRef( 49 file_path, 50 /*Size=*/static_cast<off_t>(main_file_contents.size()), 51 /*ModificationTime=*/0); 52 53 llvm::SmallVector<char, 64> buffer; 54 buffer.append(main_file_contents.begin(), main_file_contents.end()); 55 auto file_contents = std::make_unique<llvm::SmallVectorMemoryBuffer>( 56 std::move(buffer), file_path, /*RequiresNullTerminator=*/false); 57 SrcMgr.overrideFileContents(fe, std::move(file_contents)); 58 59 // Create the actual file id and use it as the main file. 60 clang::FileID fid = 61 SrcMgr.createFileID(fe, SourceLocation(), clang::SrcMgr::C_User); 62 SrcMgr.setMainFileID(fid); 63 64 // Create the source location for the test diagnostic. 65 FullSourceLoc Loc(SrcMgr.translateLineCol(fid, /*Line=*/1, /*Col=*/2), 66 SrcMgr); 67 68 DiagnosticOptions DiagOpts; 69 DiagOpts.ShowLine = true; 70 DiagOpts.ShowColumn = true; 71 // Hide printing the source line/caret to make the diagnostic shorter and it's 72 // not relevant for this test. 73 DiagOpts.ShowCarets = false; 74 EXPECT_EQ("main.cpp:1:2: warning: message\n", PrintDiag(DiagOpts, Loc)); 75 76 // Check that ShowLine doesn't influence the Vi/MSVC diagnostic formats as its 77 // a Clang-specific diagnostic option. 78 DiagOpts.setFormat(TextDiagnosticFormat::Vi); 79 DiagOpts.ShowLine = false; 80 EXPECT_EQ("main.cpp +1:2: warning: message\n", PrintDiag(DiagOpts, Loc)); 81 82 DiagOpts.setFormat(TextDiagnosticFormat::MSVC); 83 DiagOpts.ShowLine = false; 84 EXPECT_EQ("main.cpp(1,2): warning: message\n", PrintDiag(DiagOpts, Loc)); 85 86 // Reset back to the Clang format. 87 DiagOpts.setFormat(TextDiagnosticFormat::Clang); 88 89 // Hide line number but show column. 90 DiagOpts.ShowLine = false; 91 EXPECT_EQ("main.cpp:2: warning: message\n", PrintDiag(DiagOpts, Loc)); 92 93 // Show line number but hide column. 94 DiagOpts.ShowLine = true; 95 DiagOpts.ShowColumn = false; 96 EXPECT_EQ("main.cpp:1: warning: message\n", PrintDiag(DiagOpts, Loc)); 97 } 98 99 } // anonymous namespace 100