1 //===- unittests/Basic/DiagnosticTest.cpp -- Diagnostic engine tests ------===//
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
7 //===----------------------------------------------------------------------===//
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"
17 using namespace clang
;
19 void clang::DiagnosticsTestHelper(DiagnosticsEngine
&diag
) {
20 unsigned delayedDiagID
= 0U;
22 EXPECT_EQ(diag
.DelayedDiagID
, delayedDiagID
);
23 EXPECT_FALSE(diag
.DiagStates
.empty());
24 EXPECT_TRUE(diag
.DiagStatesByLoc
.empty());
25 EXPECT_TRUE(diag
.DiagStateOnPushStack
.empty());
30 // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics.
31 TEST(DiagnosticTest
, suppressAndTrap
) {
32 DiagnosticsEngine
Diags(new DiagnosticIDs(),
33 new DiagnosticOptions
,
34 new IgnoringDiagConsumer());
35 Diags
.setSuppressAllDiagnostics(true);
38 DiagnosticErrorTrap
trap(Diags
);
40 // Diag that would set UncompilableErrorOccurred and ErrorOccurred.
41 Diags
.Report(diag::err_target_unknown_triple
) << "unknown";
43 // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
44 Diags
.Report(diag::err_cannot_open_file
) << "file" << "error";
46 // Diag that would set FatalErrorOccurred
47 // (via non-note following a fatal error).
48 Diags
.Report(diag::warn_mt_message
) << "warning";
50 EXPECT_TRUE(trap
.hasErrorOccurred());
51 EXPECT_TRUE(trap
.hasUnrecoverableErrorOccurred());
54 EXPECT_FALSE(Diags
.hasErrorOccurred());
55 EXPECT_FALSE(Diags
.hasFatalErrorOccurred());
56 EXPECT_FALSE(Diags
.hasUncompilableErrorOccurred());
57 EXPECT_FALSE(Diags
.hasUnrecoverableErrorOccurred());
60 // Check that FatalsAsError works as intended
61 TEST(DiagnosticTest
, fatalsAsError
) {
62 for (unsigned FatalsAsError
= 0; FatalsAsError
!= 2; ++FatalsAsError
) {
63 DiagnosticsEngine
Diags(new DiagnosticIDs(),
64 new DiagnosticOptions
,
65 new IgnoringDiagConsumer());
66 Diags
.setFatalsAsError(FatalsAsError
);
68 // Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
69 Diags
.Report(diag::err_cannot_open_file
) << "file" << "error";
71 // Diag that would set FatalErrorOccurred
72 // (via non-note following a fatal error).
73 Diags
.Report(diag::warn_mt_message
) << "warning";
75 EXPECT_TRUE(Diags
.hasErrorOccurred());
76 EXPECT_EQ(Diags
.hasFatalErrorOccurred(), FatalsAsError
? 0u : 1u);
77 EXPECT_TRUE(Diags
.hasUncompilableErrorOccurred());
78 EXPECT_TRUE(Diags
.hasUnrecoverableErrorOccurred());
80 // The warning should be emitted and counted only if we're not suppressing
81 // after fatal errors.
82 EXPECT_EQ(Diags
.getNumWarnings(), FatalsAsError
);
86 // Check that soft RESET works as intended
87 TEST(DiagnosticTest
, softReset
) {
88 DiagnosticsEngine
Diags(new DiagnosticIDs(), new DiagnosticOptions
,
89 new IgnoringDiagConsumer());
91 unsigned numWarnings
= 0U, numErrors
= 0U;
94 // Check For ErrorOccurred and TrapNumErrorsOccurred
95 EXPECT_FALSE(Diags
.hasErrorOccurred());
96 EXPECT_FALSE(Diags
.hasFatalErrorOccurred());
97 EXPECT_FALSE(Diags
.hasUncompilableErrorOccurred());
98 // Check for UnrecoverableErrorOccurred and TrapNumUnrecoverableErrorsOccurred
99 EXPECT_FALSE(Diags
.hasUnrecoverableErrorOccurred());
101 EXPECT_EQ(Diags
.getNumWarnings(), numWarnings
);
102 EXPECT_EQ(Diags
.getNumErrors(), numErrors
);
104 // Check for private variables of DiagnosticsEngine differentiating soft reset
105 DiagnosticsTestHelper(Diags
);
107 EXPECT_FALSE(Diags
.isDiagnosticInFlight());
108 EXPECT_TRUE(Diags
.isLastDiagnosticIgnored());
111 TEST(DiagnosticTest
, diagnosticError
) {
112 DiagnosticsEngine
Diags(new DiagnosticIDs(), new DiagnosticOptions
,
113 new IgnoringDiagConsumer());
114 PartialDiagnostic::DiagStorageAllocator Alloc
;
115 llvm::Expected
<std::pair
<int, int>> Value
= DiagnosticError::create(
116 SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file
, Alloc
)
120 llvm::Error Err
= Value
.takeError();
121 std::optional
<PartialDiagnosticAt
> ErrDiag
= DiagnosticError::take(Err
);
122 llvm::cantFail(std::move(Err
));
123 ASSERT_FALSE(!ErrDiag
);
124 EXPECT_EQ(ErrDiag
->first
, SourceLocation());
125 EXPECT_EQ(ErrDiag
->second
.getDiagID(), diag::err_cannot_open_file
);
127 Value
= std::make_pair(20, 1);
128 ASSERT_FALSE(!Value
);
129 EXPECT_EQ(*Value
, std::make_pair(20, 1));
130 EXPECT_EQ(Value
->first
, 20);
133 TEST(DiagnosticTest
, storedDiagEmptyWarning
) {
134 DiagnosticsEngine
Diags(new DiagnosticIDs(), new DiagnosticOptions
);
136 class CaptureDiagnosticConsumer
: public DiagnosticConsumer
{
138 SmallVector
<StoredDiagnostic
> StoredDiags
;
140 void HandleDiagnostic(DiagnosticsEngine::Level level
,
141 const Diagnostic
&Info
) override
{
142 StoredDiags
.push_back(StoredDiagnostic(level
, Info
));
146 CaptureDiagnosticConsumer CaptureConsumer
;
147 Diags
.setClient(&CaptureConsumer
, /*ShouldOwnClient=*/false);
148 Diags
.Report(diag::pp_hash_warning
) << "";
149 ASSERT_TRUE(CaptureConsumer
.StoredDiags
.size() == 1);
151 // Make sure an empty warning can round-trip with \c StoredDiagnostic.
152 Diags
.Report(CaptureConsumer
.StoredDiags
.front());