* Copyright (c) 2024-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "insertOptionalParametersAnnotation.h"
#include "compiler/lowering/util.h"
namespace ark::es2panda::compiler {
using UAlloc = util::NodeAllocator;
static ir::Identifier *GenAnnoQualifiedLeft(ArenaAllocator *allocator)
{
return UAlloc::ForceSetParent<ir::Identifier>(
allocator,
util::UString(std::string(ARKRUNTIME_IMPORT_ALIAS_PREFIX) + std::string("annotation"), allocator).View(),
allocator);
}
static ir::Identifier *GenDefaultAnnoId(ArenaAllocator *allocator)
{
return UAlloc::ForceSetParent<ir::Identifier>(allocator, Signatures::DEFAULT_ANNO_FOR_FUNC, allocator);
}
static ir::Identifier *GenDefaultPropId(ArenaAllocator *allocator, util::StringView const name)
{
return UAlloc::ForceSetParent<ir::Identifier>(allocator, name, allocator);
}
static ir::ETSTypeReference *GenDefaultAnnoNameRef(ArenaAllocator *allocator)
{
auto defaultQualifiedAnnoName = UAlloc::ForceSetParent<ir::TSQualifiedName>(
allocator, GenAnnoQualifiedLeft(allocator), GenDefaultAnnoId(allocator), allocator);
auto defaultRefPart = UAlloc::ForceSetParent<ir::ETSTypeReferencePart>(allocator, defaultQualifiedAnnoName, nullptr,
nullptr, allocator);
auto defaultRef = UAlloc::ForceSetParent<ir::ETSTypeReference>(allocator, defaultRefPart, allocator);
return defaultRef;
}
static ir::AstNode *GenMinArgCountItem(ArenaAllocator *allocator, const int32_t requiredArgs)
{
auto *minArgsCountId = GenDefaultPropId(allocator, Signatures::MIN_ARGSCOUNT_OF_FUNC);
auto *minArgsCountValue = UAlloc::ForceSetParent<ir::NumberLiteral>(allocator, lexer::Number(requiredArgs));
auto *minArgsCount = UAlloc::ForceSetParent<ir::ClassProperty>(
allocator, minArgsCountId, minArgsCountValue, nullptr, ir::ModifierFlags::ANNOTATION_USAGE, allocator, false);
return minArgsCount;
}
static ir::AstNode *CreateDefaultAnnotationUsageForFunction(public_lib::Context *ctx, const ir::ScriptFunction *func)
{
auto allocator = ctx->allocator;
int32_t requiredArgsCnt = 0;
bool needInsert = false;
for (auto const param : func->Params()) {
if (!param->IsETSParameterExpression()) {
ES2PANDA_ASSERT(param->IsIdentifier() && param->AsIdentifier()->IsErrorPlaceHolder());
return nullptr;
}
if (param->AsETSParameterExpression()->IsOptional() || param->AsETSParameterExpression()->IsRestParameter()) {
needInsert = param->AsETSParameterExpression()->IsOptional();
break;
}
++requiredArgsCnt;
}
if (!needInsert) {
return nullptr;
}
ir::ETSTypeReference *defaultRef = GenDefaultAnnoNameRef(allocator);
auto *minArgsCount = GenMinArgCountItem(allocator, requiredArgsCnt);
ArenaVector<ir::AstNode *> properties(allocator->Adapter());
properties.emplace_back(minArgsCount);
return util::NodeAllocator::ForceSetParent<ir::AnnotationUsage>(allocator, defaultRef, std::move(properties));
}
static void TryInsertDefaultAnnotation(public_lib::Context *ctx, ir::AstNode *node)
{
if (!node->IsMethodDefinition()) {
return;
}
auto methodDef = node->AsMethodDefinition();
if (!methodDef->IsConstructor() && !methodDef->IsAbstract() && methodDef->Function() != nullptr) {
auto methodFunc = methodDef->Function();
auto defaultAnno = CreateDefaultAnnotationUsageForFunction(ctx, methodFunc);
if (defaultAnno != nullptr) {
methodFunc->EmplaceAnnotation(defaultAnno->AsAnnotationUsage());
defaultAnno->SetParent(methodFunc);
RefineSourceRanges(defaultAnno);
}
}
}
bool InsertOptionalParametersAnnotation::PerformForProgram(parser::Program *program)
{
if (program->Extension() != ScriptExtension::ETS) {
return true;
}
program->Ast()->IterateRecursivelyPostorder(
[ctx = Context()](ir::AstNode *node) -> void { TryInsertDefaultAnnotation(ctx, node); });
return true;
}
}