• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 "helpers.h"
17 #include <iomanip>
18 
19 #include "checker/ETSchecker.h"
20 
21 #include "parser/program/program.h"
22 #include "varbinder/privateBinding.h"
23 #include "varbinder/ETSBinder.h"
24 #include "lexer/token/letters.h"
25 
26 #include "ir/base/classDefinition.h"
27 #include "ir/base/scriptFunction.h"
28 #include "ir/base/classProperty.h"
29 #include "ir/base/property.h"
30 #include "ir/base/spreadElement.h"
31 #include "ir/base/methodDefinition.h"
32 
33 #include "ir/expressions/identifier.h"
34 #include "ir/expressions/literals/numberLiteral.h"
35 #include "ir/expressions/literals/stringLiteral.h"
36 #include "ir/expressions/literals/booleanLiteral.h"
37 #include "ir/expressions/functionExpression.h"
38 #include "ir/expressions/objectExpression.h"
39 #include "ir/expressions/arrayExpression.h"
40 #include "ir/expressions/assignmentExpression.h"
41 
42 #include "ir/statements/variableDeclarator.h"
43 
44 #include "ir/module/importSpecifier.h"
45 #include "ir/module/importDefaultSpecifier.h"
46 
47 #include "ir/ets/etsImportDeclaration.h"
48 #include "ir/ets/etsParameterExpression.h"
49 
50 #include "ir/ts/tsParameterProperty.h"
51 #include "ir/ts/tsInterfaceDeclaration.h"
52 #include "ir/ts/tsEnumDeclaration.h"
53 
54 #include "libpandabase/utils/utf.h"
55 
56 namespace ark::es2panda::util {
57 // Helpers
58 
IsGlobalIdentifier(const util::StringView & str)59 bool Helpers::IsGlobalIdentifier(const util::StringView &str)
60 {
61     return (str.Is("NaN") || str.Is("undefined") || str.Is("Infinity"));
62 }
63 
ContainSpreadElement(const ArenaVector<ir::Expression * > & args)64 bool Helpers::ContainSpreadElement(const ArenaVector<ir::Expression *> &args)
65 {
66     return std::any_of(args.begin(), args.end(), [](const auto *it) { return it->IsSpreadElement(); });
67 }
68 
LiteralToPropName(const ir::Expression * lit)69 util::StringView Helpers::LiteralToPropName(const ir::Expression *lit)
70 {
71     switch (lit->Type()) {
72         case ir::AstNodeType::IDENTIFIER: {
73             return lit->AsIdentifier()->Name();
74         }
75         case ir::AstNodeType::STRING_LITERAL: {
76             return lit->AsStringLiteral()->Str();
77         }
78         case ir::AstNodeType::NUMBER_LITERAL: {
79             return lit->AsNumberLiteral()->Str();
80         }
81         case ir::AstNodeType::NULL_LITERAL: {
82             return "null";
83         }
84         case ir::AstNodeType::UNDEFINED_LITERAL: {
85             return "undefined";
86         }
87         default: {
88             ES2PANDA_UNREACHABLE();
89         }
90     }
91 }
92 
IsIndex(double number)93 bool Helpers::IsIndex(double number)
94 {
95     if (number >= 0 && number < static_cast<double>(INVALID_INDEX)) {
96         auto intNum = static_cast<uint32_t>(number);
97 
98         if (static_cast<double>(intNum) == number) {
99             return true;
100         }
101     }
102 
103     return false;
104 }
105 
IsDigit(char c)106 static bool IsDigit(char c)
107 {
108     return (c >= '0' && c <= '9');
109 }
110 
GetIndex(const util::StringView & str)111 int64_t Helpers::GetIndex(const util::StringView &str)
112 {
113     const auto &s = str.Utf8();
114 
115     if (s.empty() || (*s.begin() == '0' && s.length() > 1)) {
116         return INVALID_INDEX;
117     }
118 
119     int64_t value = 0;
120     for (const auto c : s) {
121         if (!IsDigit(c)) {
122             return INVALID_INDEX;
123         }
124 
125         constexpr auto MULTIPLIER = 10;
126         value *= MULTIPLIER;
127         value += (c - '0');
128 
129         if (value >= INVALID_INDEX) {
130             return INVALID_INDEX;
131         }
132     }
133 
134     return value;
135 }
136 
ToString(double number)137 std::string Helpers::ToString(double number)
138 {
139     std::string str;
140 
141     if (Helpers::IsInteger<int32_t>(number)) {
142         str = std::to_string(static_cast<int32_t>(number));
143     } else {
144         str = std::to_string(number);
145     }
146 
147     return str;
148 }
149 
ToStringView(ArenaAllocator * allocator,double number)150 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, double number)
151 {
152     util::UString str(ToString(number), allocator);
153     return str.View();
154 }
155 
ToStringView(ArenaAllocator * allocator,uint32_t number)156 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, uint32_t number)
157 {
158     ES2PANDA_ASSERT(number <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
159     return ToStringView(allocator, static_cast<int32_t>(number));
160 }
161 
ToStringView(ArenaAllocator * allocator,int32_t number)162 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, int32_t number)
163 {
164     util::UString str(ToString(number), allocator);
165     return str.View();
166 }
167 
EndsWith(const std::string & str,const std::string & suffix)168 bool Helpers::EndsWith(const std::string &str, const std::string &suffix)
169 {
170     if (str.length() < suffix.length()) {
171         return false;
172     }
173     size_t expectPos = str.length() - suffix.length();
174     return str.find(suffix, expectPos) == expectPos;
175 }
176 
GetContainingConstructor(const ir::AstNode * node)177 const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::AstNode *node)
178 {
179     const ir::ScriptFunction *iter = GetContainingFunction(node);
180 
181     while (iter != nullptr) {
182         if (iter->IsConstructor()) {
183             return iter;
184         }
185 
186         if (!iter->IsArrow()) {
187             return nullptr;
188         }
189 
190         iter = GetContainingFunction(iter);
191     }
192 
193     return iter;
194 }
195 
GetContainingEnumDeclaration(const ir::AstNode * node)196 const ir::TSEnumDeclaration *Helpers::GetContainingEnumDeclaration(const ir::AstNode *node)
197 {
198     auto *iter = node;
199 
200     while (iter != nullptr) {
201         if (iter->IsTSEnumDeclaration()) {
202             return iter->AsTSEnumDeclaration();
203         }
204 
205         iter = iter->Parent();
206     }
207 
208     return nullptr;
209 }
210 
GetContainingObjectType(const ir::AstNode * node)211 const checker::ETSObjectType *Helpers::GetContainingObjectType(const ir::AstNode *node)
212 {
213     const auto *iter = node;
214 
215     while (iter != nullptr) {
216         if (iter->IsClassDefinition()) {
217             auto *ret = iter->AsClassDefinition()->TsType();
218             return ret != nullptr ? ret->AsETSObjectType() : nullptr;
219         }
220 
221         if (iter->IsTSInterfaceDeclaration()) {
222             auto *ret = iter->AsTSInterfaceDeclaration()->TsType();
223             return ret != nullptr ? ret->AsETSObjectType() : nullptr;
224         }
225 
226         if (iter->IsTSEnumDeclaration()) {
227             auto *ret = iter->AsTSEnumDeclaration()->TsType();
228             return ret != nullptr ? ret->AsETSObjectType() : nullptr;
229         }
230 
231         iter = iter->Parent();
232     }
233 
234     return nullptr;
235 }
236 
GetContainingClassDefinition(const ir::AstNode * node)237 const ir::ClassDefinition *Helpers::GetContainingClassDefinition(const ir::AstNode *node)
238 {
239     const auto *iter = node;
240 
241     while (iter != nullptr) {
242         if (iter->IsClassDefinition()) {
243             return iter->AsClassDefinition();
244         }
245 
246         iter = iter->Parent();
247     }
248 
249     return nullptr;
250 }
251 
GetContainingInterfaceDeclaration(const ir::AstNode * node)252 const ir::TSInterfaceDeclaration *Helpers::GetContainingInterfaceDeclaration(const ir::AstNode *node)
253 {
254     const auto *iter = node;
255 
256     while (iter != nullptr) {
257         if (iter->IsTSInterfaceDeclaration()) {
258             return iter->AsTSInterfaceDeclaration();
259         }
260 
261         iter = iter->Parent();
262     }
263 
264     return nullptr;
265 }
266 
GetContainingClassMethodDefinition(const ir::AstNode * node)267 const ir::MethodDefinition *Helpers::GetContainingClassMethodDefinition(const ir::AstNode *node)
268 {
269     const auto *iter = node;
270 
271     while (iter != nullptr) {
272         if (iter->IsMethodDefinition()) {
273             return iter->AsMethodDefinition();
274         }
275 
276         if (iter->IsClassDefinition()) {
277             break;
278         }
279 
280         iter = iter->Parent();
281     }
282 
283     return nullptr;
284 }
285 
GetContainingClassStaticBlock(const ir::AstNode * node)286 const ir::ClassStaticBlock *Helpers::GetContainingClassStaticBlock(const ir::AstNode *node)
287 {
288     const auto *iter = node;
289 
290     while (iter != nullptr) {
291         if (iter->IsClassStaticBlock()) {
292             return iter->AsClassStaticBlock();
293         }
294 
295         if (iter->IsClassDefinition()) {
296             break;
297         }
298 
299         iter = iter->Parent();
300     }
301 
302     return nullptr;
303 }
304 
GetContainingConstructor(const ir::ClassProperty * node)305 const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::ClassProperty *node)
306 {
307     for (const auto *parent = node->Parent(); parent != nullptr; parent = parent->Parent()) {
308         if (parent->IsClassDefinition()) {
309             ES2PANDA_ASSERT(parent->AsClassDefinition()->Ctor() != nullptr);
310             return parent->AsClassDefinition()->Ctor()->Function();
311         }
312     }
313 
314     return nullptr;
315 }
316 
GetContainingFunction(const ir::AstNode * node)317 const ir::ScriptFunction *Helpers::GetContainingFunction(const ir::AstNode *node)
318 {
319     for (const auto *parent = node->Parent(); parent != nullptr; parent = parent->Parent()) {
320         if (parent->IsScriptFunction()) {
321             return parent->AsScriptFunction();
322         }
323     }
324 
325     return nullptr;
326 }
327 
GetClassDefiniton(const ir::ScriptFunction * node)328 const ir::ClassDefinition *Helpers::GetClassDefiniton(const ir::ScriptFunction *node)
329 {
330     ES2PANDA_ASSERT(node->IsConstructor());
331     ES2PANDA_ASSERT(node->Parent()->IsFunctionExpression());
332     ES2PANDA_ASSERT(node->Parent()->Parent()->IsMethodDefinition());
333     ES2PANDA_ASSERT(node->Parent()->Parent()->Parent()->IsClassDefinition());
334 
335     return node->Parent()->Parent()->Parent()->AsClassDefinition();
336 }
337 
IsSpecialPropertyKey(const ir::Expression * expr)338 bool Helpers::IsSpecialPropertyKey(const ir::Expression *expr)
339 {
340     if (!expr->IsStringLiteral()) {
341         return false;
342     }
343 
344     auto *lit = expr->AsStringLiteral();
345     return lit->Str().Is("prototype") || lit->Str().Is("constructor");
346 }
347 
IsConstantPropertyKey(const ir::Expression * expr,bool isComputed)348 bool Helpers::IsConstantPropertyKey(const ir::Expression *expr, bool isComputed)
349 {
350     switch (expr->Type()) {
351         case ir::AstNodeType::IDENTIFIER: {
352             return !isComputed;
353         }
354         case ir::AstNodeType::NUMBER_LITERAL:
355         case ir::AstNodeType::STRING_LITERAL:
356         case ir::AstNodeType::BOOLEAN_LITERAL:
357         case ir::AstNodeType::NULL_LITERAL: {
358             return true;
359         }
360         default:
361             break;
362     }
363 
364     return false;
365 }
366 
ToConstantLiteral(const ir::Expression * expr)367 compiler::Literal Helpers::ToConstantLiteral(const ir::Expression *expr)
368 {
369     switch (expr->Type()) {
370         case ir::AstNodeType::NUMBER_LITERAL: {
371             auto *lit = expr->AsNumberLiteral();
372             if (util::Helpers::IsInteger<uint32_t>(lit->Number().GetDouble())) {
373                 return compiler::Literal(static_cast<uint32_t>(lit->Number().GetDouble()));
374             }
375             return compiler::Literal(lit->Number().GetDouble());
376         }
377         case ir::AstNodeType::STRING_LITERAL: {
378             auto *lit = expr->AsStringLiteral();
379             return compiler::Literal(lit->Str());
380         }
381         case ir::AstNodeType::BOOLEAN_LITERAL: {
382             auto *lit = expr->AsBooleanLiteral();
383             return compiler::Literal(lit->Value());
384         }
385         case ir::AstNodeType::NULL_LITERAL: {
386             return compiler::Literal::NullLiteral();
387         }
388         case ir::AstNodeType::UNDEFINED_LITERAL: {
389             return compiler::Literal::UndefinedLiteral();
390         }
391         default:
392             break;
393     }
394 
395     return compiler::Literal();
396 }
397 
IsBindingPattern(const ir::AstNode * node)398 bool Helpers::IsBindingPattern(const ir::AstNode *node)
399 {
400     return node->IsArrayPattern() || node->IsObjectPattern();
401 }
402 
IsPattern(const ir::AstNode * node)403 bool Helpers::IsPattern(const ir::AstNode *node)
404 {
405     return node->IsArrayPattern() || node->IsObjectPattern() || node->IsAssignmentPattern();
406 }
407 
CollectBindingName(varbinder::VarBinder * vb,ir::AstNode * node,std::vector<ir::Identifier * > * bindings)408 static void CollectBindingName(varbinder::VarBinder *vb, ir::AstNode *node, std::vector<ir::Identifier *> *bindings)
409 {
410     switch (node->Type()) {
411         case ir::AstNodeType::IDENTIFIER: {
412             if (!vb->IsGlobalIdentifier(node->AsIdentifier()->Name())) {
413                 bindings->push_back(node->AsIdentifier());
414             }
415 
416             break;
417         }
418         case ir::AstNodeType::OBJECT_PATTERN: {
419             for (auto *prop : node->AsObjectPattern()->Properties()) {
420                 CollectBindingName(vb, prop, bindings);
421             }
422             break;
423         }
424         case ir::AstNodeType::ARRAY_PATTERN: {
425             for (auto *element : node->AsArrayPattern()->Elements()) {
426                 CollectBindingName(vb, element, bindings);
427             }
428             break;
429         }
430         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
431             CollectBindingName(vb, node->AsAssignmentPattern()->Left(), bindings);
432             break;
433         }
434         case ir::AstNodeType::PROPERTY: {
435             CollectBindingName(vb, node->AsProperty()->Value(), bindings);
436             break;
437         }
438         case ir::AstNodeType::REST_ELEMENT: {
439             CollectBindingName(vb, node->AsRestElement()->Argument(), bindings);
440             break;
441         }
442         default:
443             break;
444     }
445 }
446 
CollectBindingNames(varbinder::VarBinder * vb,ir::Expression * node)447 std::vector<ir::Identifier *> Helpers::CollectBindingNames(varbinder::VarBinder *vb, ir::Expression *node)
448 {
449     std::vector<ir::Identifier *> bindings;
450     CollectBindingName(vb, node, &bindings);
451     return bindings;
452 }
453 
CheckImportedName(const ArenaVector<ir::ImportSpecifier * > & specifiers,const ir::ImportSpecifier * specifier,const std::string & fileName)454 void Helpers::CheckImportedName(const ArenaVector<ir::ImportSpecifier *> &specifiers,
455                                 const ir::ImportSpecifier *specifier, const std::string &fileName)
456 {
457     auto newIdentName = specifier->Imported()->Name();
458     auto newAliasName = specifier->Local()->Name();
459     std::stringstream message {};
460 
461     for (auto *it : specifiers) {
462         auto savedIdentName = it->Imported()->Name();
463         auto savedAliasName = it->Local()->Name();
464         if (savedIdentName == savedAliasName && savedAliasName == newIdentName) {
465             message << "Warning: '" << newIdentName << "' has already imported ";
466             break;
467         }
468         if (savedIdentName == newIdentName && newAliasName != savedAliasName) {
469             message << "Warning: '" << newIdentName << "' is explicitly used with alias several times ";
470             break;
471         }
472     }
473 
474     if (message.rdbuf()->in_avail() > 0) {
475         std::cerr << message.str() << "[" << fileName.c_str() << ":" << specifier->Start().line << ":"
476                   << specifier->Start().index << "]" << std::endl;
477     }
478 }
479 
CheckDefaultImportedName(const ArenaVector<ir::ImportDefaultSpecifier * > & specifiers,const ir::ImportDefaultSpecifier * specifier,const std::string & fileName)480 void Helpers::CheckDefaultImportedName(const ArenaVector<ir::ImportDefaultSpecifier *> &specifiers,
481                                        const ir::ImportDefaultSpecifier *specifier, const std::string &fileName)
482 {
483     for (auto *it : specifiers) {
484         if (specifier->Local()->Name() != it->Local()->Name()) {
485             std::cerr << "Warning: default element is explicitly used with alias several times [" << fileName.c_str()
486                       << ":" << specifier->Start().line << ":" << specifier->Start().index << "]" << std::endl;
487             return;
488         }
489     }
490 }
491 
CheckDefaultImport(const ArenaVector<ir::ETSImportDeclaration * > & statements)492 void Helpers::CheckDefaultImport(const ArenaVector<ir::ETSImportDeclaration *> &statements)
493 {
494     for (auto statement : statements) {
495         for (auto specifier : statement->Specifiers()) {
496             if (specifier->Type() == ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER) {
497                 auto fileName = statement->ResolvedSource();
498                 std::cerr << "Warning: default element has already imported [" << fileName << ":"
499                           << specifier->Start().line << ":" << specifier->Start().index << "]" << std::endl;
500                 return;
501             }
502         }
503     }
504 }
505 
FunctionNameFromParent(const ir::AstNode * parent,ArenaAllocator * allocator)506 static util::StringView FunctionNameFromParent(const ir::AstNode *parent, ArenaAllocator *allocator)
507 {
508     switch (parent->Type()) {
509         case ir::AstNodeType::VARIABLE_DECLARATOR: {
510             const ir::VariableDeclarator *varDecl = parent->AsVariableDeclarator();
511 
512             if (varDecl->Id()->IsIdentifier()) {
513                 return varDecl->Id()->AsIdentifier()->Name();
514             }
515 
516             break;
517         }
518         case ir::AstNodeType::METHOD_DEFINITION: {
519             const ir::MethodDefinition *methodDef = parent->AsMethodDefinition();
520 
521             if (methodDef->Key()->IsIdentifier()) {
522                 auto *ident = methodDef->Id();
523                 ES2PANDA_ASSERT(ident != nullptr);
524 
525                 if (!ident->IsPrivateIdent()) {
526                     return ident->Name();
527                 }
528 
529                 return util::UString(varbinder::PrivateBinding::ToPrivateBinding(ident->Name()), allocator).View();
530             }
531 
532             break;
533         }
534         case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
535             const ir::AssignmentExpression *assignment = parent->AsAssignmentExpression();
536 
537             if (assignment->Left()->IsIdentifier()) {
538                 return assignment->Left()->AsIdentifier()->Name();
539             }
540 
541             break;
542         }
543         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
544             const ir::AssignmentExpression *assignment = parent->AsAssignmentPattern();
545 
546             if (assignment->Left()->IsIdentifier()) {
547                 return assignment->Left()->AsIdentifier()->Name();
548             }
549 
550             break;
551         }
552         case ir::AstNodeType::PROPERTY: {
553             const ir::Property *prop = parent->AsProperty();
554 
555             if (prop->Kind() != ir::PropertyKind::PROTO &&
556                 Helpers::IsConstantPropertyKey(prop->Key(), prop->IsComputed())) {
557                 return Helpers::LiteralToPropName(prop->Key());
558             }
559 
560             break;
561         }
562         default:
563             break;
564     }
565 
566     return util::StringView();
567 }
568 
FunctionName(ArenaAllocator * allocator,const ir::ScriptFunction * func)569 util::StringView Helpers::FunctionName(ArenaAllocator *allocator, const ir::ScriptFunction *func)
570 {
571     if (func->Id() != nullptr) {
572         return func->Id()->Name();
573     }
574 
575     if (func->Parent()->IsFunctionDeclaration()) {
576         return "*default*";
577     }
578 
579     const ir::AstNode *parent = func->Parent()->Parent();
580 
581     if (func->IsConstructor()) {
582         parent = parent->Parent();
583         if (parent->AsClassDefinition()->Ident() != nullptr) {
584             return parent->AsClassDefinition()->Ident()->Name();
585         }
586 
587         parent = parent->Parent()->Parent();
588     }
589 
590     return FunctionNameFromParent(parent, allocator);
591 }
592 
ParamName(ArenaAllocator * allocator,const ir::Expression * param,std::uint32_t index)593 std::tuple<util::StringView, bool> Helpers::ParamName(ArenaAllocator *allocator, const ir::Expression *param,
594                                                       std::uint32_t index)
595 {
596     switch (param->Type()) {
597         case ir::AstNodeType::IDENTIFIER: {
598             return {param->AsIdentifier()->Name(), false};
599         }
600         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
601             const auto *lhs = param->AsAssignmentPattern()->Left();
602             if (lhs->IsIdentifier()) {
603                 return {param->AsAssignmentPattern()->Left()->AsIdentifier()->Name(), false};
604             }
605             break;
606         }
607         case ir::AstNodeType::REST_ELEMENT: {
608             if (param->AsRestElement()->Argument()->IsIdentifier()) {
609                 return {param->AsRestElement()->Argument()->AsIdentifier()->Name(), false};
610             }
611             break;
612         }
613         case ir::AstNodeType::TS_PARAMETER_PROPERTY: {
614             return ParamName(allocator, param->AsTSParameterProperty()->Parameter(), index);
615         }
616         case ir::AstNodeType::ETS_PARAMETER_EXPRESSION: {
617             return {param->AsETSParameterExpression()->Name(), false};
618         }
619         default:
620             break;
621     }
622 
623     return {Helpers::ToStringView(allocator, index), true};
624 }
625 
GetEscapedCharacter(const unsigned char c)626 static std::string GetEscapedCharacter(const unsigned char c)
627 {
628     std::stringstream escapedStr;
629     escapedStr << '\\';
630     switch (c) {
631         case lexer::LEX_CHAR_DOUBLE_QUOTE: {
632             escapedStr << '"';
633             break;
634         }
635         case lexer::LEX_CHAR_BS: {
636             escapedStr << 'b';
637             break;
638         }
639         case lexer::LEX_CHAR_TAB: {
640             escapedStr << 't';
641             break;
642         }
643         case lexer::LEX_CHAR_LF: {
644             escapedStr << 'n';
645             break;
646         }
647         case lexer::LEX_CHAR_VT: {
648             escapedStr << 'v';
649             break;
650         }
651         case lexer::LEX_CHAR_FF: {
652             escapedStr << 'f';
653             break;
654         }
655         case lexer::LEX_CHAR_CR: {
656             escapedStr << 'r';
657             break;
658         }
659         case lexer::LEX_CHAR_NULL: {
660             escapedStr << '0';
661             break;
662         }
663         default: {
664             escapedStr << 'u' << std::hex << std::setw(4U) << std::setfill('0') << static_cast<unsigned int>(c);
665             break;
666         }
667     }
668     return escapedStr.str();
669 }
670 
CreateEscapedString(const std::string & str)671 std::string Helpers::CreateEscapedString(const std::string &str)
672 {
673     std::string escapedStr;
674     for (const unsigned char c : str) {
675         // check if a given character is printable
676         // the cast is necessary to avoid undefined behaviour
677         if (LIKELY((std::isprint(c) != 0U || c >= lexer::LEX_ASCII_MAX_BITS) && c != lexer::LEX_CHAR_DOUBLE_QUOTE)) {
678             escapedStr += c;
679         } else {
680             escapedStr += GetEscapedCharacter(c);
681         }
682     }
683     return escapedStr;
684 }
685 
UTF16toUTF8(const char16_t c)686 std::string Helpers::UTF16toUTF8(const char16_t c)
687 {
688     const utf::Utf8Char utf8Ch = utf::ConvertUtf16ToUtf8(c, 0, false);
689     return std::string(reinterpret_cast<const char *>(utf8Ch.ch.data()), utf8Ch.n);
690 }
691 
SplitSignature(std::string_view signature)692 std::pair<std::string_view, std::string_view> Helpers::SplitSignature(std::string_view signature)
693 {
694     auto idx = signature.find_last_of(':');
695     auto stripped = signature.substr(0, idx);
696     idx = stripped.find_last_of('.');
697     auto fullClassName = stripped.substr(0, idx);
698     auto methodName = stripped.substr(idx + 1);
699     idx = fullClassName.find_last_of('.');
700     auto className = fullClassName.substr(idx + 1);
701     return {className, methodName};
702 }
703 
StdLib()704 std::vector<std::string> const &Helpers::StdLib()
705 {
706     static std::vector<std::string> stdlib {"std/core", "std/math",        "std/containers",        "std/interop/js",
707                                             "std/time", "std/debug",       "std/debug/concurrency", "std/testing",
708                                             "escompat", "std/concurrency", "std/annotations",       "std/interop"};
709     return stdlib;
710 }
711 
IsStdLib(const parser::Program * program)712 bool Helpers::IsStdLib(const parser::Program *program)
713 {
714     // NOTE(rsipka): early check: if program is not in a package then it is not part of the stdlib either
715     if (!program->IsPackage()) {
716         return false;
717     }
718 
719     auto fileFolder = program->ModuleName().Mutf8();
720     std::replace(fileFolder.begin(), fileFolder.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(),
721                  *compiler::Signatures::NAMESPACE_SEPARATOR.begin());
722 
723     if (fileFolder == "std/math/consts") {
724         return true;
725     }
726 
727     auto const &stdlib = StdLib();
728     return std::count(stdlib.begin(), stdlib.end(), fileFolder) != 0;
729 }
730 
CheckReturnTypeOfCheck(const ir::AstNode * const node,checker::Type * const type)731 checker::Type *Helpers::CheckReturnTypeOfCheck([[maybe_unused]] const ir::AstNode *const node,
732                                                checker::Type *const type)
733 {
734     ES2PANDA_ASSERT(type != nullptr || !node->IsExpression());
735     return type;
736 }
737 
EscapeHTMLString(ArenaAllocator * allocator,const std::string & str)738 util::UString Helpers::EscapeHTMLString(ArenaAllocator *allocator, const std::string &str)
739 {
740     util::UString replaced(allocator);
741     for (const auto c : str) {
742         switch (c) {
743             case '<':
744                 replaced.Append("&lt;");
745                 break;
746             case '>':
747                 replaced.Append("&gt;");
748                 break;
749             case '&':
750                 replaced.Append("&amp;");
751                 break;
752             case '"':
753                 replaced.Append("&quot;");
754                 break;
755             case '\'':
756                 replaced.Append("&apos;");
757                 break;
758             default:
759                 replaced.Append(c);
760                 break;
761         }
762     }
763     return replaced;
764 }
765 
DerefETSTypeReference(ir::AstNode * node)766 ir::AstNode *Helpers::DerefETSTypeReference(ir::AstNode *node)
767 {
768     ES2PANDA_ASSERT(node->IsETSTypeReference());
769     do {
770         auto *name = node->AsETSTypeReference()->Part()->GetIdent();
771 
772         ES2PANDA_ASSERT(name->IsIdentifier());
773         if (varbinder::ETSBinder::IsSpecialName(name->Name())) {
774             return node;
775         }
776         auto *var = name->AsIdentifier()->Variable();
777         ES2PANDA_ASSERT(var != nullptr);
778         auto *declNode = var->Declaration()->Node();
779         if (!declNode->IsTSTypeAliasDeclaration()) {
780             return declNode;
781         }
782         node = declNode->AsTSTypeAliasDeclaration()->TypeAnnotation();
783     } while (node->IsETSTypeReference());
784     return node;
785 }
786 
IsAsyncMethod(ir::AstNode const * node)787 bool Helpers::IsAsyncMethod(ir::AstNode const *node)
788 {
789     if (!node->IsMethodDefinition()) {
790         return false;
791     }
792     auto *method = node->AsMethodDefinition();
793     ES2PANDA_ASSERT(method->Function() != nullptr);
794     return method->Function()->IsAsyncFunc() && !method->Function()->IsProxy();
795 }
796 
IsGlobalVar(const ark::es2panda::varbinder::Variable * var)797 bool Helpers::IsGlobalVar(const ark::es2panda::varbinder::Variable *var)
798 {
799     return var->Declaration()->Node()->IsClassDeclaration() &&
800            var->Declaration()->Node()->AsClassDeclaration()->Definition()->IsGlobal();
801 }
802 
803 }  // namespace ark::es2panda::util
804