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