From f22c897abdb23b535884d495fa2493c419e3911b Mon Sep 17 00:00:00 2001 From: Shimenkov Mikhail Date: Thu, 29 May 2025 12:47:05 +0300 Subject: [PATCH] Fix enumeration equality with numeric type operand and enum member initialisation Signed-off-by: Shimenkov Mikhail Change-Id: Ib45659d579016e8d6cec1c706394467cc71db7c3 --- ets2panda/checker/ETSchecker.cpp | 10 ++++ ets2panda/checker/ETSchecker.h | 2 + ets2panda/checker/ets/arithmetic.cpp | 56 +++++++++---------- .../ets/constantExpressionLowering.cpp | 47 ++++++++++------ .../lowering/scopesInit/scopesInitPhase.cpp | 2 +- 5 files changed, 69 insertions(+), 48 deletions(-) diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index e02620306d..911c0a1ea8 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -416,6 +416,11 @@ ETSObjectType *ETSChecker::AsETSObjectType(Type *(GlobalTypesHolder::*typeFuncto return ret != nullptr ? ret->AsETSObjectType() : nullptr; } +Type *ETSChecker::GlobalIntegralBuiltinType() const +{ + return GetGlobalTypesHolder()->GlobalIntegralBuiltinType(); +} + Type *ETSChecker::GlobalByteType() const { return GetGlobalTypesHolder()->GlobalByteType(); @@ -456,6 +461,11 @@ Type *ETSChecker::GlobalLongBuiltinType() const return GetGlobalTypesHolder()->GlobalLongBuiltinType(); } +Type *ETSChecker::GlobalFloatingBuiltinType() const +{ + return GetGlobalTypesHolder()->GlobalFloatingBuiltinType(); +} + Type *ETSChecker::GlobalFloatType() const { return GetGlobalTypesHolder()->GlobalFloatType(); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 835f324291..57ef9dcf63 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -114,10 +114,12 @@ public: Type *GlobalETSBigIntType() const; Type *GlobalWildcardType() const; + Type *GlobalIntegralBuiltinType() const; Type *GlobalByteBuiltinType() const; Type *GlobalShortBuiltinType() const; Type *GlobalIntBuiltinType() const; Type *GlobalLongBuiltinType() const; + Type *GlobalFloatingBuiltinType() const; Type *GlobalFloatBuiltinType() const; Type *GlobalDoubleBuiltinType() const; Type *GlobalCharBuiltinType() const; diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index b8ba216184..4c75183cbe 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -565,6 +565,32 @@ static bool ContainsNumbers(ETSChecker *checker, Type *tp) return false; } +static bool NonNumericTypesAreAppropriateForComparison(ETSChecker *checker, Type *leftType, Type *rightType) +{ + if (rightType->IsETSStringType() && leftType->IsETSStringType()) { + return true; + } + if (leftType->IsETSEnumType() && rightType->IsETSEnumType()) { + return checker->Relation()->IsIdenticalTo(leftType, rightType); + } + if ((leftType->IsETSStringEnumType() && rightType->IsETSStringType()) || + (leftType->IsETSStringType() && rightType->IsETSStringEnumType())) { + return true; + } + + auto isComparableWithIntEnumNumeric = [checker](checker::Type *t) -> bool { + return checker->Relation()->IsSupertypeOf(checker->GlobalFloatingBuiltinType(), t) || + checker->Relation()->IsIdenticalTo(checker->GlobalIntBuiltinType(), t) || + checker->Relation()->IsIdenticalTo(checker->GlobalLongBuiltinType(), t); + }; + + if ((isComparableWithIntEnumNumeric(leftType) && rightType->IsETSIntEnumType()) || + (leftType->IsETSIntEnumType() && isComparableWithIntEnumNumeric(rightType))) { + return true; + } + return false; +} + // CC-OFFNXT(huge_cyclomatic_complexity, huge_cca_cyclomatic_complexity[C++]) solid logic bool ETSChecker::CheckValidEqualReferenceType(checker::Type *const leftType, checker::Type *const rightType) { @@ -616,13 +642,7 @@ bool ETSChecker::CheckValidEqualReferenceType(checker::Type *const leftType, che } } - if (FindOpArgsType(this, leftType, rightType, GetGlobalTypesHolder()->GlobalIntegerBuiltinType()) && - (leftType->IsETSEnumType() || rightType->IsETSEnumType())) { - return true; - } - - // 7.24.5 Enumeration Relational Operators - return leftType->IsETSEnumType() == rightType->IsETSEnumType(); + return NonNumericTypesAreAppropriateForComparison(this, leftType, rightType); } std::tuple ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expression *left, @@ -739,28 +759,6 @@ static Type *CheckBinaryOperatorEqual(ETSChecker *checker, BinaryArithmOperands return HandelReferenceBinaryEquality(checker, ops); } -// Satisfying the Chinese checker -static bool NonNumericTypesAreAppropriateForComparison(ETSChecker *checker, Type *leftType, Type *rightType) -{ - leftType = checker->MaybeUnboxType(leftType); - rightType = checker->MaybeUnboxType(rightType); - if (rightType->IsETSStringType() && leftType->IsETSStringType()) { - return true; - } - if (leftType->IsETSEnumType() && rightType->IsETSEnumType()) { - return checker->Relation()->IsIdenticalTo(leftType, rightType); - } - if ((leftType->IsETSStringEnumType() && rightType->IsETSStringType()) || - (leftType->IsETSStringType() && rightType->IsETSStringEnumType())) { - return true; - } - if ((leftType->IsETSPrimitiveType() && rightType->IsETSIntEnumType()) || - (leftType->IsETSIntEnumType() && rightType->IsETSPrimitiveType())) { - return true; - } - return false; -} - std::tuple ETSChecker::CheckBinaryOperatorLessGreater(ir::Expression *left, ir::Expression *right, lexer::TokenType operationType, lexer::SourcePosition pos, bool isEqualOp, diff --git a/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp b/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp index 9d109667b1..9f98544c4d 100644 --- a/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp @@ -1204,6 +1204,7 @@ static varbinder::Variable *ResolveMemberExpressionProperty(ir::MemberExpression } auto decl = var->Declaration(); + varbinder::LocalScope *scope = nullptr; if (decl->IsClassDecl()) { // NOTE(gogabr) : for some reason, ETSGLOBAL points to class declaration instead of definition. auto *declNode = decl->AsClassDecl()->Node(); @@ -1211,17 +1212,16 @@ static varbinder::Variable *ResolveMemberExpressionProperty(ir::MemberExpression : declNode->IsClassDeclaration() ? declNode->AsClassDeclaration()->Definition() : nullptr; ES2PANDA_ASSERT(classDef != nullptr); - - // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) - auto scope = classDef->Scope(); - auto option = var->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE_OR_ENUM) - ? varbinder::ResolveBindingOptions::STATIC_DECLARATION | - varbinder::ResolveBindingOptions::STATIC_VARIABLES - : varbinder::ResolveBindingOptions::DECLARATION | varbinder::ResolveBindingOptions::VARIABLES; - return scope->FindLocal(me->Property()->AsIdentifier()->Name(), option); + scope = classDef->Scope(); + } else if (decl->IsEnumLiteralDecl()) { + scope = decl->AsEnumLiteralDecl()->Node()->AsTSEnumDeclaration()->Scope(); + } else { + return nullptr; } - return nullptr; + auto option = + varbinder::ResolveBindingOptions::STATIC_DECLARATION | varbinder::ResolveBindingOptions::STATIC_VARIABLES; + return scope->FindLocal(me->Property()->AsIdentifier()->Name(), option); } static bool IsConstantExpression(ir::AstNode *expr) @@ -1262,6 +1262,18 @@ static bool IsConstantExpression(ir::AstNode *expr) !expr->IsAnyChild(isNotConstantExpression); } +static bool IsInTSEnumMemberInit(const ir::AstNode *node) +{ + auto enumMember = util::Helpers::FindAncestorGivenByType(node, ir::AstNodeType::TS_ENUM_MEMBER); + + if (enumMember == nullptr) { + return false; + } + + auto init = enumMember->AsTSEnumMember()->Init(); + return (init == node) || (init->FindChild([node](auto *n) -> bool { return n == node; }) != nullptr); +} + ir::AstNode *ConstantExpressionLowering::UnfoldResolvedReference(ir::AstNode *resolved, ir::AstNode *node) { ir::AstNode *resNode = nullptr; @@ -1277,6 +1289,12 @@ ir::AstNode *ConstantExpressionLowering::UnfoldResolvedReference(ir::AstNode *re resNode = init->Clone(context_->allocator, node->Parent()); resNode->SetRange(node->Range()); } + } else if (resolved->IsTSEnumMember() && IsInTSEnumMemberInit(node)) { + auto init = resolved->AsTSEnumMember()->Init(); + if (init != nullptr) { + resNode = init->Clone(context_->allocator, node->Parent()); + resNode->SetRange(node->Range()); + } } if (resNode != nullptr) { @@ -1294,7 +1312,7 @@ ir::AstNode *ConstantExpressionLowering::MaybeUnfoldIdentifier(ir::Identifier *n } auto *resolved = ResolveIdentifier(node); - if (resolved == nullptr || !resolved->Declaration()->IsConstDecl()) { + if (resolved == nullptr || !(resolved->Declaration()->IsConstDecl() || resolved->Declaration()->IsReadonlyDecl())) { return node; } return UnfoldResolvedReference(resolved->Declaration()->Node(), node); @@ -1306,12 +1324,6 @@ ir::AstNode *ConstantExpressionLowering::MaybeUnfoldMemberExpression(ir::MemberE return node; } - if (auto *const property = node->Property(); property->IsLiteral()) { - property->SetParent(node->Parent()); - property->SetRange(node->Range()); - return property; - } - auto resolved = ResolveMemberExpressionProperty(node); if (resolved == nullptr || !resolved->Declaration()->IsReadonlyDecl()) { return node; @@ -1322,7 +1334,7 @@ ir::AstNode *ConstantExpressionLowering::MaybeUnfoldMemberExpression(ir::MemberE ir::AstNode *ConstantExpressionLowering::MaybeUnfold(ir::AstNode *node) { ir::NodeTransformer handleMaybeUnfold = [this](ir::AstNode *const n) { - if (n->IsIdentifier()) { + if (n->IsIdentifier() && !n->Parent()->IsMemberExpression()) { return MaybeUnfoldIdentifier(n->AsIdentifier()); } @@ -1378,7 +1390,6 @@ ir::AstNode *ConstantExpressionLowering::Fold(ir::AstNode *constantNode) } return node; }; - constantNode->TransformChildrenRecursivelyPostorder(handleFoldConstant, Name()); return TryToCorrectNumberOrCharLiteral(handleFoldConstant(constantNode), context_); } diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 49bec80f6e..759f49ffa9 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -1074,7 +1074,7 @@ void InitScopesPhaseETS::VisitTSEnumMember(ir::TSEnumMember *enumMember) if (var = VarBinder()->GetScope()->FindLocal(name, varbinder::ResolveBindingOptions::STATIC_VARIABLES); var == nullptr) { varbinder::Decl *decl = nullptr; - std::tie(decl, var) = VarBinder()->NewVarDecl(ident->Start(), name); + std::tie(decl, var) = VarBinder()->NewVarDecl(ident->Start(), name); var->SetScope(VarBinder()->GetScope()); var->AddFlag(varbinder::VariableFlags::STATIC); decl->BindNode(enumMember); -- Gitee