1 /*
2 * Copyright (c) 2022 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 "typeExtractor.h"
17
18 #include <binder/binder.h>
19 #include <ir/base/spreadElement.h>
20 #include <ir/expressions/classExpression.h>
21 #include <ir/expressions/memberExpression.h>
22 #include <ir/expressions/newExpression.h>
23 #include <ir/statements/variableDeclaration.h>
24 #include <ir/statements/variableDeclarator.h>
25 #include <ir/ts/tsClassImplements.h>
26 #include <ir/ts/tsParenthesizedType.h>
27 #include <ir/ts/tsQualifiedName.h>
28 #include <ir/ts/tsTypeAliasDeclaration.h>
29 #include <ir/ts/tsTypeParameterInstantiation.h>
30 #include <ir/ts/tsTypeReference.h>
31 #include <parser/module/sourceTextModuleRecord.h>
32
33 #include "typeSystem.h"
34
35 namespace panda::es2panda::extractor {
36
37 #ifndef NDEBUG
38 #define TLOG(type, res) \
39 do { \
40 std::cout << "[LOG]" << __func__ << ": " << static_cast<int64_t>(type) << " | " << (res) << std::endl; \
41 } while (0)
42 #else
43 #define TLOG(type, res) static_cast<void>(0)
44 #endif
45
46 const std::set<ir::AstNodeType> PRUNING_SET = {
47 ir::AstNodeType::IDENTIFIER,
48 ir::AstNodeType::TS_INTERFACE_DECLARATION,
49 ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION,
50 ir::AstNodeType::IMPORT_DECLARATION,
51 ir::AstNodeType::EXPORT_ALL_DECLARATION
52 };
53
TypeExtractor(const ir::BlockStatement * rootNode,bool typeDtsExtractor,bool typeDtsBuiltin,ArenaAllocator * allocator,compiler::CompilerContext * context)54 TypeExtractor::TypeExtractor(const ir::BlockStatement *rootNode, bool typeDtsExtractor, bool typeDtsBuiltin,
55 ArenaAllocator *allocator, compiler::CompilerContext *context)
56 : rootNode_(rootNode), typeDtsExtractor_(typeDtsExtractor), typeDtsBuiltin_(typeDtsBuiltin)
57 {
58 recorder_ = std::make_unique<TypeRecorder>(allocator, context);
59
60 getterMap_[ir::AstNodeType::IDENTIFIER] =
61 std::bind(&TypeExtractor::GetTypeIndexFromIdentifierNode, this, std::placeholders::_1, std::placeholders::_2);
62 getterMap_[ir::AstNodeType::CLASS_EXPRESSION] =
63 std::bind(&TypeExtractor::GetTypeIndexFromClassExpression, this, std::placeholders::_1, std::placeholders::_2);
64 getterMap_[ir::AstNodeType::CLASS_DEFINITION] =
65 std::bind(&TypeExtractor::GetTypeIndexFromClassDefinition, this, std::placeholders::_1, std::placeholders::_2);
66 getterMap_[ir::AstNodeType::TS_INTERFACE_DECLARATION] =
67 std::bind(&TypeExtractor::GetTypeIndexFromInterfaceNode, this, std::placeholders::_1, std::placeholders::_2);
68 getterMap_[ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER] =
69 std::bind(&TypeExtractor::GetTypeIndexFromImportNode, this, std::placeholders::_1, std::placeholders::_2);
70 getterMap_[ir::AstNodeType::IMPORT_SPECIFIER] =
71 std::bind(&TypeExtractor::GetTypeIndexFromImportNode, this, std::placeholders::_1, std::placeholders::_2);
72 getterMap_[ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER] =
73 std::bind(&TypeExtractor::GetTypeIndexFromImportNode, this, std::placeholders::_1, std::placeholders::_2);
74 getterMap_[ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION] =
75 std::bind(&TypeExtractor::GetTypeIndexFromTypeAliasNode, this, std::placeholders::_1, std::placeholders::_2);
76 getterMap_[ir::AstNodeType::MEMBER_EXPRESSION] =
77 std::bind(&TypeExtractor::GetTypeIndexFromMemberNode, this, std::placeholders::_1, std::placeholders::_2);
78
79 handlerMap_[ir::AstNodeType::VARIABLE_DECLARATION] =
80 std::bind(&TypeExtractor::HandleVariableDeclaration, this, std::placeholders::_1);
81 handlerMap_[ir::AstNodeType::FUNCTION_DECLARATION] =
82 std::bind(&TypeExtractor::HandleFunctionDeclaration, this, std::placeholders::_1);
83 handlerMap_[ir::AstNodeType::CLASS_DECLARATION] =
84 std::bind(&TypeExtractor::HandleClassDeclaration, this, std::placeholders::_1);
85 handlerMap_[ir::AstNodeType::TS_INTERFACE_DECLARATION] =
86 std::bind(&TypeExtractor::HandleInterfaceDeclaration, this, std::placeholders::_1);
87 handlerMap_[ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION] =
88 std::bind(&TypeExtractor::HandleTypeAliasDeclaration, this, std::placeholders::_1);
89 }
90
StartTypeExtractor(const parser::Program * program)91 void TypeExtractor::StartTypeExtractor(const parser::Program *program)
92 {
93 ASSERT(rootNode_->IsProgram());
94
95 TypeCounter counter(this);
96
97 ExtractImport(program);
98 ExtractNodesType(rootNode_);
99 ExtractExport(program);
100
101 recorder_->Dump(program);
102 recorder_->SetTypeSummaryIndex(counter.GetTypeIndexPlaceHolder());
103 counter.FillLiteralBuffer();
104 }
105
GetTypeDtsExtractor() const106 bool TypeExtractor::GetTypeDtsExtractor() const
107 {
108 return typeDtsExtractor_;
109 }
110
GetTypeDtsBuiltin() const111 bool TypeExtractor::GetTypeDtsBuiltin() const
112 {
113 return typeDtsBuiltin_;
114 }
115
Recorder() const116 TypeRecorder *TypeExtractor::Recorder() const
117 {
118 return recorder_.get();
119 }
120
ExtractNodesType(const ir::AstNode * parent)121 void TypeExtractor::ExtractNodesType(const ir::AstNode *parent)
122 {
123 parent->Iterate([this, parent](const auto *childNode) {
124 ExtractNodeType(parent, childNode);
125 });
126 }
127
ExtractNodeType(const ir::AstNode * parent,const ir::AstNode * childNode)128 void TypeExtractor::ExtractNodeType(const ir::AstNode *parent, const ir::AstNode *childNode)
129 {
130 auto iter = handlerMap_.find(childNode->Type());
131 if (iter != handlerMap_.end()) {
132 iter->second(childNode);
133 }
134
135 // Traversal pruning
136 if (PRUNING_SET.find(childNode->Type()) != PRUNING_SET.end()) {
137 return;
138 }
139
140 ExtractNodesType(childNode);
141 }
142
ExtractImport(const parser::Program * program)143 void TypeExtractor::ExtractImport(const parser::Program *program)
144 {
145 auto moduleRecord = program->Binder()->Program()->ModuleRecord();
146 if (moduleRecord == nullptr) {
147 return;
148 }
149
150 const auto ®ularImportEntries = moduleRecord->GetRegularImportEntries();
151 for (const auto &t : regularImportEntries) {
152 const auto &redirectPath = moduleRecord->GetModuleRequestIdxMap().at(t.second->moduleRequestIdx_);
153 ExternalType externalType(this, t.first, redirectPath);
154 recorder_->SetNodeTypeIndex(t.second->localId_->Parent(), externalType.GetTypeIndexShift());
155 }
156
157 const auto &namespaceImportEntries = moduleRecord->GetNamespaceImportEntries();
158 for (const auto &t : namespaceImportEntries) {
159 const auto &redirectPath = moduleRecord->GetModuleRequestIdxMap().at(t->moduleRequestIdx_);
160 ExternalType externalType(this, "*", redirectPath);
161 recorder_->SetNamespaceType(std::string(t->localName_), externalType.GetTypeIndexShift());
162 recorder_->SetNamespacePath(std::string(t->localName_), std::string(redirectPath));
163 }
164 }
165
ExtractExport(const parser::Program * program)166 void TypeExtractor::ExtractExport(const parser::Program *program)
167 {
168 auto moduleRecord = program->Binder()->Program()->ModuleRecord();
169 if (moduleRecord == nullptr) {
170 return;
171 }
172
173 const auto &localExportEntries = moduleRecord->GetLocalExportEntries();
174 for (const auto &t : localExportEntries) {
175 auto identifier = t.second->localId_;
176 if (identifier == nullptr) {
177 if (t.second->exportId_ != nullptr) {
178 // Special case for NamespaceExport transform
179 // Refer to parser/statementParser.cpp `AddExportStarEntryItem`
180 recorder_->SetExportType(std::string(t.second->exportName_),
181 recorder_->GetNamespaceType(std::string(t.second->localName_)));
182 }
183 // Other export extries without local identifier is handled during traversal
184 continue;
185 }
186 auto typeIndex = recorder_->GetVariableTypeIndex(identifier->Variable());
187 if (typeIndex != PrimitiveType::ANY) {
188 recorder_->SetExportType(std::string(t.second->exportName_), typeIndex);
189 continue;
190 }
191 if (identifier->Variable() != nullptr && identifier->Variable()->Declaration() != nullptr) {
192 auto declNode = identifier->Variable()->Declaration()->Node();
193 typeIndex = recorder_->GetNodeTypeIndex(declNode);
194 if (typeIndex == PrimitiveType::ANY && declNode != nullptr) {
195 typeIndex = GetTypeIndexFromDeclNode(declNode, true);
196 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
197 }
198 if (typeIndex != PrimitiveType::ANY) {
199 recorder_->SetExportType(std::string(t.second->exportName_), typeIndex);
200 }
201 }
202 }
203
204 const auto &starExportEntries = moduleRecord->GetStarExportEntries();
205 for (const auto &t : starExportEntries) {
206 recorder_->AddAnonymousReExport(moduleRecord->GetModuleRequestIdxMap().at(t->moduleRequestIdx_));
207 }
208
209 const auto &indirectExportEntries = moduleRecord->GetIndirectExportEntries();
210 for (const auto &t : indirectExportEntries) {
211 const auto &redirectPath = moduleRecord->GetModuleRequestIdxMap().at(t->moduleRequestIdx_);
212 ExternalType externalType(this, t->importName_, redirectPath);
213 recorder_->SetExportType(std::string(t->exportName_), externalType.GetTypeIndexShift());
214 }
215 }
216
GetIdentifierFromExpression(const ir::Expression * expression)217 const ir::Identifier *TypeExtractor::GetIdentifierFromExpression(const ir::Expression *expression)
218 {
219 switch (expression->Type()) {
220 case ir::AstNodeType::IDENTIFIER:
221 return expression->AsIdentifier();
222 case ir::AstNodeType::TS_QUALIFIED_NAME: // : A.B
223 // TODO(extractor): consider property type suppport
224 return expression->AsTSQualifiedName()->Right();
225 case ir::AstNodeType::TS_CLASS_IMPLEMENTS: {
226 auto expr = expression->AsTSClassImplements()->Expr();
227 if (expr->IsIdentifier()) {
228 return expr->AsIdentifier();
229 } else if (expr->IsTSQualifiedName()) {
230 // TODO(extractor): consider property type suppport
231 return expr->AsTSQualifiedName()->Right();
232 }
233 return nullptr;
234 }
235 case ir::AstNodeType::REST_ELEMENT: {
236 auto argument = expression->AsRestElement()->Argument();
237 if (argument->IsIdentifier()) {
238 return argument->AsIdentifier();
239 }
240 return nullptr;
241 }
242 case ir::AstNodeType::SPREAD_ELEMENT: {
243 auto argument = expression->AsSpreadElement()->Argument();
244 if (argument->IsIdentifier()) {
245 return argument->AsIdentifier();
246 }
247 return nullptr;
248 }
249 case ir::AstNodeType::TS_INTERFACE_HERITAGE: {
250 auto expr = expression->AsTSInterfaceHeritage()->Expr();
251 if (expr->IsIdentifier()) {
252 return expr->AsIdentifier();
253 } else if (expr->IsTSQualifiedName()) {
254 // TODO(extractor): consider property type suppport
255 return expr->AsTSQualifiedName()->Right();
256 }
257 return nullptr;
258 }
259 default:
260 return nullptr;
261 }
262 }
263
GetDeclNodeFromIdentifier(const ir::Identifier * identifier,const ir::Identifier ** variable)264 const ir::AstNode *TypeExtractor::GetDeclNodeFromIdentifier(const ir::Identifier *identifier,
265 const ir::Identifier **variable)
266 {
267 if (identifier == nullptr || identifier->Variable() == nullptr ||
268 identifier->Variable()->Declaration() == nullptr) {
269 return nullptr;
270 }
271
272 auto res = identifier->Variable()->Declaration()->Node();
273 if (res != nullptr) {
274 // Return reference identifier if it contains variable binding to decl node
275 *variable = identifier;
276 TLOG(res->Type(), identifier);
277 }
278 return res;
279 }
280
GetDeclNodeFromInitializer(const ir::Expression * initializer,const ir::Identifier ** variable)281 const ir::AstNode *TypeExtractor::GetDeclNodeFromInitializer(const ir::Expression *initializer,
282 const ir::Identifier **variable)
283 {
284 switch (initializer->Type()) {
285 case ir::AstNodeType::IDENTIFIER: // let a = b / let a : A
286 return GetDeclNodeFromIdentifier(initializer->AsIdentifier(), variable);
287 case ir::AstNodeType::NEW_EXPRESSION: {
288 auto callee = initializer->AsNewExpression()->Callee();
289 if (callee->IsClassExpression()) { // let a = new class {}
290 return callee;
291 } else if (callee->IsIdentifier()) { // let a = new A()
292 return GetDeclNodeFromIdentifier(callee->AsIdentifier(), variable);
293 }
294 break;
295 }
296 case ir::AstNodeType::CLASS_EXPRESSION: // let a = class A {}
297 case ir::AstNodeType::MEMBER_EXPRESSION: // let a = ns.A / let a : ns.A
298 return initializer;
299 default:
300 break;
301 }
302
303 auto identifier = GetIdentifierFromExpression(initializer);
304 if (identifier != nullptr) {
305 return GetDeclNodeFromIdentifier(identifier, variable);
306 }
307 return nullptr;
308 }
309
GetTypeIndexFromDeclNode(const ir::AstNode * node,bool isNewInstance)310 int64_t TypeExtractor::GetTypeIndexFromDeclNode(const ir::AstNode *node, bool isNewInstance)
311 {
312 auto iter = getterMap_.find(node->Type());
313 if (iter != getterMap_.end()) {
314 return iter->second(node, isNewInstance);
315 }
316 return PrimitiveType::ANY;
317 }
318
GetTypeIndexFromIdentifierNode(const ir::AstNode * node,bool isNewInstance)319 int64_t TypeExtractor::GetTypeIndexFromIdentifierNode(const ir::AstNode *node, bool isNewInstance)
320 {
321 auto typeIndex = recorder_->GetNodeTypeIndex(node);
322 if (isNewInstance && typeIndex != PrimitiveType::ANY) {
323 typeIndex = GetTypeIndexFromClassInst(typeIndex);
324 }
325 TLOG(node->Type(), typeIndex);
326 return typeIndex;
327 }
328
GetTypeIndexFromClassExpression(const ir::AstNode * node,bool isNewInstance)329 int64_t TypeExtractor::GetTypeIndexFromClassExpression(const ir::AstNode *node, bool isNewInstance)
330 {
331 auto classDef = node->AsClassExpression()->Definition();
332 auto typeIndex = GetTypeIndexFromClassDefinition(classDef, isNewInstance);
333 TLOG(node->Type(), typeIndex);
334 return typeIndex;
335 }
336
GetTypeIndexFromClassDefinition(const ir::AstNode * node,bool isNewInstance)337 int64_t TypeExtractor::GetTypeIndexFromClassDefinition(const ir::AstNode *node, bool isNewInstance)
338 {
339 auto typeIndex = recorder_->GetNodeTypeIndex(node);
340 if (typeIndex == PrimitiveType::ANY) {
341 auto fn = [&node, &typeIndex, this](const util::StringView &name) {
342 ClassType classType(this, node->AsClassDefinition(), name);
343 typeIndex = classType.GetTypeIndexShift();
344 };
345
346 auto identifier = node->AsClassDefinition()->Ident();
347 if (identifier != nullptr) {
348 fn(identifier->Name());
349 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
350 } else {
351 fn(std::move(DEFAULT_NAME));
352 }
353 }
354
355 if (isNewInstance) {
356 typeIndex = GetTypeIndexFromClassInst(typeIndex);
357 }
358
359 TLOG(node->Type(), typeIndex);
360 return typeIndex;
361 }
362
GetTypeIndexFromInterfaceNode(const ir::AstNode * node,bool isNewInstance)363 int64_t TypeExtractor::GetTypeIndexFromInterfaceNode(const ir::AstNode *node, bool isNewInstance)
364 {
365 auto typeIndex = recorder_->GetNodeTypeIndex(node);
366 if (typeIndex == PrimitiveType::ANY) {
367 auto fn = [&node, &typeIndex, this](const util::StringView &name) {
368 InterfaceType interfaceType(this, node->AsTSInterfaceDeclaration(), name);
369 typeIndex = interfaceType.GetTypeIndexShift();
370 };
371
372 auto identifier = node->AsTSInterfaceDeclaration()->Id();
373 if (identifier != nullptr) {
374 fn(identifier->Name());
375 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
376 } else {
377 fn(std::move(DEFAULT_NAME));
378 }
379 }
380
381 if (isNewInstance) {
382 typeIndex = GetTypeIndexFromClassInst(typeIndex);
383 }
384
385 TLOG(node->Type(), typeIndex);
386 return typeIndex;
387 }
388
GetTypeIndexFromImportNode(const ir::AstNode * node,bool isNewInstance)389 int64_t TypeExtractor::GetTypeIndexFromImportNode(const ir::AstNode *node, [[maybe_unused]] bool isNewInstance)
390 {
391 auto typeIndex = recorder_->GetNodeTypeIndex(node);
392 TLOG(node->Type(), typeIndex);
393 return typeIndex;
394 }
395
GetTypeIndexFromTypeAliasNode(const ir::AstNode * node,bool isNewInstance)396 int64_t TypeExtractor::GetTypeIndexFromTypeAliasNode(const ir::AstNode *node, [[maybe_unused]] bool isNewInstance)
397 {
398 auto typeIndex = GetTypeIndexFromAnnotation(node->AsTSTypeAliasDeclaration()->TypeAnnotation());
399 TLOG(node->Type(), typeIndex);
400 return typeIndex;
401 }
402
GetTypeIndexFromMemberNode(const ir::AstNode * node,bool isNewInstance)403 int64_t TypeExtractor::GetTypeIndexFromMemberNode(const ir::AstNode *node, [[maybe_unused]] bool isNewInstance)
404 {
405 int64_t typeIndex = PrimitiveType::ANY;
406 auto object = node->AsMemberExpression()->Object();
407 auto property = node->AsMemberExpression()->Property();
408 if (object->IsIdentifier() && property->IsIdentifier()) {
409 auto redirectPath = recorder_->GetNamespacePath(std::string(object->AsIdentifier()->Name()));
410 if (redirectPath != "") {
411 ExternalType externalType(this, property->AsIdentifier()->Name(), util::StringView(redirectPath));
412 typeIndex = externalType.GetTypeIndexShift();
413 }
414 }
415 TLOG(node->Type(), typeIndex);
416 return typeIndex;
417 }
418
GetTypeIndexFromAnnotation(const ir::Expression * typeAnnotation)419 int64_t TypeExtractor::GetTypeIndexFromAnnotation(const ir::Expression *typeAnnotation)
420 {
421 if (typeAnnotation == nullptr) {
422 return PrimitiveType::ANY;
423 }
424
425 switch (typeAnnotation->AsTypeNode()->Type()) {
426 case ir::AstNodeType::TS_ANY_KEYWORD:
427 case ir::AstNodeType::TS_NUMBER_KEYWORD:
428 case ir::AstNodeType::TS_BOOLEAN_KEYWORD:
429 case ir::AstNodeType::TS_VOID_KEYWORD:
430 case ir::AstNodeType::TS_STRING_KEYWORD:
431 case ir::AstNodeType::TS_SYMBOL_KEYWORD:
432 case ir::AstNodeType::TS_NULL_KEYWORD:
433 case ir::AstNodeType::TS_UNDEFINED_KEYWORD:
434 return PRIMITIVE_TYPE_MAP.at(typeAnnotation->AsTypeNode()->Type());
435 case ir::AstNodeType::TS_NEVER_KEYWORD:
436 case ir::AstNodeType::TS_UNKNOWN_KEYWORD:
437 return PrimitiveType::ANY;
438 case ir::AstNodeType::TS_ARRAY_TYPE: { // ArrayType
439 ArrayType arrayType(this, typeAnnotation->AsTSArrayType());
440 return arrayType.GetTypeIndexShift();
441 }
442 case ir::AstNodeType::TS_UNION_TYPE: { // UnionType
443 UnionType unionType(this, typeAnnotation->AsTSUnionType());
444 return unionType.GetTypeIndexShift();
445 }
446 case ir::AstNodeType::TS_PARENT_TYPE: { // (UnionType)
447 auto type = typeAnnotation->AsTSParenthesizedType()->Type();
448 ASSERT(type != nullptr);
449 if (type->IsTSUnionType()) {
450 UnionType unionType(this, type->AsTSUnionType());
451 return unionType.GetTypeIndexShift();
452 }
453 return PrimitiveType::ANY;
454 }
455 case ir::AstNodeType::TS_TYPE_LITERAL: { // ObjectType
456 ObjectType objectType(this, typeAnnotation->AsTSTypeLiteral());
457 return objectType.GetTypeIndexShift();
458 }
459 case ir::AstNodeType::TS_OBJECT_KEYWORD: { // ObjectType
460 ObjectType objectType(this, nullptr); // let a : object
461 return objectType.GetTypeIndexShift();
462 }
463 case ir::AstNodeType::TS_BIGINT_KEYWORD:
464 case ir::AstNodeType::TS_CONDITIONAL_TYPE:
465 case ir::AstNodeType::TS_CONSTRUCTOR_TYPE:
466 case ir::AstNodeType::TS_FUNCTION_TYPE:
467 case ir::AstNodeType::TS_IMPORT_TYPE:
468 case ir::AstNodeType::TS_INDEXED_ACCESS_TYPE:
469 case ir::AstNodeType::TS_INTERSECTION_TYPE:
470 case ir::AstNodeType::TS_INFER_TYPE:
471 case ir::AstNodeType::TS_LITERAL_TYPE:
472 case ir::AstNodeType::TS_MAPPED_TYPE:
473 case ir::AstNodeType::TS_OPTIONAL_TYPE:
474 case ir::AstNodeType::TS_REST_TYPE:
475 case ir::AstNodeType::TS_TEMPLATE_LITERAL_TYPE:
476 case ir::AstNodeType::TS_THIS_TYPE:
477 case ir::AstNodeType::TS_TUPLE_TYPE:
478 case ir::AstNodeType::TS_TYPE_OPERATOR:
479 case ir::AstNodeType::TS_TYPE_PREDICATE:
480 case ir::AstNodeType::TS_TYPE_QUERY:
481 return PrimitiveType::ANY;
482 case ir::AstNodeType::TS_TYPE_REFERENCE: { // let a : A
483 return GetTypeIndexFromTypeReference(typeAnnotation->AsTSTypeReference());
484 }
485 default:
486 UNREACHABLE();
487 }
488 }
489
GetTypeIndexFromIdentifier(const ir::Identifier * identifier)490 int64_t TypeExtractor::GetTypeIndexFromIdentifier(const ir::Identifier *identifier)
491 {
492 auto typeAnnotation = identifier->TypeAnnotation();
493 auto typeIndex = GetTypeIndexFromAnnotation(typeAnnotation);
494 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
495 TLOG(identifier->Type(), typeIndex);
496 return typeIndex;
497 }
498
GetTypeIndexFromInitializer(const ir::Expression * initializer)499 int64_t TypeExtractor::GetTypeIndexFromInitializer(const ir::Expression *initializer)
500 {
501 int64_t typeIndex = PrimitiveType::ANY;
502 // Special case for Builtin
503 if (initializer->IsNewExpression()) {
504 auto callee = initializer->AsNewExpression()->Callee();
505 if (callee->IsIdentifier()) {
506 typeIndex = GetTypeIndexFromBuiltin(callee->AsIdentifier()->Name(),
507 initializer->AsNewExpression()->TypeParams());
508 if (typeIndex != PrimitiveType::ANY) {
509 return typeIndex;
510 }
511 }
512 }
513
514 const ir::Identifier *identifier = nullptr;
515 // Identifier here is a reference identifier binding to decl node which also contains variable
516 auto declNode = GetDeclNodeFromInitializer(initializer, &identifier);
517 if (declNode != nullptr) {
518 typeIndex = GetTypeIndexFromDeclNode(declNode, initializer->IsNewExpression());
519 recorder_->SetIdentifierTypeIndex(identifier, recorder_->GetClassType(typeIndex));
520 }
521 TLOG(initializer->Type(), typeIndex);
522 return typeIndex;
523 }
524
HandleVariableDeclaration(const ir::AstNode * node)525 void TypeExtractor::HandleVariableDeclaration(const ir::AstNode *node)
526 {
527 auto isExported = IsExportNode(node);
528 for (const auto *it : node->AsVariableDeclaration()->Declarators()) {
529 if (!it->Id()->IsIdentifier()) {
530 // BindingElement needs type inference, like:
531 // ArrayExpression: let [a, b] = [1, 2]
532 // ObjectExpression: let {a, b} = c
533 continue;
534 }
535 auto identifier = it->Id()->AsIdentifier();
536 ASSERT(identifier != nullptr);
537 auto typeIndex = GetTypeIndexFromIdentifier(identifier);
538 if (typeIndex == PrimitiveType::ANY && it->Init() != nullptr) {
539 typeIndex = GetTypeIndexFromInitializer(it->Init());
540 }
541 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
542 if (isExported && typeIndex != PrimitiveType::ANY) {
543 recorder_->SetExportType(std::string(identifier->Name()), typeIndex);
544 }
545 }
546 }
547
HandleFunctionDeclaration(const ir::AstNode * node)548 void TypeExtractor::HandleFunctionDeclaration(const ir::AstNode *node)
549 {
550 int64_t typeIndex = PrimitiveType::ANY;
551 auto fn = [&node, &typeIndex, this](const util::StringView &name) {
552 FunctionType functionType(this, node, name);
553 typeIndex = functionType.GetTypeIndexShift();
554 if (IsExportNode(node)) {
555 recorder_->SetExportType(std::string(name), typeIndex);
556 }
557 if (IsDeclareNode(node)) {
558 recorder_->SetDeclareType(std::string(name), typeIndex);
559 }
560 };
561
562 auto identifier = node->AsFunctionDeclaration()->Function()->Id();
563 if (identifier != nullptr) {
564 fn(identifier->Name());
565 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
566 } else {
567 fn("");
568 }
569 }
570
HandleClassDeclaration(const ir::AstNode * node)571 void TypeExtractor::HandleClassDeclaration(const ir::AstNode *node)
572 {
573 int64_t typeIndex = PrimitiveType::ANY;
574 auto classDef = node->AsClassDeclaration()->Definition();
575 auto fn = [&node, &typeIndex, &classDef, this](const util::StringView &name) {
576 ClassType classType(this, classDef, name);
577 typeIndex = classType.GetTypeIndexShift();
578 if (IsExportNode(node)) {
579 recorder_->SetExportType(std::string(name), typeIndex);
580 }
581 if (IsDeclareNode(node)) {
582 recorder_->SetDeclareType(std::string(name), typeIndex);
583 }
584 };
585
586 auto identifier = classDef->Ident();
587 if (identifier != nullptr) {
588 fn(identifier->Name());
589 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
590 } else {
591 fn(std::move(DEFAULT_NAME));
592 }
593 }
594
HandleInterfaceDeclaration(const ir::AstNode * node)595 void TypeExtractor::HandleInterfaceDeclaration(const ir::AstNode *node)
596 {
597 int64_t typeIndex = PrimitiveType::ANY;
598 auto interfaceDef = node->AsTSInterfaceDeclaration();
599 auto fn = [&node, &typeIndex, &interfaceDef, this](const util::StringView &name) {
600 InterfaceType interfaceType(this, interfaceDef, name);
601 typeIndex = interfaceType.GetTypeIndexShift();
602 if (IsExportNode(node)) {
603 recorder_->SetExportType(std::string(name), typeIndex);
604 }
605 if (IsDeclareNode(node)) {
606 recorder_->SetDeclareType(std::string(name), typeIndex);
607 }
608 };
609
610 auto identifier = interfaceDef->Id();
611 if (identifier != nullptr) {
612 fn(identifier->Name());
613 recorder_->SetIdentifierTypeIndex(identifier, typeIndex);
614 } else {
615 fn(std::move(DEFAULT_NAME));
616 }
617 }
618
HandleTypeAliasDeclaration(const ir::AstNode * node)619 void TypeExtractor::HandleTypeAliasDeclaration(const ir::AstNode *node)
620 {
621 // Create the type if it is exported or declared
622 auto typeAliasDef = node->AsTSTypeAliasDeclaration();
623 auto identifier = typeAliasDef->Id();
624 if (IsExportNode(node)) {
625 recorder_->SetExportType(std::string(identifier->Name()),
626 GetTypeIndexFromAnnotation(typeAliasDef->TypeAnnotation()));
627 }
628 if (IsDeclareNode(node)) {
629 recorder_->SetDeclareType(std::string(identifier->Name()),
630 GetTypeIndexFromAnnotation(typeAliasDef->TypeAnnotation()));
631 }
632 }
633
GetTypeIndexFromClassInst(int64_t typeIndex)634 int64_t TypeExtractor::GetTypeIndexFromClassInst(int64_t typeIndex)
635 {
636 auto typeIndexTmp = recorder_->GetClassInst(typeIndex);
637 if (typeIndexTmp == PrimitiveType::ANY) {
638 ClassInstType classInstType(this, typeIndex);
639 return classInstType.GetTypeIndexShift();
640 }
641 return typeIndexTmp;
642 }
643
GetTypeIndexFromTypeReference(const ir::TSTypeReference * typeReference)644 int64_t TypeExtractor::GetTypeIndexFromTypeReference(const ir::TSTypeReference *typeReference)
645 {
646 auto typeName = typeReference->TypeName();
647 ASSERT(typeName != nullptr);
648 if (typeName->IsIdentifier()) {
649 // Special case for Builtin
650 auto typeIndexBuiltin = GetTypeIndexFromBuiltin(typeName->AsIdentifier()->Name(), typeReference->TypeParams());
651 if (typeIndexBuiltin != PrimitiveType::ANY) {
652 return typeIndexBuiltin;
653 }
654 }
655
656 const ir::Identifier *identifier = nullptr;
657 // TypeName can be Identifier or TSQualifiedName
658 // Identifier here is a reference identifier binding to decl node which also contains variable
659 auto declNode = GetDeclNodeFromInitializer(typeName, &identifier);
660 if (declNode != nullptr) {
661 auto typeIndex = GetTypeIndexFromDeclNode(declNode, true);
662 recorder_->SetIdentifierTypeIndex(identifier, recorder_->GetClassType(typeIndex));
663 return typeIndex;
664 }
665 return PrimitiveType::ANY;
666 }
667
GetTypeIndexFromBuiltin(const util::StringView & name,const ir::TSTypeParameterInstantiation * node)668 int64_t TypeExtractor::GetTypeIndexFromBuiltin(const util::StringView &name,
669 const ir::TSTypeParameterInstantiation *node)
670 {
671 auto typeIndexBuiltin = GetBuiltinTypeIndex(name);
672 if (typeIndexBuiltin != PrimitiveType::ANY) {
673 if (node == nullptr) {
674 return GetTypeIndexFromClassInst(typeIndexBuiltin);
675 }
676 return GetTypeIndexFromBuiltinInst(typeIndexBuiltin, node);
677 }
678 return PrimitiveType::ANY;
679 }
680
GetTypeIndexFromBuiltinInst(int64_t typeIndexBuiltin,const ir::TSTypeParameterInstantiation * node)681 int64_t TypeExtractor::GetTypeIndexFromBuiltinInst(int64_t typeIndexBuiltin,
682 const ir::TSTypeParameterInstantiation *node)
683 {
684 std::vector<int64_t> allTypes = { typeIndexBuiltin };
685 for (const auto &t : node->Params()) {
686 allTypes.emplace_back(GetTypeIndexFromAnnotation(t));
687 }
688 auto typeIndex = recorder_->GetBuiltinInst(allTypes);
689 if (typeIndex != PrimitiveType::ANY) {
690 return typeIndex;
691 }
692
693 // New instance for builtin generic type
694 BuiltinInstType builtinInstType(this, allTypes);
695 return GetTypeIndexFromClassInst(builtinInstType.GetTypeIndexShift());
696 }
697
IsExportNode(const ir::AstNode * node) const698 bool TypeExtractor::IsExportNode(const ir::AstNode *node) const
699 {
700 auto parent = node->Parent();
701 if (parent->Parent() != rootNode_) {
702 return false;
703 }
704 if (parent->IsExportNamedDeclaration() || parent->IsExportDefaultDeclaration()) {
705 return true;
706 }
707 return false;
708 }
709
IsDeclareNode(const ir::AstNode * node) const710 bool TypeExtractor::IsDeclareNode(const ir::AstNode *node) const
711 {
712 if (!typeDtsExtractor_) {
713 return false;
714 }
715 switch (node->Type()) {
716 case ir::AstNodeType::FUNCTION_DECLARATION:
717 return node->AsFunctionDeclaration()->Function()->Declare();
718 case ir::AstNodeType::CLASS_DEFINITION:
719 return node->AsClassDefinition()->Declare();
720 case ir::AstNodeType::TS_INTERFACE_DECLARATION:
721 return true;
722 case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION:
723 return node->AsTSTypeAliasDeclaration()->Declare();
724 default:
725 break;
726 }
727 return false;
728 }
729
730 // static
GetBuiltinTypeIndex(util::StringView name)731 int64_t TypeExtractor::GetBuiltinTypeIndex(util::StringView name)
732 {
733 auto t = BUILTIN_TYPE_MAP.find(std::string(name));
734 if (t != BUILTIN_TYPE_MAP.end()) {
735 return t->second;
736 }
737 return PrimitiveType::ANY;
738 }
739
740 } // namespace panda::es2panda::extractor
741