1 //===- unittests/Basic/DiagnosticTest.cpp -- Diagnostic engine tests ------===// 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/Basic/Diagnostic.h" 10 #include "clang/Basic/DiagnosticError.h" 11 #include "clang/Basic/DiagnosticIDs.h" 12 #include "clang/Basic/DiagnosticLex.h" 13 #include "gtest/gtest.h" 14 #include <optional> 15 16 using namespace llvm; 17 using namespace clang; 18 19 // Declare DiagnosticsTestHelper to avoid GCC warning 20 namespace clang { 21 void DiagnosticsTestHelper(DiagnosticsEngine &diag); 22 } 23 24 void clang::DiagnosticsTestHelper(DiagnosticsEngine &diag) { 25 EXPECT_FALSE(diag.DiagStates.empty()); 26 EXPECT_TRUE(diag.DiagStatesByLoc.empty()); 27 EXPECT_TRUE(diag.DiagStateOnPushStack.empty()); 28 } 29 30 namespace { 31 32 // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics. 33 TEST(DiagnosticTest, suppressAndTrap) { 34 DiagnosticsEngine Diags(new DiagnosticIDs(), 35 new DiagnosticOptions, 36 new IgnoringDiagConsumer()); 37 Diags.setSuppressAllDiagnostics(true); 38 39 { 40 DiagnosticErrorTrap trap(Diags); 41 42 // Diag that would set UncompilableErrorOccurred and ErrorOccurred. 43 Diags.Report(diag::err_target_unknown_triple) << "unknown"; 44 45 // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred. 46 Diags.Report(diag::err_cannot_open_file) << "file" << "error"; 47 48 // Diag that would set FatalErrorOccurred 49 // (via non-note following a fatal error). 50 Diags.Report(diag::warn_mt_message) << "warning"; 51 52 EXPECT_TRUE(trap.hasErrorOccurred()); 53 EXPECT_TRUE(trap.hasUnrecoverableErrorOccurred()); 54 } 55 56 EXPECT_FALSE(Diags.hasErrorOccurred()); 57 EXPECT_FALSE(Diags.hasFatalErrorOccurred()); 58 EXPECT_FALSE(Diags.hasUncompilableErrorOccurred()); 59 EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred()); 60 } 61 62 // Check that FatalsAsError works as intended 63 TEST(DiagnosticTest, fatalsAsError) { 64 for (unsigned FatalsAsError = 0; FatalsAsError != 2; ++FatalsAsError) { 65 DiagnosticsEngine Diags(new DiagnosticIDs(), 66 new DiagnosticOptions, 67 new IgnoringDiagConsumer()); 68 Diags.setFatalsAsError(FatalsAsError); 69 70 // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred. 71 Diags.Report(diag::err_cannot_open_file) << "file" << "error"; 72 73 // Diag that would set FatalErrorOccurred 74 // (via non-note following a fatal error). 75 Diags.Report(diag::warn_mt_message) << "warning"; 76 77 EXPECT_TRUE(Diags.hasErrorOccurred()); 78 EXPECT_EQ(Diags.hasFatalErrorOccurred(), FatalsAsError ? 0u : 1u); 79 EXPECT_TRUE(Diags.hasUncompilableErrorOccurred()); 80 EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred()); 81 82 // The warning should be emitted and counted only if we're not suppressing 83 // after fatal errors. 84 EXPECT_EQ(Diags.getNumWarnings(), FatalsAsError); 85 } 86 } 87 88 TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) { 89 DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, 90 new IgnoringDiagConsumer()); 91 Diags.setFatalsAsError(true); 92 93 // Report a fatal_too_many_errors diagnostic to ensure that still 94 // acts as a fatal error despite downgrading fatal errors to errors. 95 Diags.Report(diag::fatal_too_many_errors); 96 EXPECT_TRUE(Diags.hasFatalErrorOccurred()); 97 98 // Ensure that the severity of that diagnostic is really "fatal". 99 EXPECT_EQ(Diags.getDiagnosticLevel(diag::fatal_too_many_errors, {}), 100 DiagnosticsEngine::Level::Fatal); 101 } 102 103 // Check that soft RESET works as intended 104 TEST(DiagnosticTest, softReset) { 105 DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, 106 new IgnoringDiagConsumer()); 107 108 unsigned numWarnings = 0U, numErrors = 0U; 109 110 Diags.Reset(true); 111 // Check For ErrorOccurred and TrapNumErrorsOccurred 112 EXPECT_FALSE(Diags.hasErrorOccurred()); 113 EXPECT_FALSE(Diags.hasFatalErrorOccurred()); 114 EXPECT_FALSE(Diags.hasUncompilableErrorOccurred()); 115 // Check for UnrecoverableErrorOccurred and TrapNumUnrecoverableErrorsOccurred 116 EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred()); 117 118 EXPECT_EQ(Diags.getNumWarnings(), numWarnings); 119 EXPECT_EQ(Diags.getNumErrors(), numErrors); 120 121 // Check for private variables of DiagnosticsEngine differentiating soft reset 122 DiagnosticsTestHelper(Diags); 123 124 EXPECT_TRUE(Diags.isLastDiagnosticIgnored()); 125 } 126 127 TEST(DiagnosticTest, diagnosticError) { 128 DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, 129 new IgnoringDiagConsumer()); 130 PartialDiagnostic::DiagStorageAllocator Alloc; 131 llvm::Expected<std::pair<int, int>> Value = DiagnosticError::create( 132 SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc) 133 << "file" 134 << "error"); 135 ASSERT_TRUE(!Value); 136 llvm::Error Err = Value.takeError(); 137 std::optional<PartialDiagnosticAt> ErrDiag = DiagnosticError::take(Err); 138 llvm::cantFail(std::move(Err)); 139 ASSERT_FALSE(!ErrDiag); 140 EXPECT_EQ(ErrDiag->first, SourceLocation()); 141 EXPECT_EQ(ErrDiag->second.getDiagID(), diag::err_cannot_open_file); 142 143 Value = std::make_pair(20, 1); 144 ASSERT_FALSE(!Value); 145 EXPECT_EQ(*Value, std::make_pair(20, 1)); 146 EXPECT_EQ(Value->first, 20); 147 } 148 149 TEST(DiagnosticTest, storedDiagEmptyWarning) { 150 DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions); 151 152 class CaptureDiagnosticConsumer : public DiagnosticConsumer { 153 public: 154 SmallVector<StoredDiagnostic> StoredDiags; 155 156 void HandleDiagnostic(DiagnosticsEngine::Level level, 157 const Diagnostic &Info) override { 158 StoredDiags.push_back(StoredDiagnostic(level, Info)); 159 } 160 }; 161 162 CaptureDiagnosticConsumer CaptureConsumer; 163 Diags.setClient(&CaptureConsumer, /*ShouldOwnClient=*/false); 164 Diags.Report(diag::pp_hash_warning) << ""; 165 ASSERT_TRUE(CaptureConsumer.StoredDiags.size() == 1); 166 167 // Make sure an empty warning can round-trip with \c StoredDiagnostic. 168 Diags.Report(CaptureConsumer.StoredDiags.front()); 169 } 170 } 171