• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &regularImportEntries = 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