• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-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 "ETSNolintParser.h"
17 
18 namespace ark::es2panda::parser {
ETSNolintParser(ParserImpl * mainParser)19 ETSNolintParser::ETSNolintParser(ParserImpl *mainParser) : parser_(mainParser)
20 {
21     line_ = parser_->Lexer()->Line();
22 }
23 
SetStartPos()24 void ETSNolintParser::SetStartPos()
25 {
26     line_ = parser_->Lexer()->Pos().Line();
27     startPos_ = parser_->Lexer()->Pos().Iterator().Index();
28     posOffset_ = startPos_;
29 
30     BackwardSymbol(startPos_);
31 }
32 
CollectETSNolints()33 void ETSNolintParser::CollectETSNolints()
34 {
35     SetStartPos();
36     char32_t cp = PeekSymbol();
37 
38     while (cp != lexer::LEX_CHAR_EOS && cp != lexer::UNICODE_CODE_POINT_MAX && cp != lexer::UNICODE_INVALID_CP) {
39         if (!IsEtsNolint()) {
40             NextSymbol();
41             cp = PeekSymbol();
42             continue;
43         }
44         std::size_t line = line_;
45         std::set<ETSWarnings> collection;
46         if (IsNextLine()) {
47             collection = ParseETSNolintArgs();
48             line += 1;
49         } else if (IsBegin()) {
50             collection = ParseETSNolintArgs();
51             for (const auto it : collection) {
52                 applyingCollection_.insert(it);
53             }
54         } else if (IsEnd()) {
55             collection = ParseETSNolintArgs();
56 
57             for (const auto it : collection) {
58                 applyingCollection_.erase(it);
59             }
60             cp = PeekSymbol();
61             continue;
62         } else {
63             collection = ParseETSNolintArgs();
64         }
65         AddToETSNolintLinesCollection(line, collection);
66         cp = PeekSymbol();
67     }
68 
69     RewindToStart();
70 }
71 
ApplyETSNolintsToStatements(ArenaVector<ir::Statement * > & statements) const72 void ETSNolintParser::ApplyETSNolintsToStatements(ArenaVector<ir::Statement *> &statements) const
73 {
74     for (auto *it : statements) {
75         ApplyETSNolintsToNodesRecursively(it);
76     }
77 }
78 
NextSymbol()79 void ETSNolintParser::NextSymbol()
80 {
81     if (PeekSymbol() == lexer::LEX_CHAR_LF) {
82         if (!applyingCollection_.empty()) {
83             AddToETSNolintLinesCollection(line_, applyingCollection_);
84         }
85         line_++;
86     }
87 
88     posOffset_++;
89     parser_->Lexer()->Pos().Iterator().Forward(1);
90 }
91 
BackwardSymbol()92 void ETSNolintParser::BackwardSymbol()
93 {
94     posOffset_--;
95     parser_->Lexer()->Pos().Iterator().Backward(1);
96 
97     if (PeekSymbol() == lexer::LEX_CHAR_LF) {
98         line_--;
99     }
100 }
101 
NextSymbol(std::size_t i)102 void ETSNolintParser::NextSymbol(std::size_t i)
103 {
104     for (; i > 0; --i) {
105         NextSymbol();
106     }
107 }
108 
BackwardSymbol(std::size_t i)109 void ETSNolintParser::BackwardSymbol(std::size_t i)
110 {
111     for (; i > 0; --i) {
112         BackwardSymbol();
113     }
114 }
115 
RewindToStart() const116 void ETSNolintParser::RewindToStart() const
117 {
118     parser_->Lexer()->Pos().Iterator().Backward(posOffset_ - startPos_);
119 }
120 
AddToETSNolintLinesCollection(std::size_t line,const std::set<ETSWarnings> & collection)121 void ETSNolintParser::AddToETSNolintLinesCollection(std::size_t line, const std::set<ETSWarnings> &collection)
122 {
123     const auto search = linesCollection_.find(line);
124     if (search != linesCollection_.end()) {
125         search->second.insert(collection.begin(), collection.end());
126         return;
127     }
128 
129     linesCollection_.insert({line, collection});
130 }
131 
PeekSymbol() const132 char32_t ETSNolintParser::PeekSymbol() const
133 {
134     return parser_->Lexer()->Pos().Iterator().Peek();
135 }
136 
TryPeekU32String(const std::u32string & u32str)137 bool ETSNolintParser::TryPeekU32String(const std::u32string &u32str)
138 {
139     std::size_t localPosOffset = 0;
140     char32_t cp;
141 
142     for (const char32_t i : u32str) {
143         cp = PeekSymbol();
144         if (i != cp) {
145             BackwardSymbol(localPosOffset);
146             return false;
147         }
148         NextSymbol();
149         localPosOffset++;
150     }
151     return true;
152 }
153 
IsEtsNolint()154 bool ETSNolintParser::IsEtsNolint()
155 {
156     static const std::u32string ETSNOLINT_CHAR32T = {
157         lexer::LEX_CHAR_UPPERCASE_E, lexer::LEX_CHAR_UPPERCASE_T, lexer::LEX_CHAR_UPPERCASE_S,
158         lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_O, lexer::LEX_CHAR_UPPERCASE_L,
159         lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_T};
160 
161     char32_t cp;
162 
163     for (unsigned long i = 0; i < ETSNOLINT_CHAR32T.length(); i++) {
164         cp = PeekSymbol();
165         if (ETSNOLINT_CHAR32T[i] != cp) {
166             return false;
167         }
168 
169         NextSymbol();
170     }
171 
172     return true;
173 }
174 
IsNextLine()175 bool ETSNolintParser::IsNextLine()
176 {
177     static const std::u32string NEXTLINE_CHAR32T = {
178         lexer::LEX_CHAR_MINUS,       lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_E,
179         lexer::LEX_CHAR_UPPERCASE_X, lexer::LEX_CHAR_UPPERCASE_T, lexer::LEX_CHAR_UPPERCASE_L,
180         lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_E};
181 
182     return TryPeekU32String(NEXTLINE_CHAR32T);
183 }
184 
IsBegin()185 bool ETSNolintParser::IsBegin()
186 {
187     static const std::u32string BEGIN_CHAR32T = {lexer::LEX_CHAR_MINUS,       lexer::LEX_CHAR_UPPERCASE_B,
188                                                  lexer::LEX_CHAR_UPPERCASE_E, lexer::LEX_CHAR_UPPERCASE_G,
189                                                  lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N};
190 
191     return TryPeekU32String(BEGIN_CHAR32T);
192 }
193 
IsEnd()194 bool ETSNolintParser::IsEnd()
195 {
196     static const std::u32string END_CHAR32T = {lexer::LEX_CHAR_MINUS, lexer::LEX_CHAR_UPPERCASE_E,
197                                                lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_D};
198 
199     return TryPeekU32String(END_CHAR32T);
200 }
201 
MapETSNolintArg(const std::string & warningName) const202 ETSWarnings ETSNolintParser::MapETSNolintArg(const std::string &warningName) const
203 {
204     return util::gen::ets_warnings::FromString(warningName);
205 }
206 
ValidETSNolintArg(const std::string & warningName) const207 bool ETSNolintParser::ValidETSNolintArg(const std::string &warningName) const
208 {
209     return util::gen::ets_warnings::FromString(warningName) != ETSWarnings::INVALID;
210 }
211 
ParseETSNolintArgs()212 std::set<ETSWarnings> ETSNolintParser::ParseETSNolintArgs()
213 {
214     std::set<ETSWarnings> warningsCollection;
215 
216     if (PeekSymbol() != lexer::LEX_CHAR_LEFT_PAREN) {
217         for (std::underlying_type_t<ETSWarnings> wid = ETSWarnings::FIRST; wid <= ETSWarnings::LAST; wid++) {
218             warningsCollection.insert(ETSWarnings {wid});
219         }
220         return warningsCollection;
221     }
222 
223     NextSymbol();
224     char32_t cp = 0;
225     std::string warningName;
226 
227     while (cp != lexer::LEX_CHAR_SP && cp != lexer::LEX_CHAR_LF && cp != lexer::LEX_CHAR_EOS) {
228         cp = PeekSymbol();
229         const lexer::SourcePosition sPos {line_ + 1, 0, parser_->GetProgram()};
230         if (cp != lexer::LEX_CHAR_MINUS && cp != lexer::LEX_CHAR_COMMA && cp != lexer::LEX_CHAR_RIGHT_PAREN &&
231             (cp < lexer::LEX_CHAR_LOWERCASE_A || cp > lexer::LEX_CHAR_LOWERCASE_Z)) {
232             parser_->DiagnosticEngine().LogDiagnostic(diagnostic::UNEXPECTED_CHAR_ETSNOLINT,
233                                                       util::DiagnosticMessageParams {}, sPos);
234         }
235         if ((cp == lexer::LEX_CHAR_COMMA || cp == lexer::LEX_CHAR_RIGHT_PAREN) && !ValidETSNolintArg(warningName)) {
236             parser_->DiagnosticEngine().LogDiagnostic(diagnostic::INVALID_ARGUMENT_ETSNOLINT,
237                                                       util::DiagnosticMessageParams {}, sPos);
238         }
239         if ((cp == lexer::LEX_CHAR_COMMA || cp == lexer::LEX_CHAR_RIGHT_PAREN) && ValidETSNolintArg(warningName)) {
240             warningsCollection.insert(MapETSNolintArg(warningName));
241             warningName.clear();
242         } else {
243             ES2PANDA_ASSERT(cp <= std::numeric_limits<unsigned char>::max());
244             warningName += cp;
245         }
246         if (cp == lexer::LEX_CHAR_RIGHT_PAREN) {
247             break;
248         }
249 
250         NextSymbol();
251     }
252 
253     return warningsCollection;
254 }
255 
IsLineWithETSNolint(const std::size_t line) const256 bool ETSNolintParser::IsLineWithETSNolint(const std::size_t line) const
257 {
258     return linesCollection_.find(line) != linesCollection_.end();
259 }
260 
GetWarningsCollectionByLine(std::size_t line) const261 std::set<ETSWarnings> ETSNolintParser::GetWarningsCollectionByLine(std::size_t line) const
262 {
263     const auto search = linesCollection_.find(line);
264     return search == linesCollection_.end() ? std::set<ETSWarnings> {} : search->second;
265 }
266 
ApplyETSNolintsToNodesRecursively(ir::AstNode * node) const267 void ETSNolintParser::ApplyETSNolintsToNodesRecursively(ir::AstNode *node) const
268 {
269     if (node == nullptr) {
270         return;
271     }
272     const std::size_t line = node->Start().line;
273     if (IsLineWithETSNolint(line)) {
274         const std::set<ETSWarnings> warningsCollection = GetWarningsCollectionByLine(line);
275 
276         parser_->GetProgram()->AddNodeToETSNolintCollection(node, warningsCollection);
277     }
278     node->Iterate([&](auto *childNode) { ApplyETSNolintsToNodesRecursively(childNode); });
279 }
280 }  // namespace ark::es2panda::parser
281