/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you 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 .
*/
#include <sal/config.h>
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <map>
#include <memory>
#include <set>
#include <string_view>
#include <utility>
#include <vector>
#include <codemaker/codemaker.hxx>
#include <codemaker/exceptiontree.hxx>
#include <codemaker/generatedtypeset.hxx>
#include <codemaker/global.hxx>
#include <codemaker/options.hxx>
#include <codemaker/typemanager.hxx>
#include <codemaker/unotype.hxx>
#include <codemaker/commonjava.hxx>
#include <rtl/ref.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/string.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/ustring.hxx>
#include <sal/types.h>
#include <unoidl/unoidl.hxx>
#include <o3tl/string_view.hxx>
#include "classfile.hxx"
#include "javaoptions.hxx"
#include "javatype.hxx"
using codemaker::javamaker::ClassFile;
namespace {
void appendUnoName(
rtl::Reference< TypeManager > const & manager, std::u16string_view nucleus,
sal_Int32 rank, std::vector< OUString > const & arguments,
OUStringBuffer * buffer)
{
assert(manager.is());
assert(rank >= 0);
assert(buffer != nullptr);
for (sal_Int32 i = 0; i != rank; ++i) {
buffer->append("[]");
}
buffer->append(nucleus);
if (arguments.empty())
return;
buffer->append('<');
for (std::vector< OUString >::const_iterator i(arguments.begin());
i != arguments.end(); ++i)
{
if (i != arguments.begin()) {
buffer->append(',');
}
OUString n;
sal_Int32 k;
std::vector< OUString > args;
manager->decompose(*i, false, &n, &k, &args, nullptr);
appendUnoName(manager, n, k, args, buffer);
}
buffer->append('>');
}
// Translate the name of a UNOIDL entity (enum type, plain struct type,
// polymorphic struct type template, or interface type, decomposed into nucleus,
// sequence rank, and template arguments) into a core UNO type name:
OUString createUnoName(
rtl::Reference< TypeManager > const & manager, std::u16string_view nucleus,
sal_Int32 rank, std::vector< OUString > const & arguments)
{
OUStringBuffer buf(256);
appendUnoName(manager, nucleus, rank, arguments, &buf);
return buf.makeStringAndClear();
}
enum SpecialType {
SPECIAL_TYPE_NONE,
SPECIAL_TYPE_ANY,
SPECIAL_TYPE_UNSIGNED,
SPECIAL_TYPE_INTERFACE
};
bool isSpecialType(SpecialType special) {
return special >= SPECIAL_TYPE_UNSIGNED;
}
OString translateUnoidlEntityNameToJavaFullyQualifiedName(
std::u16string_view name, std::string_view prefix)
{
assert(!o3tl::starts_with(name, u"[]"));
assert(name.find('<') == std::string_view::npos);
size_t i = name.rfind('.');
if (i == std::string_view::npos)
i = 0;
else
++i;
return codemaker::convertString(OUString(name.substr(0, i))).replace('.', '/')
+ codemaker::java::translateUnoToJavaIdentifier(
codemaker::convertString(OUString(name.substr(i))), prefix);
}
struct PolymorphicUnoType {
PolymorphicUnoType(): kind(KIND_NONE) {}
enum Kind { KIND_NONE, KIND_STRUCT, KIND_SEQUENCE };
Kind kind;
OUString name;
};
SpecialType translateUnoTypeToDescriptor(
rtl::Reference< TypeManager > const & manager, std::u16string_view type,
bool array, bool classType, std::set<OUString> * dependencies,
OStringBuffer * descriptor, OStringBuffer * signature,
bool * needsSignature, PolymorphicUnoType * polymorphicUnoType);
SpecialType translateUnoTypeToDescriptor(
rtl::Reference< TypeManager > const & manager,
codemaker::UnoType::Sort sort, OUString const & nucleus, sal_Int32 rank,
std::vector< OUString > const & arguments, bool array, bool classType,
std::set<OUString> * dependencies, OStringBuffer * descriptor,
OStringBuffer * signature, bool * needsSignature,
PolymorphicUnoType * polymorphicUnoType)
{
assert(rank >= 0);
assert((signature == nullptr) == (needsSignature == nullptr));
assert(
arguments.empty()
== (sort
!= codemaker::UnoType::Sort::InstantiatedPolymorphicStruct));
if (rank > 0xFF - (array ? 1 : 0)) {
throw CannotDumpException(
u"Too many array dimensions for Java class file format"_ustr);
}
if (array) {
++rank;
}
for (sal_Int32 i = 0; i != rank; ++i) {
if (descriptor != nullptr) {
descriptor->append('[');
}
if (signature != nullptr) {
signature->append('[');
}
}
if (polymorphicUnoType != nullptr) {
if (sort
== codemaker::UnoType::Sort::InstantiatedPolymorphicStruct)
{
polymorphicUnoType->kind = rank == 0
? PolymorphicUnoType::KIND_STRUCT
: PolymorphicUnoType::KIND_SEQUENCE;
polymorphicUnoType->name = createUnoName(
manager, nucleus, rank, arguments);
} else {
polymorphicUnoType->kind = PolymorphicUnoType::KIND_NONE;
}
}
switch (sort) {
case codemaker::UnoType::Sort::Void:
case codemaker::UnoType::Sort::Boolean:
case codemaker::UnoType::Sort::Byte:
case codemaker::UnoType::Sort::Short:
case codemaker::UnoType::Sort::UnsignedShort:
case codemaker::UnoType::Sort::Long:
case codemaker::UnoType::Sort::UnsignedLong:
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
case codemaker::UnoType::Sort::Float:
case codemaker::UnoType::Sort::Double:
case codemaker::UnoType::Sort::Char:
case codemaker::UnoType::Sort::String:
case codemaker::UnoType::Sort::Type:
case codemaker::UnoType::Sort::Any:
{
static char const * const
simpleTypeDescriptors[static_cast<int>(codemaker::UnoType::Sort::Any) + 1][2] = {
{ "V", "Ljava/lang/Void;" },
{ "Z", "Ljava/lang/Boolean;" },
{ "B", "Ljava/lang/Byte;" },
{ "S", "Ljava/lang/Short;" },
{ "S", "Ljava/lang/Short;" },
{ "I", "Ljava/lang/Integer;" },
{ "I", "Ljava/lang/Integer;" },
{ "J", "Ljava/lang/Long;" },
{ "J", "Ljava/lang/Long;" },
{ "F", "Ljava/lang/Float;" },
{ "D", "Ljava/lang/Double;" },
{ "C", "Ljava/lang/Character;" },
{ "Ljava/lang/String;", "Ljava/lang/String;" },
{ "Lcom/sun/star/uno/Type;", "Lcom/sun/star/uno/Type;" },
{ "Ljava/lang/Object;", "Ljava/lang/Object;" } };
char const * s
= simpleTypeDescriptors[static_cast<int>(sort)][rank == 0 && classType];
if (descriptor != nullptr) {
descriptor->append(s);
}
if (signature != nullptr) {
signature->append(s);
}
static SpecialType const
simpleTypeSpecials[static_cast<int>(codemaker::UnoType::Sort::Any) + 1] = {
SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE,
SPECIAL_TYPE_NONE, SPECIAL_TYPE_UNSIGNED, SPECIAL_TYPE_NONE,
SPECIAL_TYPE_UNSIGNED, SPECIAL_TYPE_NONE, SPECIAL_TYPE_UNSIGNED,
SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE,
SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, SPECIAL_TYPE_ANY };
return simpleTypeSpecials[static_cast<int>(sort)];
}
case codemaker::UnoType::Sort::Interface:
if (nucleus == "com.sun.star.uno.XInterface") {
if (descriptor != nullptr) {
descriptor->append("Ljava/lang/Object;");
}
if (signature != nullptr) {
signature->append("Ljava/lang/Object;");
}
return SPECIAL_TYPE_INTERFACE;
}
[[fallthrough]];
case codemaker::UnoType::Sort::Sequence:
case codemaker::UnoType::Sort::Enum:
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
if (dependencies != nullptr) {
dependencies->insert(nucleus);
}
if (descriptor != nullptr) {
descriptor->append(
"L" + codemaker::convertString(nucleus).replace('.', '/')
+ ";");
}
if (signature != nullptr) {
signature->append(
"L" + codemaker::convertString(nucleus).replace('.', '/'));
if (!arguments.empty()) {
signature->append('<');
for (const OUString& arg : arguments)
{
translateUnoTypeToDescriptor(
manager, arg, false, true, dependencies, nullptr, signature,
needsSignature, nullptr);
}
signature->append('>');
*needsSignature = true;
}
signature->append(';');
}
return SPECIAL_TYPE_NONE;
default:
throw CannotDumpException(
"unexpected nucleus \"" + nucleus
+ "\" in call to translateUnoTypeToDescriptor");
}
}
SpecialType translateUnoTypeToDescriptor(
rtl::Reference< TypeManager > const & manager, std::u16string_view type,
bool array, bool classType, std::set<OUString> * dependencies,
OStringBuffer * descriptor, OStringBuffer * signature,
bool * needsSignature, PolymorphicUnoType * polymorphicUnoType)
{
assert(manager.is());
OUString nucleus;
sal_Int32 rank;
std::vector< OUString > args;
codemaker::UnoType::Sort sort = manager->decompose(
type, true, &nucleus, &rank, &args, nullptr);
return translateUnoTypeToDescriptor(
manager, sort, nucleus, rank, args, array, classType, dependencies,
descriptor, signature, needsSignature, polymorphicUnoType);
}
SpecialType getFieldDescriptor(
rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies,
std::u16string_view type, OString * descriptor, OString * signature,
PolymorphicUnoType * polymorphicUnoType)
{
assert(descriptor != nullptr);
OStringBuffer desc(64);
OStringBuffer sig(64);
bool needsSig = false;
SpecialType specialType = translateUnoTypeToDescriptor(
manager, type, false, false, dependencies, &desc, &sig, &needsSig,
polymorphicUnoType);
*descriptor = desc.makeStringAndClear();
if (signature != nullptr) {
if (needsSig) {
*signature = sig.makeStringAndClear();
} else {
signature->clear();
}
}
return specialType;
}
class MethodDescriptor {
public:
MethodDescriptor(
rtl::Reference< TypeManager > manager,
std::set<OUString> * dependencies, std::u16string_view returnType,
SpecialType * specialReturnType,
PolymorphicUnoType * polymorphicUnoType);
SpecialType addParameter(
std::u16string_view type, bool array, bool dependency,
PolymorphicUnoType * polymorphicUnoType);
void addTypeParameter(OUString const & name);
OString getDescriptor() const;
OString getSignature() const { return m_needsSignature ? m_signatureStart + m_signatureEnd : OString();}
private:
rtl::Reference< TypeManager > m_manager;
std::set<OUString> * m_dependencies;
OStringBuffer m_descriptorStart{16*1024};
OString m_descriptorEnd;
OStringBuffer m_signatureStart{16*1024};
OString m_signatureEnd;
bool m_needsSignature;
};
MethodDescriptor::MethodDescriptor(
rtl::Reference< TypeManager > manager, std::set<OUString> * dependencies,
std::u16string_view returnType, SpecialType * specialReturnType,
PolymorphicUnoType * polymorphicUnoType):
m_manager(std::move(manager)), m_dependencies(dependencies), m_needsSignature(false)
{
assert(dependencies != nullptr);
m_descriptorStart.append('(');
m_signatureStart.append('(');
OStringBuffer descEnd(128);
descEnd.append(')');
OStringBuffer sigEnd(128);
sigEnd.append(')');
SpecialType special = translateUnoTypeToDescriptor(
m_manager, returnType, false, false, m_dependencies, &descEnd, &sigEnd,
&m_needsSignature, polymorphicUnoType);
m_descriptorEnd = descEnd.makeStringAndClear();
m_signatureEnd = sigEnd.makeStringAndClear();
if (specialReturnType != nullptr) {
*specialReturnType = special;
}
}
SpecialType MethodDescriptor::addParameter(
std::u16string_view type, bool array, bool dependency,
PolymorphicUnoType * polymorphicUnoType)
{
return translateUnoTypeToDescriptor(
m_manager, type, array, false, dependency ? m_dependencies : nullptr,
&m_descriptorStart, &m_signatureStart, &m_needsSignature,
polymorphicUnoType);
}
void MethodDescriptor::addTypeParameter(OUString const & name) {
m_descriptorStart.append("Ljava/lang/Object;");
m_signatureStart.append("T" + codemaker::convertString(name) + ";");
m_needsSignature = true;
}
OString MethodDescriptor::getDescriptor() const {
return m_descriptorStart + m_descriptorEnd;
}
class TypeInfo {
public:
enum Kind { KIND_MEMBER, KIND_ATTRIBUTE, KIND_METHOD, KIND_PARAMETER };
// Same values as in com/sun/star/lib/uno/typeinfo/TypeInfo.java:
enum Flags {
FLAG_READONLY = 0x008, FLAG_BOUND = 0x100
};
// KIND_MEMBER:
TypeInfo(
OString name, SpecialType specialType, sal_Int32 index,
PolymorphicUnoType const & polymorphicUnoType,
sal_Int32 typeParameterIndex);
// KIND_ATTRIBUTE/METHOD:
TypeInfo(
Kind kind, OString name, SpecialType specialType, Flags flags,
sal_Int32 index, PolymorphicUnoType polymorphicUnoType);
// KIND_PARAMETER:
TypeInfo(
OString parameterName, SpecialType specialType,
bool inParameter, bool outParameter, OString methodName,
sal_Int32 index, PolymorphicUnoType polymorphicUnoType);
sal_uInt16 generateCode(ClassFile::Code & code, std::set<OUString> * dependencies)
const;
void generatePolymorphicUnoTypeCode(
ClassFile::Code & code, std::set<OUString> * dependencies) const;
private:
Kind m_kind;
OString m_name;
sal_Int32 m_flags;
sal_Int32 m_index;
OString m_methodName;
PolymorphicUnoType m_polymorphicUnoType;
sal_Int32 m_typeParameterIndex;
};
sal_Int32 translateSpecialTypeFlags(
SpecialType specialType, bool inParameter, bool outParameter)
{
static sal_Int32 const specialTypeFlags[SPECIAL_TYPE_INTERFACE + 1] = {
0, 0x0040 /* ANY */, 0x0004 /* UNSIGNED */, 0x0080 /* INTERFACE */ };
sal_Int32 flags = specialTypeFlags[specialType];
if (inParameter) {
flags |= 0x0001; /* IN */
}
if (outParameter) {
flags |= 0x0002; /* OUT */
}
return flags;
}
TypeInfo::TypeInfo(
OString name, SpecialType specialType, sal_Int32 index,
PolymorphicUnoType const & polymorphicUnoType,
sal_Int32 typeParameterIndex):
m_kind(KIND_MEMBER), m_name(std::move(name)),
m_flags(translateSpecialTypeFlags(specialType, false, false)),
m_index(index), m_polymorphicUnoType(polymorphicUnoType),
m_typeParameterIndex(typeParameterIndex)
{
assert(
polymorphicUnoType.kind == PolymorphicUnoType::KIND_NONE
? typeParameterIndex >= -1 : typeParameterIndex == -1);
}
TypeInfo::TypeInfo(
Kind kind, OString name, SpecialType specialType, Flags flags,
sal_Int32 index, PolymorphicUnoType polymorphicUnoType):
m_kind(kind), m_name(std::move(name)),
m_flags(flags | translateSpecialTypeFlags(specialType, false, false)),
m_index(index), m_polymorphicUnoType(std::move(polymorphicUnoType)),
m_typeParameterIndex(0)
{
assert(kind == KIND_ATTRIBUTE || kind == KIND_METHOD);
}
TypeInfo::TypeInfo(
OString parameterName, SpecialType specialType, bool inParameter,
bool outParameter, OString methodName, sal_Int32 index,
PolymorphicUnoType polymorphicUnoType):
m_kind(KIND_PARAMETER), m_name(std::move(parameterName)),
m_flags(translateSpecialTypeFlags(specialType, inParameter, outParameter)),
m_index(index), m_methodName(std::move(methodName)),
m_polymorphicUnoType(std::move(polymorphicUnoType)),
m_typeParameterIndex(0)
{}
sal_uInt16 TypeInfo::generateCode(
ClassFile::Code & code, std::set<OUString> * dependencies) const
{
switch (m_kind) {
case KIND_MEMBER:
code.instrNew("com/sun/star/lib/uno/typeinfo/MemberTypeInfo"_ostr);
code.instrDup();
code.loadStringConstant(m_name);
code.loadIntegerConstant(m_index);
code.loadIntegerConstant(m_flags);
if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) {
generatePolymorphicUnoTypeCode(code, dependencies);
code.loadIntegerConstant(m_typeParameterIndex);
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/MemberTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;IILcom/sun/star/uno/Type;I)V"_ostr);
return 8;
} else if (m_typeParameterIndex >= 0) {
code.instrAconstNull();
code.loadIntegerConstant(m_typeParameterIndex);
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/MemberTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;IILcom/sun/star/uno/Type;I)V"_ostr);
return 6;
} else {
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/MemberTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;II)V"_ostr);
return 4;
}
case KIND_ATTRIBUTE:
code.instrNew("com/sun/star/lib/uno/typeinfo/AttributeTypeInfo"_ostr);
code.instrDup();
code.loadStringConstant(m_name);
code.loadIntegerConstant(m_index);
code.loadIntegerConstant(m_flags);
if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) {
generatePolymorphicUnoTypeCode(code, dependencies);
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/AttributeTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;IILcom/sun/star/uno/Type;)V"_ostr);
return 8;
} else {
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/AttributeTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;II)V"_ostr);
return 4;
}
case KIND_METHOD:
code.instrNew("com/sun/star/lib/uno/typeinfo/MethodTypeInfo"_ostr);
code.instrDup();
code.loadStringConstant(m_name);
code.loadIntegerConstant(m_index);
code.loadIntegerConstant(m_flags);
if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) {
generatePolymorphicUnoTypeCode(code, dependencies);
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/MethodTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;IILcom/sun/star/uno/Type;)V"_ostr);
return 8;
} else {
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/MethodTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;II)V"_ostr);
return 4;
}
case KIND_PARAMETER:
code.instrNew("com/sun/star/lib/uno/typeinfo/ParameterTypeInfo"_ostr);
code.instrDup();
code.loadStringConstant(m_name);
code.loadStringConstant(m_methodName);
code.loadIntegerConstant(m_index);
code.loadIntegerConstant(m_flags);
if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) {
generatePolymorphicUnoTypeCode(code, dependencies);
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/ParameterTypeInfo"_ostr, "<init>"_ostr,
("(Ljava/lang/String;Ljava/lang/String;II"
"Lcom/sun/star/uno/Type;)V"_ostr));
return 9;
} else {
code.instrInvokespecial(
"com/sun/star/lib/uno/typeinfo/ParameterTypeInfo"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Ljava/lang/String;II)V"_ostr);
return 5;
}
default:
assert(false);
return 0;
}
}
void TypeInfo::generatePolymorphicUnoTypeCode(
ClassFile::Code & code, std::set<OUString> * dependencies) const
{
assert(dependencies != nullptr);
assert(m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE);
code.instrNew("com/sun/star/uno/Type"_ostr);
code.instrDup();
code.loadStringConstant(
codemaker::convertString(m_polymorphicUnoType.name));
if (m_polymorphicUnoType.kind == PolymorphicUnoType::KIND_STRUCT) {
code.instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "STRUCT"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
} else {
code.instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "SEQUENCE"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
}
dependencies->insert(u"com.sun.star.uno.TypeClass"_ustr);
code.instrInvokespecial(
"com/sun/star/uno/Type"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"_ostr);
}
void writeClassFile(
JavaOptions const & options, OString const & type,
ClassFile const & classFile)
{
OString path;
if (options.isValid("-O"_ostr)) {
path = options.getOption("-O"_ostr);
}
OString filename(createFileNameFromType(path, type, ".class"_ostr));
bool bCheck = false;
if (fileExists(filename)) {
if (options.isValid("-G"_ostr)) {
return;
}
bCheck = options.isValid("-Gc"_ostr);
}
FileStream tempfile;
tempfile.createTempFile(getTempDir(filename));
if (!tempfile.isValid()) {
throw CannotDumpException(
"Cannot create temporary file for " + b2u(filename));
}
OString tempname(tempfile.getName());
try {
classFile.write(tempfile);
} catch (...) {
// Remove existing file for consistency:
if (fileExists(filename)) {
removeTypeFile(filename);
}
tempfile.close();
removeTypeFile(tempname);
throw;
}
tempfile.close();
if (!makeValidTypeFile(filename, tempname, bCheck)) {
throw CannotDumpException(
"Cannot create " + b2u(filename) + " from temporary file "
+ b2u(tempname));
}
}
void addTypeInfo(
OString const & className, std::vector< TypeInfo > const & typeInfo,
std::set<OUString> * dependencies, ClassFile * classFile)
{
assert(classFile != nullptr);
std::vector< TypeInfo >::size_type typeInfos = typeInfo.size();
if (typeInfos > SAL_MAX_INT32) {
throw CannotDumpException(
u"UNOTYPEINFO array too big for Java class file format"_ustr);
}
if (typeInfos == 0)
return;
classFile->addField(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC
| ClassFile::ACC_FINAL),
"UNOTYPEINFO"_ostr, "[Lcom/sun/star/lib/uno/typeinfo/TypeInfo;"_ostr,
0, ""_ostr);
std::unique_ptr< ClassFile::Code > code(classFile->newCode());
code->loadIntegerConstant(static_cast< sal_Int32 >(typeInfos));
code->instrAnewarray("com/sun/star/lib/uno/typeinfo/TypeInfo"_ostr);
sal_Int32 index = 0;
sal_uInt16 stack = 0;
for (const TypeInfo& ti : typeInfo)
{
code->instrDup();
code->loadIntegerConstant(index++);
stack = std::max(stack, ti.generateCode(*code, dependencies));
code->instrAastore();
}
code->instrPutstatic(
className, "UNOTYPEINFO"_ostr,
"[Lcom/sun/star/lib/uno/typeinfo/TypeInfo;"_ostr);
code->instrReturn();
if (stack > SAL_MAX_UINT16 - 4) {
throw CannotDumpException(
u"Stack too big for Java class file format"_ustr);
}
code->setMaxStackAndLocals(static_cast< sal_uInt16 >(stack + 4), 0);
classFile->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC),
"<clinit>"_ostr, "()V"_ostr, code.get(), std::vector< OString >(), ""_ostr);
}
void handleEnumType(
const OUString& name, rtl::Reference< unoidl::EnumTypeEntity > const & entity,
JavaOptions const & options)
{
assert(entity.is());
OString className(codemaker::convertString(name).replace('.', '/'));
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL
| ClassFile::ACC_SUPER),
className, "com/sun/star/uno/Enum"_ostr, ""_ostr));
OString classDescriptor("L" + className + ";");
for (const unoidl::EnumTypeEntity::Member& member : entity->getMembers())
{
OString fieldName(codemaker::convertString(member.name));
cf->addField(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC
| ClassFile::ACC_FINAL),
fieldName, classDescriptor, 0, OString());
cf->addField(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC
| ClassFile::ACC_FINAL),
fieldName + "_value", "I"_ostr,
cf->addIntegerInfo(member.value), ""_ostr);
}
std::unique_ptr< ClassFile::Code > code(cf->newCode());
code->loadLocalReference(0);
code->loadLocalInteger(1);
code->instrInvokespecial("com/sun/star/uno/Enum"_ostr, "<init>"_ostr, "(I)V"_ostr);
code->instrReturn();
code->setMaxStackAndLocals(2, 2);
cf->addMethod(
ClassFile::ACC_PRIVATE,
"<init>"_ostr, "(I)V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
code = cf->newCode();
code->instrGetstatic(
className,
codemaker::convertString(entity->getMembers()[0].name),
classDescriptor);
code->instrAreturn();
code->setMaxStackAndLocals(1, 0);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC),
"getDefault"_ostr, "()" + classDescriptor,
code.get(), std::vector< OString >(), ""_ostr);
code = cf->newCode();
code->loadLocalInteger(0);
std::map< sal_Int32, OString > map;
sal_Int32 min = SAL_MAX_INT32;
sal_Int32 max = SAL_MIN_INT32;
for (const unoidl::EnumTypeEntity::Member& member : entity->getMembers())
{
min = std::min(min, member.value);
max = std::max(max, member.value);
map.emplace(member.value, codemaker::convertString(member.name));
}
sal_uInt64 size = static_cast< sal_uInt64 >(map.size());
if ((static_cast< sal_uInt64 >(max) - static_cast< sal_uInt64 >(min)
<= 2 * size)
|| size > SAL_MAX_INT32)
{
std::unique_ptr< ClassFile::Code > defCode(cf->newCode());
defCode->instrAconstNull();
defCode->instrAreturn();
std::vector< std::unique_ptr<ClassFile::Code> > blocks;
//FIXME: pointers contained in blocks may leak
sal_Int32 last = SAL_MAX_INT32;
for (const auto& pair : map)
{
sal_Int32 value = pair.first;
if (last != SAL_MAX_INT32) {
for (sal_Int32 j = last + 1; j < value; ++j) {
blocks.push_back(nullptr);
}
}
last = value;
std::unique_ptr< ClassFile::Code > blockCode(cf->newCode());
blockCode->instrGetstatic(className, pair.second, classDescriptor);
blockCode->instrAreturn();
blocks.push_back(std::move(blockCode));
}
code->instrTableswitch(defCode.get(), min, blocks);
} else{
std::unique_ptr< ClassFile::Code > defCode(cf->newCode());
defCode->instrAconstNull();
defCode->instrAreturn();
std::vector< std::pair< sal_Int32, ClassFile::Code * > > blocks;
//FIXME: pointers contained in blocks may leak
for (const auto& pair : map )
{
std::unique_ptr< ClassFile::Code > blockCode(cf->newCode());
blockCode->instrGetstatic(className, pair.second, classDescriptor);
blockCode->instrAreturn();
blocks.emplace_back(pair.first, blockCode.release());
}
code->instrLookupswitch(defCode.get(), blocks);
for (const std::pair< sal_Int32, ClassFile::Code * >& pair : blocks)
{
delete pair.second;
}
}
code->setMaxStackAndLocals(1, 1);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC),
"fromInt"_ostr, "(I)" + classDescriptor, code.get(),
std::vector< OString >(), ""_ostr);
code = cf->newCode();
for (const unoidl::EnumTypeEntity::Member& member : entity->getMembers())
{
code->instrNew(className);
code->instrDup();
code->loadIntegerConstant(member.value);
code->instrInvokespecial(className, "<init>"_ostr, "(I)V"_ostr);
code->instrPutstatic(
className, codemaker::convertString(member.name), classDescriptor);
}
code->instrReturn();
code->setMaxStackAndLocals(3, 0);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC),
"<clinit>"_ostr, "()V"_ostr, code.get(), std::vector< OString >(), ""_ostr);
writeClassFile(options, className, *cf);
}
void addField(
rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies,
ClassFile * classFile, std::vector< TypeInfo > * typeInfo,
sal_Int32 typeParameterIndex, OUString const & type, OUString const & name,
sal_Int32 index)
{
assert(classFile != nullptr);
assert(typeInfo != nullptr);
OString descriptor;
OString signature;
SpecialType specialType;
PolymorphicUnoType polymorphicUnoType;
if (typeParameterIndex >= 0) {
descriptor = "Ljava/lang/Object;"_ostr;
signature = "T" + codemaker::convertString(type).replace('.', '/')
+ ";";
specialType = SPECIAL_TYPE_NONE; //TODO: SPECIAL_TYPE_TYPE_PARAMETER?
} else {
specialType = getFieldDescriptor(
manager, dependencies, type, &descriptor, &signature,
&polymorphicUnoType);
}
classFile->addField(
ClassFile::ACC_PUBLIC, codemaker::convertString(name), descriptor, 0,
signature);
typeInfo->push_back(
TypeInfo(
codemaker::convertString(name), specialType, index,
polymorphicUnoType, typeParameterIndex));
}
sal_uInt16 addFieldInit(
rtl::Reference< TypeManager > const & manager, OString const & className,
OUString const & fieldName, bool typeParameter, std::u16string_view fieldType,
std::set<OUString> * dependencies, ClassFile::Code * code)
{
assert(manager.is());
assert(code != nullptr);
if (typeParameter) {
return 0;
}
OString name(codemaker::convertString(fieldName));
OUString nucleus;
sal_Int32 rank;
std::vector< OUString > args;
rtl::Reference< unoidl::Entity > ent;
codemaker::UnoType::Sort sort = manager->decompose(
fieldType, true, &nucleus, &rank, &args, &ent);
if (rank == 0) {
switch (sort) {
case codemaker::UnoType::Sort::Boolean:
case codemaker::UnoType::Sort::Byte:
case codemaker::UnoType::Sort::Short:
case codemaker::UnoType::Sort::UnsignedShort:
case codemaker::UnoType::Sort::Long:
case codemaker::UnoType::Sort::UnsignedLong:
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
case codemaker::UnoType::Sort::Float:
case codemaker::UnoType::Sort::Double:
case codemaker::UnoType::Sort::Char:
case codemaker::UnoType::Sort::Interface:
return 0;
case codemaker::UnoType::Sort::String:
code->loadLocalReference(0);
code->loadStringConstant(OString());
code->instrPutfield(className, name, "Ljava/lang/String;"_ostr);
return 2;
case codemaker::UnoType::Sort::Type:
code->loadLocalReference(0);
code->instrGetstatic(
"com/sun/star/uno/Type"_ostr, "VOID"_ostr, "Lcom/sun/star/uno/Type;"_ostr);
code->instrPutfield(className, name, "Lcom/sun/star/uno/Type;"_ostr);
return 2;
case codemaker::UnoType::Sort::Any:
code->loadLocalReference(0);
code->instrGetstatic(
"com/sun/star/uno/Any"_ostr, "VOID"_ostr, "Lcom/sun/star/uno/Any;"_ostr);
code->instrPutfield(className, name, "Ljava/lang/Object;"_ostr);
return 2;
case codemaker::UnoType::Sort::Enum:
{
rtl::Reference< unoidl::EnumTypeEntity > ent2(
dynamic_cast< unoidl::EnumTypeEntity * >(ent.get()));
assert(ent2.is());
code->loadLocalReference(0);
OStringBuffer descBuf(128);
translateUnoTypeToDescriptor(
manager, sort, nucleus, 0, std::vector< OUString >(), false,
false, dependencies, &descBuf, nullptr, nullptr, nullptr);
OString desc(descBuf.makeStringAndClear());
code->instrGetstatic(
codemaker::convertString(nucleus).replace('.', '/'),
codemaker::convertString(ent2->getMembers()[0].name), desc);
code->instrPutfield(className, name, desc);
return 2;
}
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
{
code->loadLocalReference(0);
code->instrNew(
codemaker::convertString(nucleus).replace('.', '/'));
code->instrDup();
code->instrInvokespecial(
codemaker::convertString(nucleus).replace('.', '/'),
"<init>"_ostr, "()V"_ostr);
OStringBuffer desc(128);
translateUnoTypeToDescriptor(
manager, sort, nucleus, 0, args, false, false, dependencies,
&desc, nullptr, nullptr, nullptr);
code->instrPutfield(className, name, desc.makeStringAndClear());
return 3;
}
case codemaker::UnoType::Sort::Sequence:
case codemaker::UnoType::Sort::Typedef:
for (;;) std::abort(); // this cannot happen
default:
throw CannotDumpException(
OUString::Concat("unexpected entity \"") + fieldType
+ "\" in call to addFieldInit");
}
}
code->loadLocalReference(0);
code->loadIntegerConstant(0);
if (rank == 1) {
if (sort >= codemaker::UnoType::Sort::Boolean
&& sort <= codemaker::UnoType::Sort::Char)
{
code->instrNewarray(sort);
} else {
code->instrAnewarray(
codemaker::java::translateUnoToJavaType(
sort, codemaker::convertString(nucleus).replace('.', '/'),
false));
}
} else {
OStringBuffer desc(128);
translateUnoTypeToDescriptor(
manager, sort, nucleus, rank - 1, std::vector< OUString >(), false,
false, dependencies, &desc, nullptr, nullptr, nullptr);
code->instrAnewarray(desc.makeStringAndClear());
}
OStringBuffer desc(128);
translateUnoTypeToDescriptor(
manager, sort, nucleus, rank, std::vector< OUString >(), false, false,
dependencies, &desc, nullptr, nullptr, nullptr);
code->instrPutfield(className, name, desc.makeStringAndClear());
return 2;
}
sal_uInt16 addLoadLocal(
rtl::Reference< TypeManager > const & manager, ClassFile::Code * code,
sal_uInt16 * index, bool typeParameter, std::u16string_view type, bool any,
std::set<OUString> * dependencies)
{
assert(manager.is());
assert(code != nullptr);
assert(index != nullptr);
assert(!(typeParameter && any));
assert(dependencies != nullptr);
sal_uInt16 stack = 1;
sal_uInt16 size = 1;
if (typeParameter) {
code->loadLocalReference(*index);
stack = size = 1;
} else {
OUString nucleus;
sal_Int32 rank;
std::vector< OUString > args;
codemaker::UnoType::Sort sort = manager->decompose(
type, true, &nucleus, &rank, &args, nullptr);
if (rank == 0) {
switch (sort) {
case codemaker::UnoType::Sort::Boolean:
if (any) {
code->instrNew("java/lang/Boolean"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Boolean"_ostr, "<init>"_ostr, "(Z)V"_ostr);
stack = 3;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Byte:
if (any) {
code->instrNew("java/lang/Byte"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Byte"_ostr, "<init>"_ostr, "(B)V"_ostr);
stack = 3;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Short:
if (any) {
code->instrNew("java/lang/Short"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Short"_ostr, "<init>"_ostr, "(S)V"_ostr);
stack = 3;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::UnsignedShort:
if (any) {
code->instrNew("com/sun/star/uno/Any"_ostr);
code->instrDup();
code->instrGetstatic(
"com/sun/star/uno/Type"_ostr, "UNSIGNED_SHORT"_ostr,
"Lcom/sun/star/uno/Type;"_ostr);
code->instrNew("java/lang/Short"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Short"_ostr, "<init>"_ostr, "(S)V"_ostr);
code->instrInvokespecial(
"com/sun/star/uno/Any"_ostr, "<init>"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"_ostr);
stack = 6;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Long:
if (any) {
code->instrNew("java/lang/Integer"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Integer"_ostr, "<init>"_ostr, "(I)V"_ostr);
stack = 3;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::UnsignedLong:
if (any) {
code->instrNew("com/sun/star/uno/Any"_ostr);
code->instrDup();
code->instrGetstatic(
"com/sun/star/uno/Type"_ostr, "UNSIGNED_LONG"_ostr,
"Lcom/sun/star/uno/Type;"_ostr);
code->instrNew("java/lang/Integer"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Integer"_ostr, "<init>"_ostr, "(I)V"_ostr);
code->instrInvokespecial(
"com/sun/star/uno/Any"_ostr, "<init>"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"_ostr);
stack = 6;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Hyper:
if (any) {
code->instrNew("java/lang/Long"_ostr);
code->instrDup();
code->loadLocalLong(*index);
code->instrInvokespecial(
"java/lang/Long"_ostr, "<init>"_ostr, "(J)V"_ostr);
stack = 4;
} else {
code->loadLocalLong(*index);
stack = 2;
}
size = 2;
break;
case codemaker::UnoType::Sort::UnsignedHyper:
if (any) {
code->instrNew("com/sun/star/uno/Any"_ostr);
code->instrDup();
code->instrGetstatic(
"com/sun/star/uno/Type"_ostr, "UNSIGNED_HYPER"_ostr,
"Lcom/sun/star/uno/Type;"_ostr);
code->instrNew("java/lang/Long"_ostr);
code->instrDup();
code->loadLocalLong(*index);
code->instrInvokespecial(
"java/lang/Long"_ostr, "<init>"_ostr, "(J)V"_ostr);
code->instrInvokespecial(
"com/sun/star/uno/Any"_ostr, "<init>"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"_ostr);
stack = 7;
} else {
code->loadLocalLong(*index);
stack = 2;
}
size = 2;
break;
case codemaker::UnoType::Sort::Float:
if (any) {
code->instrNew("java/lang/Float"_ostr);
code->instrDup();
code->loadLocalFloat(*index);
code->instrInvokespecial(
"java/lang/Float"_ostr, "<init>"_ostr, "(F)V"_ostr);
stack = 3;
} else {
code->loadLocalFloat(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Double:
if (any) {
code->instrNew("java/lang/Double"_ostr);
code->instrDup();
code->loadLocalDouble(*index);
code->instrInvokespecial(
"java/lang/Double"_ostr, "<init>"_ostr, "(D)V"_ostr);
stack = 4;
} else {
code->loadLocalDouble(*index);
stack = 2;
}
size = 2;
break;
case codemaker::UnoType::Sort::Char:
if (any) {
code->instrNew("java/lang/Character"_ostr);
code->instrDup();
code->loadLocalInteger(*index);
code->instrInvokespecial(
"java/lang/Character"_ostr, "<init>"_ostr, "(C)V"_ostr);
stack = 3;
} else {
code->loadLocalInteger(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::String:
case codemaker::UnoType::Sort::Type:
case codemaker::UnoType::Sort::Any:
code->loadLocalReference(*index);
stack = size = 1;
break;
case codemaker::UnoType::Sort::Enum:
// Assuming that no Java types are derived from Java types that
// are directly derived from com.sun.star.uno.Enum:
code->loadLocalReference(*index);
stack = size = 1;
break;
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
if (any) {
code->instrNew("com/sun/star/uno/Any"_ostr);
code->instrDup();
code->instrNew("com/sun/star/uno/Type"_ostr);
code->instrDup();
code->loadStringConstant(
codemaker::convertString(
createUnoName(manager, nucleus, rank, args)));
code->instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "STRUCT"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
dependencies->insert(u"com.sun.star.uno.TypeClass"_ustr);
code->instrInvokespecial(
"com/sun/star/uno/Type"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"_ostr);
code->loadLocalReference(*index);
code->instrInvokespecial(
"com/sun/star/uno/Any"_ostr, "<init>"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"_ostr);
stack = 6;
} else {
code->loadLocalReference(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Interface:
if (any && nucleus != "com.sun.star.uno.XInterface") {
code->instrNew("com/sun/star/uno/Any"_ostr);
code->instrDup();
code->instrNew("com/sun/star/uno/Type"_ostr);
code->instrDup();
code->loadStringConstant(codemaker::convertString(nucleus));
code->instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "INTERFACE"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
dependencies->insert(u"com.sun.star.uno.TypeClass"_ustr);
code->instrInvokespecial(
"com/sun/star/uno/Type"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"_ostr);
code->loadLocalReference(*index);
code->instrInvokespecial(
"com/sun/star/uno/Any"_ostr, "<init>"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"_ostr);
stack = 6;
} else {
code->loadLocalReference(*index);
stack = 1;
}
size = 1;
break;
case codemaker::UnoType::Sort::Sequence:
case codemaker::UnoType::Sort::Typedef:
for (;;) std::abort(); // this cannot happen
default:
throw CannotDumpException(
OUString::Concat("unexpected entity \"") + type
+ "\" in call to addLoadLocal");
}
} else {
bool bWrap = false;
if (any) {
switch (sort) {
case codemaker::UnoType::Sort::Boolean:
case codemaker::UnoType::Sort::Byte:
case codemaker::UnoType::Sort::Short:
case codemaker::UnoType::Sort::Long:
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::Float:
case codemaker::UnoType::Sort::Double:
case codemaker::UnoType::Sort::Char:
case codemaker::UnoType::Sort::String:
case codemaker::UnoType::Sort::Type:
// assuming that no Java types are derived from
// com.sun.star.uno.Type
case codemaker::UnoType::Sort::Enum:
// assuming that no Java types are derived from Java
// types that are directly derived from
// com.sun.star.uno.Enum
break;
case codemaker::UnoType::Sort::UnsignedShort:
case codemaker::UnoType::Sort::UnsignedLong:
case codemaker::UnoType::Sort::UnsignedHyper:
case codemaker::UnoType::Sort::Any:
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct:
case codemaker::UnoType::Sort::Interface:
bWrap = true;
break;
case codemaker::UnoType::Sort::Sequence:
case codemaker::UnoType::Sort::Typedef:
for (;;) std::abort(); // this cannot happen
default:
throw CannotDumpException(
OUString::Concat("unexpected entity \"") + type
+ "\" in call to addLoadLocal");
}
}
if (bWrap) {
code->instrNew("com/sun/star/uno/Any"_ostr);
code->instrDup();
code->instrNew("com/sun/star/uno/Type"_ostr);
code->instrDup();
code->loadStringConstant(
codemaker::convertString(
createUnoName(manager, nucleus, rank, args)));
code->instrInvokespecial(
"com/sun/star/uno/Type"_ostr, "<init>"_ostr, "(Ljava/lang/String;)V"_ostr);
code->loadLocalReference(*index);
code->instrInvokespecial(
"com/sun/star/uno/Any"_ostr, "<init>"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"_ostr);
stack = 5;
} else {
code->loadLocalReference(*index);
stack = 1;
}
size = 1;
}
}
if (*index > SAL_MAX_UINT16 - size) {
throw CannotDumpException(
u"Too many local variables for Java class file format"_ustr);
}
*index = *index + size;
return stack;
}
sal_uInt16 addDirectArgument(
rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies,
MethodDescriptor * methodDescriptor, ClassFile::Code * code,
sal_uInt16 * index, OString const & className, OString const & fieldName,
bool typeParameter, OUString const & fieldType)
{
assert(methodDescriptor != nullptr);
assert(code != nullptr);
OString desc;
if (typeParameter) {
methodDescriptor->addTypeParameter(fieldType);
desc = "Ljava/lang/Object;"_ostr;
} else {
methodDescriptor->addParameter(fieldType, false, true, nullptr);
getFieldDescriptor(manager, dependencies, fieldType, &desc, nullptr, nullptr);
}
code->loadLocalReference(0);
sal_uInt16 stack = addLoadLocal(
manager, code, index, typeParameter, fieldType, false, dependencies);
code->instrPutfield(className, fieldName, desc);
return stack + 1;
}
void addPlainStructBaseArguments(
rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies,
MethodDescriptor * methodDescriptor, ClassFile::Code * code,
OUString const & base, sal_uInt16 * index)
{
assert(manager.is());
assert(methodDescriptor != nullptr);
rtl::Reference< unoidl::Entity > ent;
if (manager->getSort(base, &ent)
!= codemaker::UnoType::Sort::PlainStruct)
{
throw CannotDumpException(
"unexpected entity \"" + base
+ "\" in call to addPlainStructBaseArguments");
}
unoidl::PlainStructTypeEntity& ent2(dynamic_cast<unoidl::PlainStructTypeEntity&>(*ent));
if (!ent2.getDirectBase().isEmpty()) {
addPlainStructBaseArguments(
manager, dependencies, methodDescriptor, code,
ent2.getDirectBase(), index);
}
for (const unoidl::PlainStructTypeEntity::Member& member : ent2.getDirectMembers())
{
methodDescriptor->addParameter(member.type, false, true, nullptr);
addLoadLocal(manager, code, index, false, member.type, false, dependencies);
}
}
void handlePlainStructType(
const OUString& name,
rtl::Reference< unoidl::PlainStructTypeEntity > const & entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
assert(dependencies != nullptr);
OString className(codemaker::convertString(name).replace('.', '/'));
OString superClass;
if (entity->getDirectBase().isEmpty()) {
superClass = "java/lang/Object"_ostr;
} else {
superClass = codemaker::convertString(entity->getDirectBase()).
replace('.', '/');
dependencies->insert(entity->getDirectBase());
}
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER),
className, superClass, ""_ostr));
std::vector< TypeInfo > typeInfo;
sal_Int32 index = 0;
for (const unoidl::PlainStructTypeEntity::Member& member : entity->getDirectMembers())
{
addField(
manager, dependencies, cf.get(), &typeInfo, -1, member.type, member.name,
index++);
}
std::unique_ptr< ClassFile::Code > code(cf->newCode());
code->loadLocalReference(0);
code->instrInvokespecial(superClass, "<init>"_ostr, "()V"_ostr);
sal_uInt16 stack = 0;
for (const unoidl::PlainStructTypeEntity::Member& member : entity->getDirectMembers())
{
stack = std::max(
stack,
addFieldInit(
manager, className, member.name, false, member.type, dependencies,
code.get()));
}
code->instrReturn();
code->setMaxStackAndLocals(stack + 1, 1);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, "()V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
MethodDescriptor desc(manager, dependencies, u"void", nullptr, nullptr);
code = cf->newCode();
code->loadLocalReference(0);
sal_uInt16 index2 = 1;
if (!entity->getDirectBase().isEmpty()) {
addPlainStructBaseArguments(
manager, dependencies, &desc, code.get(), entity->getDirectBase(),
&index2);
}
code->instrInvokespecial(superClass, "<init>"_ostr, desc.getDescriptor());
sal_uInt16 maxSize = index2;
for (const unoidl::PlainStructTypeEntity::Member& member : entity->getDirectMembers())
{
maxSize = std::max(
maxSize,
addDirectArgument(
manager, dependencies, &desc, code.get(), &index2, className,
codemaker::convertString(member.name), false, member.type));
}
code->instrReturn();
code->setMaxStackAndLocals(maxSize, index2);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, desc.getDescriptor(), code.get(),
std::vector< OString >(), desc.getSignature());
addTypeInfo(className, typeInfo, dependencies, cf.get());
writeClassFile(options, className, *cf);
}
void handlePolyStructType(
const OUString& name,
rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > const &
entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
OString className(codemaker::convertString(name).replace('.', '/'));
std::map< OUString, sal_Int32 > typeParameters;
OStringBuffer sig(128);
sig.append("<");
sal_Int32 index = 0;
for (const OUString& param : entity->getTypeParameters())
{
sig.append(codemaker::convertString(param) + ":Ljava/lang/Object;");
if (!typeParameters.emplace(param, index++).second)
{
throw CannotDumpException(u"Bad type information"_ustr); //TODO
}
}
sig.append(">Ljava/lang/Object;");
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER),
className, "java/lang/Object"_ostr, sig.makeStringAndClear()));
std::vector< TypeInfo > typeInfo;
index = 0;
for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity->getMembers())
{
sal_Int32 typeParameterIndex;
if (member.parameterized) {
std::map< OUString, sal_Int32 >::iterator it(
typeParameters.find(member.type));
if (it == typeParameters.end()) {
throw CannotDumpException(u"Bad type information"_ustr); //TODO
}
typeParameterIndex = it->second;
} else {
typeParameterIndex = -1;
}
addField(
manager, dependencies, cf.get(), &typeInfo, typeParameterIndex,
member.type, member.name, index++);
}
std::unique_ptr< ClassFile::Code > code(cf->newCode());
code->loadLocalReference(0);
code->instrInvokespecial("java/lang/Object"_ostr, "<init>"_ostr, "()V"_ostr);
sal_uInt16 stack = 0;
for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity->getMembers())
{
stack = std::max(
stack,
addFieldInit(
manager, className, member.name, member.parameterized, member.type,
dependencies, code.get()));
}
code->instrReturn();
code->setMaxStackAndLocals(stack + 1, 1);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, "()V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
MethodDescriptor desc(manager, dependencies, u"void", nullptr, nullptr);
code = cf->newCode();
code->loadLocalReference(0);
sal_uInt16 index2 = 1;
code->instrInvokespecial(
"java/lang/Object"_ostr, "<init>"_ostr, desc.getDescriptor());
sal_uInt16 maxSize = index2;
for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity->getMembers())
{
maxSize = std::max(
maxSize,
addDirectArgument(
manager, dependencies, &desc, code.get(), &index2, className,
codemaker::convertString(member.name), member.parameterized, member.type));
}
code->instrReturn();
code->setMaxStackAndLocals(maxSize, index2);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, desc.getDescriptor(), code.get(),
std::vector< OString >(), desc.getSignature());
addTypeInfo(className, typeInfo, dependencies, cf.get());
writeClassFile(options, className, *cf);
}
void addExceptionBaseArguments(
rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies,
MethodDescriptor * methodDescriptor, ClassFile::Code * code,
OUString const & base, sal_uInt16 * index)
{
assert(manager.is());
assert(methodDescriptor != nullptr);
rtl::Reference< unoidl::Entity > ent;
if (manager->getSort(base, &ent) != codemaker::UnoType::Sort::Exception)
{
throw CannotDumpException(
"unexpected entity \"" + base
+ "\" in call to addExceptionBaseArguments");
}
unoidl::ExceptionTypeEntity& ent2(dynamic_cast<unoidl::ExceptionTypeEntity&>(*ent));
bool baseException = base == "com.sun.star.uno.Exception";
if (!baseException) {
addExceptionBaseArguments(
manager, dependencies, methodDescriptor, code,
ent2.getDirectBase(), index);
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
ent2.getDirectMembers().begin());
i != ent2.getDirectMembers().end(); ++i)
{
if (!baseException || i != ent2.getDirectMembers().begin()) {
methodDescriptor->addParameter(i->type, false, true, nullptr);
addLoadLocal(
manager, code, index, false, i->type, false, dependencies);
}
}
}
void handleExceptionType(
const OUString& name, rtl::Reference< unoidl::ExceptionTypeEntity > const & entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
assert(dependencies != nullptr);
OString className(codemaker::convertString(name).replace('.', '/'));
bool baseException = false;
bool baseRuntimeException = false;
OString superClass;
if (className == "com/sun/star/uno/Exception") {
baseException = true;
superClass = "java/lang/Exception"_ostr;
} else if (className == "com/sun/star/uno/RuntimeException") {
baseRuntimeException = true;
superClass = "java/lang/RuntimeException"_ostr;
} else {
if (entity->getDirectBase().isEmpty()) {
throw CannotDumpException(
"Exception type \"" + name + "\" lacks base");
}
superClass = codemaker::convertString(entity->getDirectBase()).
replace('.', '/');
dependencies->insert(entity->getDirectBase());
}
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER),
className, superClass, ""_ostr));
std::vector< TypeInfo > typeInfo;
sal_Int32 index = 0;
if (baseRuntimeException) {
addField(
manager, dependencies, cf.get(), &typeInfo, -1,
u"com.sun.star.uno.XInterface"_ustr, u"Context"_ustr, index++);
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
addField(
manager, dependencies, cf.get(), &typeInfo, -1, i->type,
i->name, index++);
}
}
// create default constructor
std::unique_ptr< ClassFile::Code > code(cf->newCode());
code->loadLocalReference(0);
code->instrInvokespecial(superClass, "<init>"_ostr, "()V"_ostr);
sal_uInt16 stack = 0;
if (baseRuntimeException) {
stack = std::max(
stack,
addFieldInit(
manager, className, u"Context"_ustr, false,
u"com.sun.star.uno.XInterface", dependencies, code.get()));
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
stack = std::max(
stack,
addFieldInit(
manager, className, i->name, false, i->type, dependencies,
code.get()));
}
}
code->instrReturn();
code->setMaxStackAndLocals(stack + 1, 1);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, "()V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
// create (Throwable Cause) constructor
code = cf->newCode();
code->loadLocalReference(0);
code->loadLocalReference(1);
code->instrInvokespecial(superClass, "<init>"_ostr, "(Ljava/lang/Throwable;)V"_ostr);
stack = 0;
if (baseRuntimeException) {
stack = std::max(
stack,
addFieldInit(
manager, className, u"Context"_ustr, false,
u"com.sun.star.uno.XInterface", dependencies, code.get()));
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
stack = std::max(
stack,
addFieldInit(
manager, className, i->name, false, i->type, dependencies,
code.get()));
}
}
code->instrReturn();
code->setMaxStackAndLocals(stack + 2, 2);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, "(Ljava/lang/Throwable;)V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
// create (Throwable Cause, String Message) constructor
code = cf->newCode();
code->loadLocalReference(0);
if (baseException || baseRuntimeException) {
code->loadLocalReference(2);
code->loadLocalReference(1);
code->instrInvokespecial(superClass, "<init>"_ostr, "(Ljava/lang/String;Ljava/lang/Throwable;)V"_ostr);
} else {
code->loadLocalReference(1);
code->loadLocalReference(2);
code->instrInvokespecial(superClass, "<init>"_ostr, "(Ljava/lang/Throwable;Ljava/lang/String;)V"_ostr);
}
stack = 0;
if (baseRuntimeException) {
stack = std::max(
stack,
addFieldInit(
manager, className, u"Context"_ustr, false,
u"com.sun.star.uno.XInterface", dependencies, code.get()));
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
stack = std::max(
stack,
addFieldInit(
manager, className, i->name, false, i->type, dependencies,
code.get()));
}
}
code->instrReturn();
code->setMaxStackAndLocals(stack + 3, 3);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, "(Ljava/lang/Throwable;Ljava/lang/String;)V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
// create (String Message) constructor
code = cf->newCode();
code->loadLocalReference(0);
code->loadLocalReference(1);
code->instrInvokespecial(superClass, "<init>"_ostr, "(Ljava/lang/String;)V"_ostr);
stack = 0;
if (baseRuntimeException) {
stack = std::max(
stack,
addFieldInit(
manager, className, u"Context"_ustr, false,
u"com.sun.star.uno.XInterface", dependencies, code.get()));
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
stack = std::max(
stack,
addFieldInit(
manager, className, i->name, false, i->type, dependencies,
code.get()));
}
}
code->instrReturn();
code->setMaxStackAndLocals(stack + 2, 2);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, "(Ljava/lang/String;)V"_ostr, code.get(),
std::vector< OString >(), ""_ostr);
// create (String Message, Object Context, T1 m1, ..., Tn mn) constructor
MethodDescriptor desc1(manager, dependencies, u"void", nullptr, nullptr);
code = cf->newCode();
code->loadLocalReference(0);
sal_uInt16 index2 = 1;
code->loadLocalReference(index2++);
desc1.addParameter(u"string", false, true, nullptr);
if (!(baseException || baseRuntimeException)) {
addExceptionBaseArguments(
manager, dependencies, &desc1, code.get(), entity->getDirectBase(),
&index2);
}
code->instrInvokespecial(superClass, "<init>"_ostr, desc1.getDescriptor());
sal_uInt16 maxSize = index2;
if (baseRuntimeException) {
maxSize = std::max(
maxSize,
addDirectArgument(
manager, dependencies, &desc1, code.get(), &index2, className,
"Context"_ostr, false, u"com.sun.star.uno.XInterface"_ustr));
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
maxSize = std::max(
maxSize,
addDirectArgument(
manager, dependencies, &desc1, code.get(), &index2,
className, codemaker::convertString(i->name), false,
i->type));
}
}
code->instrReturn();
code->setMaxStackAndLocals(maxSize, index2);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, desc1.getDescriptor(), code.get(),
std::vector< OString >(), desc1.getSignature());
// create (Throwable Cause, String Message, Object Context, T1 m1, ..., Tn mn) constructor
MethodDescriptor desc2(manager, dependencies, u"void", nullptr, nullptr);
code = cf->newCode();
code->loadLocalReference(0);
sal_uInt16 index3 = 3;
// Note that we hack in the java.lang.Throwable parameter further down,
// because MethodDescriptor does not know how to handle it.
desc2.addParameter(u"string", false, true, nullptr);
if (baseException || baseRuntimeException) {
code->loadLocalReference(2);
code->loadLocalReference(1);
code->instrInvokespecial(superClass, "<init>"_ostr, "(Ljava/lang/String;Ljava/lang/Throwable;)V"_ostr);
} else {
code->loadLocalReference(1);
code->loadLocalReference(2);
addExceptionBaseArguments(
manager, dependencies, &desc2, code.get(), entity->getDirectBase(),
&index3);
code->instrInvokespecial(superClass, "<init>"_ostr, OString::Concat("(Ljava/lang/Throwable;") + desc2.getDescriptor().subView(1));
}
sal_uInt16 maxSize2 = index3;
if (baseRuntimeException) {
maxSize2 = std::max(
maxSize2,
addDirectArgument(
manager, dependencies, &desc2, code.get(), &index3, className,
"Context"_ostr, false, u"com.sun.star.uno.XInterface"_ustr));
}
for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i(
entity->getDirectMembers().begin());
i != entity->getDirectMembers().end(); ++i)
{
if (!baseException || i != entity->getDirectMembers().begin()) {
maxSize2 = std::max(
maxSize2,
addDirectArgument(
manager, dependencies, &desc2, code.get(), &index3,
className, codemaker::convertString(i->name), false,
i->type));
}
}
code->instrReturn();
code->setMaxStackAndLocals(maxSize2, index3);
cf->addMethod(
ClassFile::ACC_PUBLIC, "<init>"_ostr, OString::Concat("(Ljava/lang/Throwable;") + desc2.getDescriptor().subView(1), code.get(),
std::vector< OString >(), desc2.getSignature());
addTypeInfo(className, typeInfo, dependencies, cf.get());
writeClassFile(options, className, *cf);
}
void createExceptionsAttribute(
rtl::Reference< TypeManager > const & manager,
std::vector< OUString > const & exceptionTypes,
std::set<OUString> * dependencies, std::vector< OString > * exceptions,
codemaker::ExceptionTree * tree)
{
assert(dependencies != nullptr);
assert(exceptions != nullptr);
for (const OUString& ex : exceptionTypes)
{
dependencies->insert(ex);
OString type(codemaker::convertString(ex).replace('.', '/'));
exceptions->push_back(type);
if (tree != nullptr) {
tree->add(type.replace('/', '.'), manager);
}
}
}
void handleInterfaceType(
const OUString& name, rtl::Reference< unoidl::InterfaceTypeEntity > const & entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
assert(dependencies != nullptr);
OString className(codemaker::convertString(name).replace('.', '/'));
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE
| ClassFile::ACC_ABSTRACT),
className, "java/lang/Object"_ostr, ""_ostr));
for (const unoidl::AnnotatedReference& ar : entity->getDirectMandatoryBases())
{
dependencies->insert(ar.name);
cf->addInterface(codemaker::convertString(ar.name).replace('.', '/'));
}
// As a special case, let com.sun.star.lang.XEventListener extend
// java.util.EventListener ("A tagging interface that all event listener
// interfaces must extend"):
if (className == "com/sun/star/lang/XEventListener") {
cf->addInterface("java/util/EventListener"_ostr);
}
std::vector< TypeInfo > typeInfo;
if (className != "com/sun/star/uno/XInterface") {
sal_Int32 index = 0;
for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity->getDirectAttributes())
{
SpecialType specialType;
PolymorphicUnoType polymorphicUnoType;
MethodDescriptor gdesc(
manager, dependencies, attr.type, &specialType,
&polymorphicUnoType);
std::vector< OString > exc;
createExceptionsAttribute(
manager, attr.getExceptions, dependencies, &exc, nullptr);
OString attrName(codemaker::convertString(attr.name));
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT),
"get" + attrName, gdesc.getDescriptor(), nullptr, exc,
gdesc.getSignature());
if (!attr.readOnly) {
MethodDescriptor sdesc(manager, dependencies, u"void", nullptr, nullptr);
sdesc.addParameter(attr.type, false, true, nullptr);
std::vector< OString > exc2;
createExceptionsAttribute(
manager, attr.setExceptions, dependencies, &exc2, nullptr);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT),
"set" + attrName, sdesc.getDescriptor(), nullptr, exc2,
sdesc.getSignature());
}
typeInfo.emplace_back(
TypeInfo::KIND_ATTRIBUTE, attrName, specialType,
static_cast< TypeInfo::Flags >(
(attr.readOnly ? TypeInfo::FLAG_READONLY : 0)
| (attr.bound ? TypeInfo::FLAG_BOUND : 0)),
index, polymorphicUnoType);
index += (attr.readOnly ? 1 : 2);
}
for (const unoidl::InterfaceTypeEntity::Method& method : entity->getDirectMethods())
{
OString methodName(codemaker::convertString(method.name));
SpecialType specialReturnType;
PolymorphicUnoType polymorphicUnoReturnType;
MethodDescriptor desc(
manager, dependencies, method.returnType, &specialReturnType,
&polymorphicUnoReturnType);
typeInfo.emplace_back(
TypeInfo::KIND_METHOD, methodName, specialReturnType,
static_cast< TypeInfo::Flags >(0), index++,
polymorphicUnoReturnType);
sal_Int32 paramIndex = 0;
for (const unoidl::InterfaceTypeEntity::Method::Parameter& param : method.parameters)
{
bool in = param.direction
!= unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT;
bool out = param.direction
!= unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
PolymorphicUnoType polymorphicUnoType;
SpecialType specialType = desc.addParameter(
param.type, out, true, &polymorphicUnoType);
if (out || isSpecialType(specialType)
|| polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE)
{
typeInfo.emplace_back(
codemaker::convertString(param.name), specialType, in,
out, methodName, paramIndex, polymorphicUnoType);
}
++paramIndex;
}
std::vector< OString > exc2;
createExceptionsAttribute(
manager, method.exceptions, dependencies, &exc2, nullptr);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT),
methodName, desc.getDescriptor(), nullptr, exc2, desc.getSignature());
}
}
addTypeInfo(className, typeInfo, dependencies, cf.get());
writeClassFile(options, className, *cf);
}
void handleTypedef(
rtl::Reference< unoidl::TypedefEntity > const & entity,
rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies)
{
assert(entity.is());
assert(manager.is());
assert(dependencies != nullptr);
OUString nucleus;
switch (manager->decompose(entity->getType(), false, &nucleus, nullptr, nullptr, nullptr))
{
case codemaker::UnoType::Sort::Boolean:
case codemaker::UnoType::Sort::Byte:
case codemaker::UnoType::Sort::Short:
case codemaker::UnoType::Sort::UnsignedShort:
case codemaker::UnoType::Sort::Long:
case codemaker::UnoType::Sort::UnsignedLong:
case codemaker::UnoType::Sort::Hyper:
case codemaker::UnoType::Sort::UnsignedHyper:
case codemaker::UnoType::Sort::Float:
case codemaker::UnoType::Sort::Double:
case codemaker::UnoType::Sort::Char:
case codemaker::UnoType::Sort::String:
case codemaker::UnoType::Sort::Type:
case codemaker::UnoType::Sort::Any:
break;
case codemaker::UnoType::Sort::Enum:
case codemaker::UnoType::Sort::PlainStruct:
case codemaker::UnoType::Sort::Interface:
case codemaker::UnoType::Sort::Typedef:
dependencies->insert(nucleus);
break;
default:
assert(false); // this cannot happen
}
}
void handleConstantGroup(
const OUString& name, rtl::Reference< unoidl::ConstantGroupEntity > const & entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
OString className(codemaker::convertString(name).replace('.', '/'));
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE
| ClassFile::ACC_ABSTRACT),
className, "java/lang/Object"_ostr, ""_ostr));
for (const unoidl::ConstantGroupEntity::Member& member : entity->getMembers())
{
OUString type;
sal_uInt16 valueIndex = sal_uInt16(); // avoid false warnings
switch (member.value.type) {
case unoidl::ConstantValue::TYPE_BOOLEAN:
type = "boolean";
valueIndex = cf->addIntegerInfo(sal_Int32(member.value.booleanValue));
break;
case unoidl::ConstantValue::TYPE_BYTE:
type = "byte";
valueIndex = cf->addIntegerInfo(member.value.byteValue);
break;
case unoidl::ConstantValue::TYPE_SHORT:
type = "short";
valueIndex = cf->addIntegerInfo(member.value.shortValue);
break;
case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
type = "unsigned short";
valueIndex = cf->addIntegerInfo(member.value.unsignedShortValue);
break;
case unoidl::ConstantValue::TYPE_LONG:
type = "long";
valueIndex = cf->addIntegerInfo(member.value.longValue);
break;
case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
type = "unsigned long";
valueIndex = cf->addIntegerInfo(
static_cast< sal_Int32 >(member.value.unsignedLongValue));
break;
case unoidl::ConstantValue::TYPE_HYPER:
type = "hyper";
valueIndex = cf->addLongInfo(member.value.hyperValue);
break;
case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
type = "unsigned hyper";
valueIndex = cf->addLongInfo(
static_cast< sal_Int64 >(member.value.unsignedHyperValue));
break;
case unoidl::ConstantValue::TYPE_FLOAT:
type = "float";
valueIndex = cf->addFloatInfo(member.value.floatValue);
break;
case unoidl::ConstantValue::TYPE_DOUBLE:
type = "double";
valueIndex = cf->addDoubleInfo(member.value.doubleValue);
break;
}
OString desc;
OString sig;
getFieldDescriptor(manager, dependencies, type, &desc, &sig, nullptr);
cf->addField(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC
| ClassFile::ACC_FINAL),
codemaker::convertString(member.name), desc, valueIndex, sig);
}
writeClassFile(options, className, *cf);
}
void addExceptionHandlers(
codemaker::ExceptionTreeNode const * node,
ClassFile::Code::Position start, ClassFile::Code::Position end,
ClassFile::Code::Position handler, ClassFile::Code * code)
{
assert(node != nullptr);
assert(code != nullptr);
if (node->present) {
code->addException(start, end, handler, node->name.replace('.', '/'));
} else {
for (std::unique_ptr<codemaker::ExceptionTreeNode> const & p : node->children)
{
addExceptionHandlers(p.get(), start, end, handler, code);
}
}
}
void addConstructor(
rtl::Reference< TypeManager > const & manager,
std::string_view realJavaBaseName, OString const & unoName,
OString const & className,
unoidl::SingleInterfaceBasedServiceEntity::Constructor const & constructor,
OUString const & returnType, std::set<OUString> * dependencies,
ClassFile * classFile)
{
assert(dependencies != nullptr);
assert(classFile != nullptr);
MethodDescriptor desc(manager, dependencies, returnType, nullptr, nullptr);
desc.addParameter(u"com.sun.star.uno.XComponentContext", false, false, nullptr);
std::unique_ptr< ClassFile::Code > code(classFile->newCode());
code->loadLocalReference(0);
// stack: context
code->instrInvokeinterface(
"com/sun/star/uno/XComponentContext"_ostr, "getServiceManager"_ostr,
"()Lcom/sun/star/lang/XMultiComponentFactory;"_ostr, 1);
// stack: factory
code->loadStringConstant(unoName);
// stack: factory serviceName
codemaker::ExceptionTree tree;
ClassFile::Code::Position tryStart;
ClassFile::Code::Position tryEnd;
std::vector< OString > exc;
sal_uInt16 stack;
sal_uInt16 localIndex = 1;
ClassFile::AccessFlags access = static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC);
if (constructor.defaultConstructor) {
code->loadLocalReference(0);
// stack: factory serviceName context
tryStart = code->getPosition();
code->instrInvokeinterface(
"com/sun/star/lang/XMultiComponentFactory"_ostr,
"createInstanceWithContext"_ostr,
("(Ljava/lang/String;Lcom/sun/star/uno/XComponentContext;)"
"Ljava/lang/Object;"_ostr),
3);
tryEnd = code->getPosition();
// stack: instance
stack = 3;
} else {
if (constructor.parameters.size() == 1
&& constructor.parameters[0].rest)
{
desc.addParameter(u"any", true, true, nullptr);
code->loadLocalReference(localIndex++);
// stack: factory serviceName args
stack = 4;
access = static_cast< ClassFile::AccessFlags >(
access | ClassFile::ACC_VARARGS);
} else {
code->loadIntegerConstant(constructor.parameters.size());
// stack: factory serviceName N
code->instrAnewarray("java/lang/Object"_ostr);
// stack: factory serviceName args
stack = 0;
sal_Int32 n = 0;
for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param :
constructor.parameters)
{
desc.addParameter(param.type, false, true, nullptr);
code->instrDup();
// stack: factory serviceName args args
code->loadIntegerConstant(n++);
// stack: factory serviceName args args i
stack = std::max(
stack,
addLoadLocal(
manager, code.get(), &localIndex, false, param.type, true,
dependencies));
// stack: factory serviceName args args i any
code->instrAastore();
// stack: factory serviceName args
}
stack += 5;
}
code->loadLocalReference(0);
// stack: factory serviceName args context
tryStart = code->getPosition();
code->instrInvokeinterface(
"com/sun/star/lang/XMultiComponentFactory"_ostr,
"createInstanceWithArgumentsAndContext"_ostr,
("(Ljava/lang/String;[Ljava/lang/Object;"
"Lcom/sun/star/uno/XComponentContext;)Ljava/lang/Object;"_ostr),
4);
tryEnd = code->getPosition();
// stack: instance
createExceptionsAttribute(
manager, constructor.exceptions, dependencies, &exc, &tree);
}
code->loadLocalReference(0);
// stack: instance context
code->instrInvokestatic(
className, "$castInstance"_ostr,
("(Ljava/lang/Object;Lcom/sun/star/uno/XComponentContext;)"
"Ljava/lang/Object;"_ostr));
// stack: instance
code->instrCheckcast(
codemaker::convertString(returnType).replace('.', '/'));
// stack: instance
code->instrAreturn();
if (!tree.getRoot().present) {
ClassFile::Code::Position pos1 = code->getPosition();
// stack: e
code->instrInvokevirtual(
"java/lang/Throwable"_ostr, "toString"_ostr, "()Ljava/lang/String;"_ostr);
// stack: str
localIndex = std::max< sal_uInt16 >(localIndex, 2);
code->storeLocalReference(1);
// stack: -
code->instrNew("com/sun/star/uno/DeploymentException"_ostr);
// stack: ex
code->instrDup();
// stack: ex ex
code->loadStringConstant(
"component context fails to supply service " + unoName + " of type "
+ realJavaBaseName + ": ");
// stack: ex ex "..."
code->loadLocalReference(1);
// stack: ex ex "..." str
code->instrInvokevirtual(
"java/lang/String"_ostr, "concat"_ostr,
"(Ljava/lang/String;)Ljava/lang/String;"_ostr);
// stack: ex ex "..."
code->loadLocalReference(0);
// stack: ex ex "..." context
code->instrInvokespecial(
"com/sun/star/uno/DeploymentException"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Ljava/lang/Object;)V"_ostr);
// stack: ex
ClassFile::Code::Position pos2 = code->getPosition();
code->instrAthrow();
addExceptionHandlers(
&tree.getRoot(), tryStart, tryEnd, pos2, code.get());
code->addException(
tryStart, tryEnd, pos1, "com/sun/star/uno/Exception"_ostr);
dependencies->insert(u"com.sun.star.uno.Exception"_ustr);
stack = std::max< sal_uInt16 >(stack, 4);
}
code->setMaxStackAndLocals(stack, localIndex);
classFile->addMethod(
access,
codemaker::java::translateUnoToJavaIdentifier(
(constructor.defaultConstructor
? "create"_ostr : codemaker::convertString(constructor.name)),
"method"),
desc.getDescriptor(), code.get(), exc, desc.getSignature());
}
void handleService(
const OUString& name,
rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > const & entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
assert(dependencies != nullptr);
OString unoName(codemaker::convertString(name));
OString className(
translateUnoidlEntityNameToJavaFullyQualifiedName(name, "service"));
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL
| ClassFile::ACC_SUPER),
className, "java/lang/Object"_ostr, ""_ostr));
if (!entity->getConstructors().empty()) {
OString realJavaBaseName(
codemaker::convertString(entity->getBase()));
dependencies->insert(entity->getBase());
dependencies->insert(u"com.sun.star.lang.XMultiComponentFactory"_ustr);
dependencies->insert(u"com.sun.star.uno.DeploymentException"_ustr);
dependencies->insert(u"com.sun.star.uno.TypeClass"_ustr);
dependencies->insert(u"com.sun.star.uno.XComponentContext"_ustr);
for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons :
entity->getConstructors())
{
addConstructor(
manager, realJavaBaseName, unoName, className, cons,
entity->getBase(), dependencies, cf.get());
}
// Synthetic castInstance method:
{
std::unique_ptr< ClassFile::Code > code(cf->newCode());
code->instrNew("com/sun/star/uno/Type"_ostr);
// stack: type
code->instrDup();
// stack: type type
code->loadStringConstant(realJavaBaseName);
// stack: type type "..."
code->instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "INTERFACE"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
// stack: type type "..." INTERFACE
code->instrInvokespecial(
"com/sun/star/uno/Type"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"_ostr);
// stack: type
code->loadLocalReference(0);
// stack: type instance
code->instrInvokestatic(
"com/sun/star/uno/UnoRuntime"_ostr, "queryInterface"_ostr,
("(Lcom/sun/star/uno/Type;Ljava/lang/Object;)"
"Ljava/lang/Object;"_ostr));
// stack: instance
code->instrDup();
// stack: instance instance
ClassFile::Code::Branch branch = code->instrIfnull();
// stack: instance
code->instrAreturn();
code->branchHere(branch);
code->instrPop();
// stack: -
code->instrNew("com/sun/star/uno/DeploymentException"_ostr);
// stack: ex
code->instrDup();
// stack: ex ex
code->loadStringConstant(
"component context fails to supply service " + unoName
+ " of type " + realJavaBaseName);
// stack: ex ex "..."
code->loadLocalReference(1);
// stack: ex ex "..." context
code->instrInvokespecial(
"com/sun/star/uno/DeploymentException"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Ljava/lang/Object;)V"_ostr);
// stack: ex
code->instrAthrow();
code->setMaxStackAndLocals(4, 2);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC
| ClassFile::ACC_SYNTHETIC),
"$castInstance"_ostr,
("(Ljava/lang/Object;Lcom/sun/star/uno/XComponentContext;)"
"Ljava/lang/Object;"_ostr),
code.get(), std::vector< OString >(), ""_ostr);
}
}
writeClassFile(options, className, *cf);
}
void handleSingleton(
const OUString& name,
rtl::Reference< unoidl::InterfaceBasedSingletonEntity > const & entity,
rtl::Reference< TypeManager > const & manager, JavaOptions const & options,
std::set<OUString> * dependencies)
{
assert(entity.is());
assert(dependencies != nullptr);
OString realJavaBaseName(codemaker::convertString(entity->getBase()));
OString base(realJavaBaseName.replace('.', '/'));
dependencies->insert(entity->getBase());
OString unoName(codemaker::convertString(name));
OString className(
translateUnoidlEntityNameToJavaFullyQualifiedName(name, "singleton"));
dependencies->insert(u"com.sun.star.uno.DeploymentException"_ustr);
dependencies->insert(u"com.sun.star.uno.TypeClass"_ustr);
dependencies->insert(u"com.sun.star.uno.XComponentContext"_ustr);
std::unique_ptr< ClassFile > cf(
new ClassFile(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL
| ClassFile::ACC_SUPER),
className, "java/lang/Object"_ostr, ""_ostr));
MethodDescriptor desc(manager, dependencies, entity->getBase(), nullptr, nullptr);
desc.addParameter(u"com.sun.star.uno.XComponentContext", false, false, nullptr);
std::unique_ptr< ClassFile::Code > code(cf->newCode());
code->loadLocalReference(0);
// stack: context
code->loadStringConstant("/singletons/" + unoName);
// stack: context "..."
code->instrInvokeinterface(
"com/sun/star/uno/XComponentContext"_ostr, "getValueByName"_ostr,
"(Ljava/lang/String;)Ljava/lang/Object;"_ostr, 2);
// stack: value
code->instrDup();
// stack: value value
code->instrInstanceof("com/sun/star/uno/Any"_ostr);
// stack: value 0/1
ClassFile::Code::Branch branch1 = code->instrIfeq();
// stack: value
code->instrCheckcast("com/sun/star/uno/Any"_ostr);
// stack: value
code->instrDup();
// stack: value value
code->instrInvokevirtual(
"com/sun/star/uno/Any"_ostr, "getType"_ostr, "()Lcom/sun/star/uno/Type;"_ostr);
// stack: value type
code->instrInvokevirtual(
"com/sun/star/uno/Type"_ostr, "getTypeClass"_ostr,
"()Lcom/sun/star/uno/TypeClass;"_ostr);
// stack: value typeClass
code->instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "INTERFACE"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
// stack: value typeClass INTERFACE
ClassFile::Code::Branch branch2 = code->instrIfAcmpne();
// stack: value
code->instrInvokevirtual(
"com/sun/star/uno/Any"_ostr, "getObject"_ostr, "()Ljava/lang/Object;"_ostr);
// stack: value
code->branchHere(branch1);
code->instrNew("com/sun/star/uno/Type"_ostr);
// stack: value type
code->instrDup();
// stack: value type type
code->loadStringConstant(realJavaBaseName);
// stack: value type type "..."
code->instrGetstatic(
"com/sun/star/uno/TypeClass"_ostr, "INTERFACE"_ostr,
"Lcom/sun/star/uno/TypeClass;"_ostr);
// stack: value type type "..." INTERFACE
code->instrInvokespecial(
"com/sun/star/uno/Type"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"_ostr);
// stack: value type
code->instrSwap();
// stack: type value
code->instrInvokestatic(
"com/sun/star/uno/UnoRuntime"_ostr, "queryInterface"_ostr,
"(Lcom/sun/star/uno/Type;Ljava/lang/Object;)Ljava/lang/Object;"_ostr);
// stack: instance
code->instrDup();
// stack: instance instance
ClassFile::Code::Branch branch3 = code->instrIfnull();
// stack: instance
code->instrCheckcast(base);
// stack: instance
code->instrAreturn();
code->branchHere(branch2);
code->branchHere(branch3);
code->instrPop();
// stack: -
code->instrNew("com/sun/star/uno/DeploymentException"_ostr);
// stack: ex
code->instrDup();
// stack: ex ex
code->loadStringConstant(
"component context fails to supply singleton " + unoName + " of type "
+ realJavaBaseName);
// stack: ex ex "..."
code->loadLocalReference(0);
// stack: ex ex "..." context
code->instrInvokespecial(
"com/sun/star/uno/DeploymentException"_ostr, "<init>"_ostr,
"(Ljava/lang/String;Ljava/lang/Object;)V"_ostr);
// stack: ex
code->instrAthrow();
code->setMaxStackAndLocals(5, 1);
cf->addMethod(
static_cast< ClassFile::AccessFlags >(
ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC),
"get"_ostr, desc.getDescriptor(), code.get(), std::vector< OString >(),
desc.getSignature());
writeClassFile(options, className, *cf);
}
}
void produce(
OUString const & name, rtl::Reference< TypeManager > const & manager,
codemaker::GeneratedTypeSet & generated, JavaOptions const & options)
{
if (generated.contains(u2b(name))) {
return;
}
generated.add(u2b(name));
if (!manager->foundAtPrimaryProvider(name)) {
return;
}
std::set<OUString> deps;
rtl::Reference< unoidl::Entity > ent;
rtl::Reference< unoidl::MapCursor > cur;
switch (manager->getSort(name, &ent, &cur)) {
case codemaker::UnoType::Sort::Module:
{
OUString prefix;
if (!name.isEmpty()) {
prefix = name + ".";
}
for (;;) {
OUString mem;
if (!cur->getNext(&mem).is()) {
break;
}
produce(prefix + mem, manager, generated, options);
}
return;
}
case codemaker::UnoType::Sort::Enum:
handleEnumType(
name, dynamic_cast< unoidl::EnumTypeEntity * >(ent.get()), options);
break;
case codemaker::UnoType::Sort::PlainStruct:
handlePlainStructType(
name, dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::PolymorphicStructTemplate:
handlePolyStructType(
name,
dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >(
ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::Exception:
handleExceptionType(
name, dynamic_cast< unoidl::ExceptionTypeEntity * >(ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::Interface:
handleInterfaceType(
name, dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::Typedef:
handleTypedef(
dynamic_cast< unoidl::TypedefEntity * >(ent.get()), manager, &deps);
break;
case codemaker::UnoType::Sort::ConstantGroup:
handleConstantGroup(
name, dynamic_cast< unoidl::ConstantGroupEntity * >(ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::SingleInterfaceBasedService:
handleService(
name,
dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >(
ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::InterfaceBasedSingleton:
handleSingleton(
name,
dynamic_cast< unoidl::InterfaceBasedSingletonEntity * >(ent.get()),
manager, options, &deps);
break;
case codemaker::UnoType::Sort::AccumulationBasedService:
case codemaker::UnoType::Sort::ServiceBasedSingleton:
break;
default:
throw CannotDumpException(
"unexpected entity \"" + name + "\" in call to produce");
}
if (!options.isValid("-nD"_ostr)) {
for (const OUString& d : deps) {
produce(d, manager, generated, options);
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1175, 1181
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.
↑ V1048 The 'stack' variable was assigned the same value.
↑ V1048 The 'size' variable was assigned the same value.