1 /**
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "diagnosticEngine.h"
17 #include <memory>
18 #include "util/diagnostic.h"
19 #include "util/options.h"
20
21 #include <csignal>
22
23 namespace ark::es2panda::util {
24
Print(const DiagnosticBase & diagnostic,std::ostream & out) const25 void CLIDiagnosticPrinter::Print(const DiagnosticBase &diagnostic, std::ostream &out) const
26 {
27 out << DiagnosticTypeToString(diagnostic.Type()) << ": " << diagnostic.Message();
28 if (!diagnostic.File().empty()) {
29 out << " [" << util::BaseName(diagnostic.File()) << ":" << diagnostic.Line() << ":" << diagnostic.Offset()
30 << "]";
31 }
32 out << std::endl;
33 }
34
Print(const DiagnosticBase & diagnostic) const35 void CLIDiagnosticPrinter::Print(const DiagnosticBase &diagnostic) const
36 {
37 Print(diagnostic, std::cout);
38 }
39
GetDiagnosticStorage(DiagnosticType type)40 const DiagnosticStorage &DiagnosticEngine::GetDiagnosticStorage(DiagnosticType type)
41 {
42 return diagnostics_[type];
43 }
44
Throw(ThrowableDiagnostic diag) const45 [[noreturn]] void DiagnosticEngine::Throw(ThrowableDiagnostic diag) const
46 {
47 throw diag;
48 }
49
GetAllDiagnostic()50 DiagnosticStorage DiagnosticEngine::GetAllDiagnostic()
51 {
52 size_t totalSize = 0;
53 for (const auto &vec : diagnostics_) {
54 totalSize += vec.size();
55 }
56
57 DiagnosticStorage merged;
58 merged.reserve(totalSize);
59 for (auto &vec : diagnostics_) {
60 for (auto &&diag : vec) {
61 merged.emplace_back(std::move(diag));
62 }
63 }
64 return merged;
65 }
66
GetErrorDiagnostic()67 DiagnosticStorage DiagnosticEngine::GetErrorDiagnostic()
68 {
69 size_t errorCount = 0;
70 for (const auto &vec : diagnostics_) {
71 if (!vec.empty() && IsError(vec.front()->Type())) {
72 errorCount += vec.size();
73 }
74 }
75
76 DiagnosticStorage merged;
77 merged.reserve(errorCount);
78 for (const auto &vec : diagnostics_) {
79 if (!vec.empty() && IsError(vec.front()->Type())) {
80 merged.insert(merged.end(), vec.begin(), vec.end());
81 }
82 }
83 return merged;
84 }
85
PrintAndFlushErrorDiagnostic()86 std::string DiagnosticEngine::PrintAndFlushErrorDiagnostic()
87 {
88 auto log = GetErrorDiagnostic();
89 std::sort(log.begin(), log.end(), [](const auto &lhs, const auto &rhs) { return *lhs < *rhs; });
90 auto last = std::unique(log.begin(), log.end(), [](const auto &lhs, const auto &rhs) { return *lhs == *rhs; });
91 std::ostringstream oss;
92 for (auto it = log.begin(); it != last; ++it) {
93 printer_->Print(**it, oss);
94 }
95 return oss.str();
96 }
97
FlushDiagnostic()98 void DiagnosticEngine::FlushDiagnostic()
99 {
100 auto log = GetAllDiagnostic();
101 std::sort(log.begin(), log.end(), [](const auto &lhs, const auto &rhs) { return *lhs < *rhs; });
102 auto last =
103 std::unique(log.begin(), log.end(), [&](const auto &rhs, const auto &lhs) -> bool { return *rhs == *lhs; });
104 for (auto it = log.begin(); it != last; it++) {
105 printer_->Print(**it);
106 }
107 for (auto &vec : diagnostics_) {
108 vec.clear();
109 }
110 }
111 #ifndef FUZZING_EXIT_ON_FAILED_ASSERT
SigSegvHandler(int sig)112 static void SigSegvHandler([[maybe_unused]] int sig)
113 {
114 CompilerBugAction(lexer::SourcePosition {});
115 ark::PrintStack(ark::GetStacktrace(), std::cerr);
116 std::abort(); // CC-OFF(G.STD.16-CPP) fatal error
117 }
118 #endif
119
InitializeSignalHandlers()120 void DiagnosticEngine::InitializeSignalHandlers()
121 {
122 #ifndef FUZZING_EXIT_ON_FAILED_ASSERT
123 std::signal(SIGSEGV, SigSegvHandler);
124 #endif
125 }
126
IsAnyError() const127 bool DiagnosticEngine::IsAnyError() const noexcept
128 {
129 for (size_t i = DiagnosticType::BEGIN; i < DiagnosticType::COUNT; ++i) {
130 if (IsError(static_cast<DiagnosticType>(i)) && !diagnostics_[i].empty()) {
131 return true;
132 }
133 }
134 return false;
135 }
136
GetAnyError() const137 const DiagnosticBase &DiagnosticEngine::GetAnyError() const
138 {
139 ES2PANDA_ASSERT(IsAnyError());
140 for (size_t i = DiagnosticType::BEGIN; i < DiagnosticType::COUNT; ++i) {
141 if (IsError(static_cast<DiagnosticType>(i)) && !diagnostics_[i].empty()) {
142 return *diagnostics_[i].front();
143 }
144 }
145 ES2PANDA_UNREACHABLE();
146 }
147
IsError(DiagnosticType type) const148 bool DiagnosticEngine::IsError(DiagnosticType type) const
149 {
150 switch (type) {
151 case DiagnosticType::FATAL:
152 case DiagnosticType::SYNTAX:
153 case DiagnosticType::SEMANTIC:
154 case DiagnosticType::PLUGIN_ERROR:
155 case DiagnosticType::DECLGEN_ETS2TS_ERROR:
156 case DiagnosticType::ARKTS_CONFIG_ERROR:
157 case DiagnosticType::ISOLATED_DECLGEN:
158 return true;
159 case DiagnosticType::WARNING:
160 case DiagnosticType::DECLGEN_ETS2TS_WARNING:
161 case DiagnosticType::PLUGIN_WARNING:
162 return wError_;
163 case DiagnosticType::SUGGESTION:
164 return false;
165 default:
166 ES2PANDA_UNREACHABLE();
167 }
168 }
169
170 } // namespace ark::es2panda::util
171