xref: /llvm-project/clang/unittests/Basic/DiagnosticTest.cpp (revision eda72fac548f317cec997967494763e9a7bafa27)
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