• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 - 2023 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 "aliveAnalyzer.h"
17 #include <cstddef>
18 
19 #include "checker/types/ets/etsAsyncFuncReturnType.h"
20 #include "ir/base/classDefinition.h"
21 #include "ir/base/classProperty.h"
22 #include "ir/base/methodDefinition.h"
23 #include "ir/base/scriptFunction.h"
24 #include "ir/statements/classDeclaration.h"
25 #include "ir/statements/variableDeclaration.h"
26 #include "ir/statements/doWhileStatement.h"
27 #include "ir/statements/expressionStatement.h"
28 #include "ir/statements/whileStatement.h"
29 #include "ir/statements/forUpdateStatement.h"
30 #include "ir/statements/labelledStatement.h"
31 #include "ir/statements/forOfStatement.h"
32 #include "ir/statements/blockStatement.h"
33 #include "ir/statements/ifStatement.h"
34 #include "ir/statements/switchStatement.h"
35 #include "ir/statements/variableDeclarator.h"
36 #include "ir/statements/throwStatement.h"
37 #include "ir/statements/switchCaseStatement.h"
38 #include "ir/statements/breakStatement.h"
39 #include "ir/statements/continueStatement.h"
40 #include "ir/statements/returnStatement.h"
41 #include "ir/statements/tryStatement.h"
42 #include "ir/expressions/callExpression.h"
43 #include "ir/expressions/identifier.h"
44 #include "ir/ets/etsNewClassInstanceExpression.h"
45 #include "ir/ets/etsStructDeclaration.h"
46 #include "ir/ts/tsInterfaceDeclaration.h"
47 #include "varbinder/variable.h"
48 #include "varbinder/scope.h"
49 #include "varbinder/declaration.h"
50 #include "checker/ETSchecker.h"
51 #include "ir/base/catchClause.h"
52 
53 namespace panda::es2panda::checker {
54 
AnalyzeNodes(const ir::AstNode * node)55 void AliveAnalyzer::AnalyzeNodes(const ir::AstNode *node)
56 {
57     node->Iterate([this](auto *childNode) { AnalyzeNode(childNode); });
58 }
59 
AnalyzeNode(const ir::AstNode * node)60 void AliveAnalyzer::AnalyzeNode(const ir::AstNode *node)
61 {
62     if (node == nullptr) {
63         return;
64     }
65 
66     switch (node->Type()) {
67         case ir::AstNodeType::EXPRESSION_STATEMENT: {
68             AnalyzeNode(node->AsExpressionStatement()->GetExpression());
69             break;
70         }
71         case ir::AstNodeType::STRUCT_DECLARATION: {
72             AnalyzeStructDecl(node->AsETSStructDeclaration());
73             break;
74         }
75         case ir::AstNodeType::CLASS_DECLARATION: {
76             AnalyzeClassDecl(node->AsClassDeclaration());
77             break;
78         }
79         case ir::AstNodeType::CLASS_DEFINITION: {
80             AnalyzeClassDef(node->AsClassDefinition());
81             break;
82         }
83         case ir::AstNodeType::METHOD_DEFINITION: {
84             AnalyzeMethodDef(node->AsMethodDefinition());
85             break;
86         }
87         case ir::AstNodeType::VARIABLE_DECLARATION: {
88             AnalyzeVarDef(node->AsVariableDeclaration());
89             break;
90         }
91         case ir::AstNodeType::BLOCK_STATEMENT: {
92             AnalyzeStats(node->AsBlockStatement()->Statements());
93             break;
94         }
95         case ir::AstNodeType::DO_WHILE_STATEMENT: {
96             AnalyzeDoLoop(node->AsDoWhileStatement());
97             break;
98         }
99         case ir::AstNodeType::WHILE_STATEMENT: {
100             AnalyzeWhileLoop(node->AsWhileStatement());
101             break;
102         }
103         case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
104             AnalyzeForLoop(node->AsForUpdateStatement());
105             break;
106         }
107         case ir::AstNodeType::FOR_OF_STATEMENT: {
108             AnalyzeForOfLoop(node->AsForOfStatement());
109             break;
110         }
111         case ir::AstNodeType::IF_STATEMENT: {
112             AnalyzeIf(node->AsIfStatement());
113             break;
114         }
115         case ir::AstNodeType::LABELLED_STATEMENT: {
116             AnalyzeLabelled(node->AsLabelledStatement());
117             break;
118         }
119         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: {
120             AnalyzeNewClass(node->AsETSNewClassInstanceExpression());
121             break;
122         }
123         case ir::AstNodeType::CALL_EXPRESSION: {
124             AnalyzeCall(node->AsCallExpression());
125             break;
126         }
127         case ir::AstNodeType::THROW_STATEMENT: {
128             AnalyzeThrow(node->AsThrowStatement());
129             break;
130         }
131         case ir::AstNodeType::SWITCH_STATEMENT: {
132             AnalyzeSwitch(node->AsSwitchStatement());
133             break;
134         }
135         case ir::AstNodeType::TRY_STATEMENT: {
136             AnalyzeTry(node->AsTryStatement());
137             break;
138         }
139         case ir::AstNodeType::BREAK_STATEMENT: {
140             AnalyzeBreak(node->AsBreakStatement());
141             break;
142         }
143         case ir::AstNodeType::CONTINUE_STATEMENT: {
144             AnalyzeContinue(node->AsContinueStatement());
145             break;
146         }
147         case ir::AstNodeType::RETURN_STATEMENT: {
148             AnalyzeReturn(node->AsReturnStatement());
149             break;
150         }
151         default: {
152             break;
153         }
154     }
155 }
156 
AnalyzeDef(const ir::AstNode * node)157 void AliveAnalyzer::AnalyzeDef(const ir::AstNode *node)
158 {
159     AnalyzeStat(node);
160     if (node != nullptr && node->IsClassStaticBlock() && status_ == LivenessStatus::DEAD) {
161         checker_->ThrowTypeError("Initializer must be able to complete normally.", node->Start());
162     }
163 }
164 
AnalyzeStat(const ir::AstNode * node)165 void AliveAnalyzer::AnalyzeStat(const ir::AstNode *node)
166 {
167     if (node == nullptr) {
168         return;
169     }
170 
171     if (status_ == LivenessStatus::DEAD) {
172         checker_->ThrowTypeError("Unreachable statement.", node->Start());
173     }
174 
175     if (node->IsClassStaticBlock()) {
176         AnalyzeNodes(node);
177         return;
178     }
179 
180     AnalyzeNode(node);
181 }
182 
AnalyzeStats(const ArenaVector<ir::Statement * > & stats)183 void AliveAnalyzer::AnalyzeStats(const ArenaVector<ir::Statement *> &stats)
184 {
185     for (const auto *it : stats) {
186         AnalyzeStat(it);
187     }
188 }
189 
IsStaticMember(const ir::AstNode * node)190 static bool IsStaticMember(const ir::AstNode *node)
191 {
192     switch (node->Type()) {
193         case ir::AstNodeType::CLASS_PROPERTY: {
194             return node->IsStatic();
195         }
196         case ir::AstNodeType::STRUCT_DECLARATION: {
197             return node->AsETSStructDeclaration()->Definition()->IsStatic();
198         }
199         case ir::AstNodeType::CLASS_DECLARATION: {
200             return node->AsClassDeclaration()->Definition()->IsStatic();
201         }
202         case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
203             return node->IsStatic();
204         }
205         default: {
206             return false;
207         }
208     }
209 }
210 
AnalyzeStructDecl(const ir::ETSStructDeclaration * structDecl)211 void AliveAnalyzer::AnalyzeStructDecl(const ir::ETSStructDeclaration *structDecl)
212 {
213     for (const auto *it : structDecl->Definition()->Body()) {
214         AnalyzeNode(it);
215     }
216 }
217 
AnalyzeClassDecl(const ir::ClassDeclaration * classDecl)218 void AliveAnalyzer::AnalyzeClassDecl(const ir::ClassDeclaration *classDecl)
219 {
220     for (const auto *it : classDecl->Definition()->Body()) {
221         AnalyzeNode(it);
222     }
223 }
224 
AnalyzeClassDef(const ir::ClassDefinition * classDef)225 void AliveAnalyzer::AnalyzeClassDef(const ir::ClassDefinition *classDef)
226 {
227     if (classDef->Variable() == nullptr) {
228         return;
229     }
230 
231     LivenessStatus prevStatus = status_;
232     SetOldPendingExits(PendingExits());
233 
234     for (const auto *it : classDef->Body()) {
235         if (!it->IsMethodDefinition() && IsStaticMember(it)) {
236             AnalyzeDef(it);
237             ClearPendingExits();
238         }
239     }
240 
241     for (const auto *it : classDef->Body()) {
242         if (!it->IsMethodDefinition() && !IsStaticMember(it)) {
243             AnalyzeDef(it);
244             ClearPendingExits();
245         }
246     }
247 
248     for (const auto *it : classDef->Body()) {
249         if (it->IsClassStaticBlock()) {
250             AnalyzeDef(it);
251             break;
252         }
253     }
254 
255     for (const auto *it : classDef->Body()) {
256         if (it->IsMethodDefinition()) {
257             AnalyzeNode(it);
258         }
259     }
260 
261     SetPendingExits(OldPendingExits());
262     status_ = prevStatus;
263 }
264 
AnalyzeMethodDef(const ir::MethodDefinition * methodDef)265 void AliveAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef)
266 {
267     auto *func = methodDef->Function();
268 
269     if (func->Body() == nullptr || func->IsProxy()) {
270         return;
271     }
272 
273     status_ = LivenessStatus::ALIVE;
274     AnalyzeStat(func->Body());
275     ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType());
276     const auto *returnType = methodDef->TsType()->AsETSFunctionType()->FindSignature(func)->ReturnType();
277     const auto isVoid = returnType->IsETSVoidType() || returnType == checker_->GlobalBuiltinVoidType();
278 
279     auto isPromiseVoid = false;
280 
281     if (returnType->IsETSAsyncFuncReturnType()) {
282         const auto *asAsync = returnType->AsETSAsyncFuncReturnType();
283         isPromiseVoid = asAsync->GetPromiseTypeArg() == checker_->GlobalBuiltinVoidType();
284     }
285 
286     if (status_ == LivenessStatus::ALIVE && !isVoid && !isPromiseVoid) {
287         checker_->ThrowTypeError("Function with a non void return type must return a value.", func->Id()->Start());
288     }
289 
290     ClearPendingExits();
291 }
292 
AnalyzeVarDef(const ir::VariableDeclaration * varDef)293 void AliveAnalyzer::AnalyzeVarDef(const ir::VariableDeclaration *varDef)
294 {
295     for (auto *it : varDef->Declarators()) {
296         if (it->Init() == nullptr) {
297             continue;
298         }
299 
300         AnalyzeNode(it->Init());
301     }
302 }
303 
AnalyzeDoLoop(const ir::DoWhileStatement * doWhile)304 void AliveAnalyzer::AnalyzeDoLoop(const ir::DoWhileStatement *doWhile)
305 {
306     SetOldPendingExits(PendingExits());
307     AnalyzeStat(doWhile->Body());
308     status_ = Or(status_, ResolveContinues(doWhile));
309     AnalyzeNode(doWhile->Test());
310     ASSERT(doWhile->Test()->TsType() && doWhile->Test()->TsType()->IsConditionalExprType());
311     const auto exprRes = doWhile->Test()->TsType()->ResolveConditionExpr();
312     status_ = And(status_, static_cast<LivenessStatus>(!std::get<0>(exprRes) || !std::get<1>(exprRes)));
313     status_ = Or(status_, ResolveBreaks(doWhile));
314 }
315 
AnalyzeWhileLoop(const ir::WhileStatement * whileStmt)316 void AliveAnalyzer::AnalyzeWhileLoop(const ir::WhileStatement *whileStmt)
317 {
318     SetOldPendingExits(PendingExits());
319     AnalyzeNode(whileStmt->Test());
320     ASSERT(whileStmt->Test()->TsType() && whileStmt->Test()->TsType()->IsConditionalExprType());
321     const auto exprRes = whileStmt->Test()->TsType()->ResolveConditionExpr();
322     status_ = And(status_, static_cast<LivenessStatus>(!std::get<0>(exprRes) || std::get<1>(exprRes)));
323     AnalyzeStat(whileStmt->Body());
324     status_ = Or(status_, ResolveContinues(whileStmt));
325     status_ = Or(ResolveBreaks(whileStmt), From(!std::get<0>(exprRes) || !std::get<1>(exprRes)));
326 }
327 
AnalyzeForLoop(const ir::ForUpdateStatement * forStmt)328 void AliveAnalyzer::AnalyzeForLoop(const ir::ForUpdateStatement *forStmt)
329 {
330     AnalyzeNode(forStmt->Init());
331     SetOldPendingExits(PendingExits());
332     const Type *condType {};
333     bool resolveType = false;
334     bool res = false;
335 
336     if (forStmt->Test() != nullptr) {
337         AnalyzeNode(forStmt->Test());
338         ASSERT(forStmt->Test()->TsType() && forStmt->Test()->TsType()->IsConditionalExprType());
339         condType = forStmt->Test()->TsType();
340         std::tie(resolveType, res) = forStmt->Test()->TsType()->ResolveConditionExpr();
341         status_ = From(!resolveType || res);
342     } else {
343         status_ = LivenessStatus::ALIVE;
344     }
345 
346     AnalyzeStat(forStmt->Body());
347     status_ = Or(status_, ResolveContinues(forStmt));
348     AnalyzeNode(forStmt->Update());
349     status_ = Or(ResolveBreaks(forStmt), From(condType != nullptr && (!resolveType || !res)));
350 }
351 
AnalyzeForOfLoop(const ir::ForOfStatement * forOfStmt)352 void AliveAnalyzer::AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt)
353 {
354     //  Note: iterator definition can be a reference to variable defined in outer scope!
355     if (forOfStmt->Left()->IsVariableDeclaration()) {
356         AnalyzeVarDef(forOfStmt->Left()->AsVariableDeclaration());
357     } else {
358         AnalyzeNode(forOfStmt->Left());
359     }
360     AnalyzeNode(forOfStmt->Right());
361     SetOldPendingExits(PendingExits());
362 
363     AnalyzeStat(forOfStmt->Body());
364     status_ = Or(status_, ResolveContinues(forOfStmt));
365     ResolveBreaks(forOfStmt);
366     status_ = LivenessStatus::ALIVE;
367 }
368 
AnalyzeIf(const ir::IfStatement * ifStmt)369 void AliveAnalyzer::AnalyzeIf(const ir::IfStatement *ifStmt)
370 {
371     AnalyzeNode(ifStmt->Test());
372     AnalyzeStat(ifStmt->Consequent());
373     if (ifStmt->Alternate() != nullptr) {
374         LivenessStatus prevStatus = status_;
375         status_ = LivenessStatus::ALIVE;
376         AnalyzeStat(ifStmt->Alternate());
377         status_ = Or(status_, prevStatus);
378     } else {
379         status_ = LivenessStatus::ALIVE;
380     }
381 }
382 
AnalyzeLabelled(const ir::LabelledStatement * labelledStmt)383 void AliveAnalyzer::AnalyzeLabelled(const ir::LabelledStatement *labelledStmt)
384 {
385     SetOldPendingExits(PendingExits());
386     AnalyzeStat(labelledStmt->Body());
387     status_ = Or(status_, ResolveBreaks(labelledStmt));
388 }
389 
AnalyzeNewClass(const ir::ETSNewClassInstanceExpression * newClass)390 void AliveAnalyzer::AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass)
391 {
392     for (const auto *it : newClass->GetArguments()) {
393         AnalyzeNode(it);
394     }
395 
396     if (newClass->ClassDefinition() != nullptr) {
397         AnalyzeNode(newClass->ClassDefinition());
398     }
399 }
400 
AnalyzeCall(const ir::CallExpression * callExpr)401 void AliveAnalyzer::AnalyzeCall(const ir::CallExpression *callExpr)
402 {
403     AnalyzeNode(callExpr->Callee());
404     for (const auto *it : callExpr->Arguments()) {
405         AnalyzeNode(it);
406     }
407     if (callExpr->Signature()->ReturnType() == checker_->GetGlobalTypesHolder()->GlobalBuiltinNeverType()) {
408         MarkDead();
409     }
410 }
411 
AnalyzeThrow(const ir::ThrowStatement * throwStmt)412 void AliveAnalyzer::AnalyzeThrow(const ir::ThrowStatement *throwStmt)
413 {
414     AnalyzeNode(throwStmt->Argument());
415     MarkDead();
416 }
417 
AnalyzeSwitch(const ir::SwitchStatement * switchStmt)418 void AliveAnalyzer::AnalyzeSwitch(const ir::SwitchStatement *switchStmt)
419 {
420     SetOldPendingExits(PendingExits());
421 
422     AnalyzeNode(switchStmt->Discriminant());
423 
424     bool hasDefault = false;
425     for (std::size_t i = 0, size = switchStmt->Cases().size(); i < size; i++) {
426         const auto *caseClause = switchStmt->Cases()[i];
427         status_ = LivenessStatus::ALIVE;
428 
429         if (caseClause->Test() == nullptr) {
430             hasDefault = true;
431         } else {
432             AnalyzeNode(caseClause->Test());
433         }
434 
435         AnalyzeStats(caseClause->Consequent());
436 
437         if (status_ == LivenessStatus::ALIVE && !caseClause->Consequent().empty() && i < size - 1) {
438             // NOTE(user) Add lint categories and option to enable/disable compiler warnings
439             checker_->Warning("Possible fall-through into case", caseClause->Start());
440         }
441     }
442 
443     if (!hasDefault) {
444         status_ = LivenessStatus::ALIVE;
445     }
446 
447     status_ = Or(status_, ResolveBreaks(switchStmt));
448 }
449 
AnalyzeBreak(const ir::BreakStatement * breakStmt)450 void AliveAnalyzer::AnalyzeBreak(const ir::BreakStatement *breakStmt)
451 {
452     RecordExit(PendingExit(breakStmt));
453 }
454 
AnalyzeContinue(const ir::ContinueStatement * contStmt)455 void AliveAnalyzer::AnalyzeContinue(const ir::ContinueStatement *contStmt)
456 {
457     RecordExit(PendingExit(contStmt));
458 }
459 
AnalyzeReturn(const ir::ReturnStatement * retStmt)460 void AliveAnalyzer::AnalyzeReturn(const ir::ReturnStatement *retStmt)
461 {
462     AnalyzeNode(retStmt->Argument());
463     RecordExit(PendingExit(retStmt));
464 }
465 
AnalyzeTry(const ir::TryStatement * tryStmt)466 void AliveAnalyzer::AnalyzeTry(const ir::TryStatement *tryStmt)
467 {
468     status_ = LivenessStatus::ALIVE;
469     bool isAlive = false;
470     AnalyzeStats(tryStmt->Block()->Statements());
471 
472     if (status_ != LivenessStatus::DEAD) {
473         isAlive = true;
474     }
475 
476     for (const auto &it : tryStmt->CatchClauses()) {
477         status_ = LivenessStatus::ALIVE;
478         AnalyzeStats(it->Body()->Statements());
479         if (status_ == LivenessStatus::ALIVE) {
480             isAlive = true;
481         }
482     }
483 
484     if (tryStmt->FinallyBlock() != nullptr) {
485         status_ = LivenessStatus::ALIVE;
486         AnalyzeStats(tryStmt->FinallyBlock()->Statements());
487         if (status_ == LivenessStatus::DEAD) {
488             isAlive = false;
489         }
490     }
491 
492     status_ = isAlive ? LivenessStatus::ALIVE : LivenessStatus::DEAD;
493 }
494 }  // namespace panda::es2panda::checker
495