diff --git a/clang/include/clang/Basic/DiagnosticOptions.def b/clang/include/clang/Basic/DiagnosticOptions.def --- a/clang/include/clang/Basic/DiagnosticOptions.def +++ b/clang/include/clang/Basic/DiagnosticOptions.def @@ -47,6 +47,7 @@ DIAGOPT(NoRewriteMacros, 1, 0) /// -Wno-rewrite-macros DIAGOPT(Pedantic, 1, 0) /// -pedantic DIAGOPT(PedanticErrors, 1, 0) /// -pedantic-errors +DIAGOPT(ShowLine, 1, 1) /// Show line number on diagnostics. DIAGOPT(ShowColumn, 1, 1) /// Show column number on diagnostics. DIAGOPT(ShowLocation, 1, 1) /// Show source location information. DIAGOPT(ShowLevel, 1, 1) /// Show diagnostic level. diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -827,7 +827,10 @@ emitFilename(PLoc.getFilename(), Loc.getManager()); switch (DiagOpts->getFormat()) { - case DiagnosticOptions::Clang: OS << ':' << LineNo; break; + case DiagnosticOptions::Clang: + if (DiagOpts->ShowLine) + OS << ':' << LineNo; + break; case DiagnosticOptions::MSVC: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } diff --git a/clang/unittests/Frontend/CMakeLists.txt b/clang/unittests/Frontend/CMakeLists.txt --- a/clang/unittests/Frontend/CMakeLists.txt +++ b/clang/unittests/Frontend/CMakeLists.txt @@ -12,6 +12,7 @@ ParsedSourceLocationTest.cpp PCHPreambleTest.cpp OutputStreamTest.cpp + TextDiagnosticTest.cpp ) clang_target_link_libraries(FrontendTests PRIVATE diff --git a/clang/unittests/Frontend/TextDiagnosticTest.cpp b/clang/unittests/Frontend/TextDiagnosticTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/Frontend/TextDiagnosticTest.cpp @@ -0,0 +1,100 @@ +//===- unittests/Frontend/TextDiagnosticTest.cpp - ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/TextDiagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { + +/// Prints a diagnostic with the given DiagnosticOptions and the given +/// SourceLocation and returns the printed diagnostic text. +static std::string PrintDiag(const DiagnosticOptions &Opts, FullSourceLoc Loc) { + std::string Out; + llvm::raw_string_ostream OS(Out); + clang::LangOptions LangOpts; + // Owned by TextDiagnostic. + DiagnosticOptions *DiagOpts = new DiagnosticOptions(Opts); + TextDiagnostic Diag(OS, LangOpts, DiagOpts); + // Emit a dummy diagnostic that is just 'message'. + Diag.emitDiagnostic(Loc, DiagnosticsEngine::Level::Warning, "message", + /*Ranges=*/{}, /*FixItHints=*/{}); + OS.flush(); + return Out; +} + +TEST(TextDiagnostic, ShowLine) { + // Create dummy FileManager and SourceManager. + FileSystemOptions FSOpts; + FileManager FileMgr(FSOpts); + IntrusiveRefCntPtr DiagID(new DiagnosticIDs); + DiagnosticsEngine DiagEngine(DiagID, new DiagnosticOptions, + new IgnoringDiagConsumer()); + SourceManager SrcMgr(DiagEngine, FileMgr); + + // Create a dummy file with some contents to produce a test SourceLocation. + const llvm::StringRef file_path = "main.cpp"; + const llvm::StringRef main_file_contents = "some\nsource\ncode\n"; + const clang::FileEntry &fe = *FileMgr.getVirtualFile( + file_path, + /*Size=*/static_cast(main_file_contents.size()), + /*ModificationTime=*/0); + + llvm::SmallVector buffer; + buffer.append(main_file_contents.begin(), main_file_contents.end()); + auto file_contents = std::make_unique( + std::move(buffer), file_path); + SrcMgr.overrideFileContents(&fe, std::move(file_contents)); + + // Create the actual file id and use it as the main file. + clang::FileID fid = + SrcMgr.createFileID(&fe, SourceLocation(), clang::SrcMgr::C_User); + SrcMgr.setMainFileID(fid); + + // Create the source location for the test diagnostic. + FullSourceLoc Loc(SrcMgr.translateLineCol(fid, /*Line=*/1, /*Col=*/2), + SrcMgr); + + DiagnosticOptions DiagOpts; + DiagOpts.ShowLine = true; + DiagOpts.ShowColumn = true; + // Hide printing the source line/caret to make the diagnostic shorter and it's + // not relevant for this test. + DiagOpts.ShowCarets = false; + EXPECT_EQ("main.cpp:1:2: warning: message\n", PrintDiag(DiagOpts, Loc)); + + // Check that ShowLine doesn't influence the Vi/MSVC diagnostic formats as its + // a Clang-specific diagnostic option. + DiagOpts.setFormat(TextDiagnosticFormat::Vi); + DiagOpts.ShowLine = false; + EXPECT_EQ("main.cpp +1:2: warning: message\n", PrintDiag(DiagOpts, Loc)); + + DiagOpts.setFormat(TextDiagnosticFormat::MSVC); + DiagOpts.ShowLine = false; + EXPECT_EQ("main.cpp(1,2): warning: message\n", PrintDiag(DiagOpts, Loc)); + + // Reset back to the Clang format. + DiagOpts.setFormat(TextDiagnosticFormat::Clang); + + // Hide line number but show column. + DiagOpts.ShowLine = false; + EXPECT_EQ("main.cpp:2: warning: message\n", PrintDiag(DiagOpts, Loc)); + + // Show line number but hide column. + DiagOpts.ShowLine = true; + DiagOpts.ShowColumn = false; + EXPECT_EQ("main.cpp:1: warning: message\n", PrintDiag(DiagOpts, Loc)); +} + +} // anonymous namespace