794 lines
21 KiB
C++
794 lines
21 KiB
C++
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* 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 "Type.h"
|
|
|
|
#include "ConstantExpression.h"
|
|
#include "NamedType.h"
|
|
#include "ScalarType.h"
|
|
#include "Scope.h"
|
|
|
|
#include <android-base/logging.h>
|
|
#include <hidl-util/Formatter.h>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
namespace android {
|
|
|
|
Type::Type(Scope* parent, const std::string& definedName)
|
|
: mDefinedName(definedName), mParent(parent) {}
|
|
|
|
Type::~Type() {}
|
|
|
|
bool Type::isScope() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isInterface() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isScalar() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isString() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isEnum() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isBitField() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isHandle() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isTypeDef() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isNamedType() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isMemory() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isCompoundType() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isArray() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isVector() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isTemplatedType() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isPointer() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::isFmq() const {
|
|
return false;
|
|
}
|
|
|
|
Type* Type::resolve() {
|
|
return const_cast<Type*>(static_cast<const Type*>(this)->resolve());
|
|
}
|
|
|
|
const Type* Type::resolve() const {
|
|
return this;
|
|
}
|
|
|
|
std::vector<Type*> Type::getDefinedTypes() {
|
|
const auto& constRet = static_cast<const Type*>(this)->getDefinedTypes();
|
|
std::vector<Type*> ret(constRet.size());
|
|
std::transform(constRet.begin(), constRet.end(), ret.begin(),
|
|
[](const auto* type) { return const_cast<Type*>(type); });
|
|
return ret;
|
|
}
|
|
|
|
std::vector<const Type*> Type::getDefinedTypes() const {
|
|
return {};
|
|
}
|
|
|
|
std::vector<Reference<Type>*> Type::getReferences() {
|
|
const auto& constRet = static_cast<const Type*>(this)->getReferences();
|
|
std::vector<Reference<Type>*> ret(constRet.size());
|
|
std::transform(constRet.begin(), constRet.end(), ret.begin(),
|
|
[](const auto* ref) { return const_cast<Reference<Type>*>(ref); });
|
|
return ret;
|
|
}
|
|
|
|
std::vector<const Reference<Type>*> Type::getReferences() const {
|
|
return {};
|
|
}
|
|
|
|
std::vector<ConstantExpression*> Type::getConstantExpressions() {
|
|
const auto& constRet = static_cast<const Type*>(this)->getConstantExpressions();
|
|
std::vector<ConstantExpression*> ret(constRet.size());
|
|
std::transform(constRet.begin(), constRet.end(), ret.begin(),
|
|
[](const auto* ce) { return const_cast<ConstantExpression*>(ce); });
|
|
return ret;
|
|
}
|
|
|
|
std::vector<const ConstantExpression*> Type::getConstantExpressions() const {
|
|
return {};
|
|
}
|
|
|
|
std::vector<Reference<Type>*> Type::getStrongReferences() {
|
|
const auto& constRet = static_cast<const Type*>(this)->getStrongReferences();
|
|
std::vector<Reference<Type>*> ret(constRet.size());
|
|
std::transform(constRet.begin(), constRet.end(), ret.begin(),
|
|
[](const auto* ref) { return const_cast<Reference<Type>*>(ref); });
|
|
return ret;
|
|
}
|
|
|
|
std::vector<const Reference<Type>*> Type::getStrongReferences() const {
|
|
std::vector<const Reference<Type>*> ret;
|
|
for (const auto* ref : getReferences()) {
|
|
if (!ref->shallowGet()->isNeverStrongReference()) {
|
|
ret.push_back(ref);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
status_t Type::recursivePass(ParseStage stage, const std::function<status_t(Type*)>& func,
|
|
std::unordered_set<const Type*>* visited) {
|
|
if (mParseStage > stage) return OK;
|
|
if (mParseStage < stage) return UNKNOWN_ERROR;
|
|
|
|
if (visited->find(this) != visited->end()) return OK;
|
|
visited->insert(this);
|
|
|
|
status_t err = func(this);
|
|
if (err != OK) return err;
|
|
|
|
for (auto* nextType : getDefinedTypes()) {
|
|
err = nextType->recursivePass(stage, func, visited);
|
|
if (err != OK) return err;
|
|
}
|
|
|
|
for (auto* nextRef : getReferences()) {
|
|
err = nextRef->shallowGet()->recursivePass(stage, func, visited);
|
|
if (err != OK) return err;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t Type::recursivePass(ParseStage stage, const std::function<status_t(const Type*)>& func,
|
|
std::unordered_set<const Type*>* visited) const {
|
|
if (mParseStage > stage) return OK;
|
|
if (mParseStage < stage) return UNKNOWN_ERROR;
|
|
|
|
if (visited->find(this) != visited->end()) return OK;
|
|
visited->insert(this);
|
|
|
|
status_t err = func(this);
|
|
if (err != OK) return err;
|
|
|
|
for (const auto* nextType : getDefinedTypes()) {
|
|
err = nextType->recursivePass(stage, func, visited);
|
|
if (err != OK) return err;
|
|
}
|
|
|
|
for (const auto* nextRef : getReferences()) {
|
|
err = nextRef->shallowGet()->recursivePass(stage, func, visited);
|
|
if (err != OK) return err;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t Type::resolveInheritance() {
|
|
return OK;
|
|
}
|
|
|
|
status_t Type::validate() const {
|
|
return OK;
|
|
}
|
|
|
|
Type::CheckAcyclicStatus::CheckAcyclicStatus(status_t status, const Type* cycleEnd)
|
|
: status(status), cycleEnd(cycleEnd) {
|
|
CHECK(cycleEnd == nullptr || status != OK);
|
|
}
|
|
|
|
Type::CheckAcyclicStatus Type::topologicalOrder(
|
|
std::unordered_map<const Type*, size_t>* reversedOrder,
|
|
std::unordered_set<const Type*>* stack) const {
|
|
if (stack->find(this) != stack->end()) {
|
|
std::cerr << "ERROR: Cyclic declaration:\n";
|
|
return CheckAcyclicStatus(UNKNOWN_ERROR, this);
|
|
}
|
|
|
|
if (reversedOrder->find(this) != reversedOrder->end()) return CheckAcyclicStatus(OK);
|
|
stack->insert(this);
|
|
|
|
for (const auto* nextType : getDefinedTypes()) {
|
|
auto err = nextType->topologicalOrder(reversedOrder, stack);
|
|
|
|
if (err.status != OK) {
|
|
if (err.cycleEnd == nullptr) return err;
|
|
|
|
std::cerr << " '" << nextType->typeName() << "' in '" << typeName() << "'";
|
|
if (nextType->isNamedType()) {
|
|
std::cerr << " at " << static_cast<const NamedType*>(nextType)->location();
|
|
}
|
|
std::cerr << "\n";
|
|
|
|
if (err.cycleEnd == this) {
|
|
return CheckAcyclicStatus(err.status);
|
|
}
|
|
return err;
|
|
}
|
|
}
|
|
|
|
for (const auto* nextRef : getStrongReferences()) {
|
|
const auto* nextType = nextRef->shallowGet();
|
|
auto err = nextType->topologicalOrder(reversedOrder, stack);
|
|
|
|
if (err.status != OK) {
|
|
if (err.cycleEnd == nullptr) return err;
|
|
|
|
std::cerr << " '" << nextType->typeName() << "' in '" << typeName() << "' at "
|
|
<< nextRef->location() << "\n";
|
|
|
|
if (err.cycleEnd == this) {
|
|
return CheckAcyclicStatus(err.status);
|
|
}
|
|
return err;
|
|
}
|
|
}
|
|
|
|
CHECK(stack->find(this) != stack->end());
|
|
stack->erase(this);
|
|
|
|
CHECK(reversedOrder->find(this) == reversedOrder->end());
|
|
// Do not call insert and size in one statement to not rely on
|
|
// evaluation order.
|
|
size_t index = reversedOrder->size();
|
|
reversedOrder->insert({this, index});
|
|
|
|
return CheckAcyclicStatus(OK);
|
|
}
|
|
|
|
status_t Type::checkForwardReferenceRestrictions(const Reference<Type>& ref) const {
|
|
const Location& refLoc = ref.location();
|
|
const Type* refType = ref.shallowGet();
|
|
|
|
// Not NamedTypes are avaiable everywhere.
|
|
// Only ArrayType and TemplatedType contain additional types in
|
|
// their reference (which is actually a part of type definition),
|
|
// so they are proceeded in this case.
|
|
//
|
|
// If we support named templated types one day, we will need to change
|
|
// this logic.
|
|
if (!refType->isNamedType()) {
|
|
for (const Reference<Type>* innerRef : refType->getReferences()) {
|
|
status_t err = checkForwardReferenceRestrictions(*innerRef);
|
|
if (err != OK) return err;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
const Location& typeLoc = static_cast<const NamedType*>(refType)->location();
|
|
|
|
// If referenced type is declared in another file or before reference,
|
|
// there is no forward reference here.
|
|
if (!Location::inSameFile(refLoc, typeLoc) ||
|
|
(!Location::intersect(refLoc, typeLoc) && typeLoc < refLoc)) {
|
|
return OK;
|
|
}
|
|
|
|
// Type must be declared somewhere in the current stack to make it
|
|
// available for forward referencing.
|
|
const Type* refTypeParent = refType->parent();
|
|
for (const Type* ancestor = this; ancestor != nullptr; ancestor = ancestor->parent()) {
|
|
if (ancestor == refTypeParent) return OK;
|
|
}
|
|
|
|
std::cerr << "ERROR: Forward reference of '" << refType->typeName() << "' at " << ref.location()
|
|
<< " is not supported.\n"
|
|
<< "C++ forward declaration doesn't support inner types.\n";
|
|
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
const ScalarType *Type::resolveToScalarType() const {
|
|
return nullptr;
|
|
}
|
|
|
|
bool Type::isValidEnumStorageType() const {
|
|
const ScalarType *scalarType = resolveToScalarType();
|
|
|
|
if (scalarType == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return scalarType->isValidEnumStorageType();
|
|
}
|
|
|
|
bool Type::isElidableType() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::canCheckEquality() const {
|
|
std::unordered_set<const Type*> visited;
|
|
return canCheckEquality(&visited);
|
|
}
|
|
|
|
bool Type::canCheckEquality(std::unordered_set<const Type*>* visited) const {
|
|
// See isJavaCompatible for similar structure.
|
|
if (visited->find(this) != visited->end()) {
|
|
return true;
|
|
}
|
|
visited->insert(this);
|
|
return deepCanCheckEquality(visited);
|
|
}
|
|
|
|
bool Type::deepCanCheckEquality(std::unordered_set<const Type*>* /* visited */) const {
|
|
return false;
|
|
}
|
|
|
|
Type::ParseStage Type::getParseStage() const {
|
|
return mParseStage;
|
|
}
|
|
|
|
void Type::setParseStage(ParseStage stage) {
|
|
CHECK(mParseStage < stage);
|
|
mParseStage = stage;
|
|
}
|
|
|
|
Scope* Type::parent() {
|
|
return mParent;
|
|
}
|
|
|
|
const Scope* Type::parent() const {
|
|
return mParent;
|
|
}
|
|
|
|
const std::string& Type::definedName() const {
|
|
return mDefinedName;
|
|
}
|
|
|
|
std::string Type::getCppType(StorageMode, bool) const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
return std::string();
|
|
}
|
|
|
|
std::string Type::decorateCppName(
|
|
const std::string &name, StorageMode mode, bool specifyNamespaces) const {
|
|
return getCppType(mode, specifyNamespaces) + " " + name;
|
|
}
|
|
|
|
std::string Type::getJavaType(bool /* forInitializer */) const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
return std::string();
|
|
}
|
|
|
|
std::string Type::getJavaTypeClass() const {
|
|
return getJavaType();
|
|
}
|
|
|
|
std::string Type::getJavaTypeCast(const std::string& objName) const {
|
|
return "(" + getJavaType() + ") " + objName;
|
|
}
|
|
|
|
std::string Type::getJavaSuffix() const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
return std::string();
|
|
}
|
|
|
|
std::string Type::getVtsType() const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
return std::string();
|
|
}
|
|
|
|
std::string Type::getVtsValueName() const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
return std::string();
|
|
}
|
|
|
|
void Type::emitReaderWriter(
|
|
Formatter &,
|
|
const std::string &,
|
|
const std::string &,
|
|
bool,
|
|
bool,
|
|
ErrorMode) const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
}
|
|
|
|
void Type::emitDump(
|
|
Formatter &out,
|
|
const std::string &streamName,
|
|
const std::string &name) const {
|
|
emitDumpWithMethod(out, streamName, "::android::hardware::toString", name);
|
|
}
|
|
|
|
void Type::emitDumpWithMethod(
|
|
Formatter &out,
|
|
const std::string &streamName,
|
|
const std::string &methodName,
|
|
const std::string &name) const {
|
|
out << streamName
|
|
<< " += "
|
|
<< methodName
|
|
<< "("
|
|
<< name
|
|
<< ");\n";
|
|
}
|
|
|
|
void Type::emitJavaDump(
|
|
Formatter &out,
|
|
const std::string &streamName,
|
|
const std::string &name) const {
|
|
out << streamName << ".append(" << name << ");\n";
|
|
}
|
|
|
|
void Type::emitReaderWriterEmbedded(
|
|
Formatter &,
|
|
size_t,
|
|
const std::string &,
|
|
const std::string &,
|
|
bool,
|
|
const std::string &,
|
|
bool,
|
|
bool,
|
|
ErrorMode,
|
|
const std::string &,
|
|
const std::string &) const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
}
|
|
|
|
void Type::emitJavaReaderWriter(
|
|
Formatter &out,
|
|
const std::string &parcelObj,
|
|
const std::string &argName,
|
|
bool isReader) const {
|
|
emitJavaReaderWriterWithSuffix(
|
|
out,
|
|
parcelObj,
|
|
argName,
|
|
isReader,
|
|
getJavaSuffix(),
|
|
"" /* extra */);
|
|
}
|
|
|
|
void Type::emitJavaFieldInitializer(
|
|
Formatter &out,
|
|
const std::string &fieldName) const {
|
|
out << getJavaType()
|
|
<< " "
|
|
<< fieldName
|
|
<< ";\n";
|
|
}
|
|
|
|
void Type::emitJavaFieldDefaultInitialValue(Formatter &, const std::string &) const {}
|
|
|
|
void Type::emitJavaFieldReaderWriter(
|
|
Formatter &,
|
|
size_t,
|
|
const std::string &,
|
|
const std::string &,
|
|
const std::string &,
|
|
const std::string &,
|
|
bool) const {
|
|
CHECK(!"Should not be here") << typeName();
|
|
}
|
|
|
|
void Type::handleError(Formatter &out, ErrorMode mode) {
|
|
switch (mode) {
|
|
case ErrorMode_Goto:
|
|
{
|
|
out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
|
|
break;
|
|
}
|
|
|
|
case ErrorMode_Break:
|
|
{
|
|
out << "if (_hidl_err != ::android::OK) { break; }\n\n";
|
|
break;
|
|
}
|
|
|
|
case ErrorMode_Return:
|
|
{
|
|
out << "if (_hidl_err != ::android::OK) { return _hidl_err; }\n\n";
|
|
break;
|
|
}
|
|
|
|
case ErrorMode_ReturnNothing:
|
|
{
|
|
out << "if (_hidl_err != ::android::OK) { return; }\n\n";
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
LOG(FATAL) << "Should not be here";
|
|
}
|
|
}
|
|
}
|
|
|
|
void Type::emitReaderWriterEmbeddedForTypeName(
|
|
Formatter &out,
|
|
const std::string &name,
|
|
bool nameIsPointer,
|
|
const std::string &parcelObj,
|
|
bool parcelObjIsPointer,
|
|
bool isReader,
|
|
ErrorMode mode,
|
|
const std::string &parentName,
|
|
const std::string &offsetText,
|
|
const std::string &typeName,
|
|
const std::string &childName,
|
|
const std::string &funcNamespace) const {
|
|
|
|
const std::string parcelObjDeref =
|
|
parcelObjIsPointer ? ("*" + parcelObj) : parcelObj;
|
|
|
|
const std::string parcelObjPointer =
|
|
parcelObjIsPointer ? parcelObj : ("&" + parcelObj);
|
|
|
|
const std::string nameDerefed = nameIsPointer ? ("*" + name) : name;
|
|
const std::string namePointer = nameIsPointer ? name : ("&" + name);
|
|
|
|
out << "_hidl_err = ";
|
|
|
|
if (!funcNamespace.empty()) {
|
|
out << funcNamespace << "::";
|
|
}
|
|
|
|
out << (isReader ? "readEmbeddedFromParcel(\n" : "writeEmbeddedToParcel(\n");
|
|
|
|
out.indent();
|
|
out.indent();
|
|
|
|
if (isReader) {
|
|
out << "const_cast<"
|
|
<< typeName
|
|
<< " &>("
|
|
<< nameDerefed
|
|
<< "),\n";
|
|
} else {
|
|
out << nameDerefed
|
|
<< ",\n";
|
|
}
|
|
|
|
out << (isReader ? parcelObjDeref : parcelObjPointer)
|
|
<< ",\n"
|
|
<< parentName
|
|
<< ",\n"
|
|
<< offsetText;
|
|
|
|
if (!childName.empty()) {
|
|
out << ", &"
|
|
<< childName;
|
|
}
|
|
|
|
out << ");\n\n";
|
|
|
|
out.unindent();
|
|
out.unindent();
|
|
|
|
handleError(out, mode);
|
|
}
|
|
|
|
void Type::emitHidlDefinition(Formatter&) const {
|
|
CHECK(!"Should not be here.") << typeName();
|
|
}
|
|
|
|
void Type::emitTypeDeclarations(Formatter&) const {}
|
|
|
|
void Type::emitTypeForwardDeclaration(Formatter&) const {}
|
|
|
|
void Type::emitGlobalTypeDeclarations(Formatter&) const {}
|
|
|
|
void Type::emitPackageTypeDeclarations(Formatter&) const {}
|
|
|
|
void Type::emitPackageTypeHeaderDefinitions(Formatter&) const {}
|
|
|
|
void Type::emitPackageHwDeclarations(Formatter&) const {}
|
|
|
|
void Type::emitTypeDefinitions(Formatter&, const std::string&) const {}
|
|
|
|
void Type::emitJavaTypeDeclarations(Formatter&, bool) const {}
|
|
|
|
bool Type::needsEmbeddedReadWrite() const {
|
|
return false;
|
|
}
|
|
|
|
bool Type::resultNeedsDeref() const {
|
|
return false;
|
|
}
|
|
|
|
std::string Type::getCppStackType(bool specifyNamespaces) const {
|
|
return getCppType(StorageMode_Stack, specifyNamespaces);
|
|
}
|
|
|
|
std::string Type::getCppResultType(bool specifyNamespaces) const {
|
|
return getCppType(StorageMode_Result, specifyNamespaces);
|
|
}
|
|
|
|
std::string Type::getCppArgumentType(bool specifyNamespaces) const {
|
|
return getCppType(StorageMode_Argument, specifyNamespaces);
|
|
}
|
|
|
|
std::string Type::getCppTypeCast(const std::string& objName, bool specifyNamespaces) const {
|
|
return "static_cast<" + getCppStackType(specifyNamespaces) + ">(" + objName + ")";
|
|
}
|
|
|
|
void Type::emitJavaReaderWriterWithSuffix(
|
|
Formatter &out,
|
|
const std::string &parcelObj,
|
|
const std::string &argName,
|
|
bool isReader,
|
|
const std::string &suffix,
|
|
const std::string &extra) const {
|
|
out << parcelObj
|
|
<< "."
|
|
<< (isReader ? "read" : "write")
|
|
<< suffix
|
|
<< "(";
|
|
|
|
if (isReader) {
|
|
out << extra;
|
|
} else {
|
|
out << (extra.empty() ? "" : (extra + ", "));
|
|
out << argName;
|
|
}
|
|
|
|
out << ");\n";
|
|
}
|
|
|
|
void Type::emitVtsTypeDeclarations(Formatter&) const {}
|
|
|
|
void Type::emitVtsAttributeType(Formatter& out) const {
|
|
emitVtsTypeDeclarations(out);
|
|
}
|
|
|
|
bool Type::isJavaCompatible() const {
|
|
std::unordered_set<const Type*> visited;
|
|
return isJavaCompatible(&visited);
|
|
}
|
|
|
|
bool Type::containsPointer() const {
|
|
std::unordered_set<const Type*> visited;
|
|
return containsPointer(&visited);
|
|
}
|
|
|
|
bool Type::isJavaCompatible(std::unordered_set<const Type*>* visited) const {
|
|
// We need to find al least one path from requested vertex
|
|
// to not java compatible.
|
|
// That means that if we have already visited some vertex,
|
|
// there is no need to determine whether it is java compatible
|
|
// (and we can assume that it is java compatible),
|
|
// as if not, the information about that would appear in the
|
|
// requested vertex through another path.
|
|
if (visited->find(this) != visited->end()) {
|
|
return true;
|
|
}
|
|
visited->insert(this);
|
|
return deepIsJavaCompatible(visited);
|
|
}
|
|
|
|
bool Type::containsPointer(std::unordered_set<const Type*>* visited) const {
|
|
// See isJavaCompatible for similar structure.
|
|
if (visited->find(this) != visited->end()) {
|
|
return false;
|
|
}
|
|
visited->insert(this);
|
|
return deepContainsPointer(visited);
|
|
}
|
|
|
|
bool Type::deepIsJavaCompatible(std::unordered_set<const Type*>* /* visited */) const {
|
|
return true;
|
|
}
|
|
|
|
bool Type::deepContainsPointer(std::unordered_set<const Type*>* /* visited */) const {
|
|
return false;
|
|
}
|
|
|
|
void Type::getAlignmentAndSize(
|
|
size_t * /* align */, size_t * /* size */) const {
|
|
CHECK(!"Should not be here.") << typeName();
|
|
}
|
|
|
|
void Type::appendToExportedTypesVector(
|
|
std::vector<const Type *> * /* exportedTypes */) const {
|
|
}
|
|
|
|
void Type::emitExportedHeader(Formatter& /* out */, bool /* forJava */) const {}
|
|
|
|
bool Type::isNeverStrongReference() const {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
TemplatedType::TemplatedType(Scope* parent, const std::string& definedName)
|
|
: Type(parent, definedName) {}
|
|
|
|
std::string TemplatedType::typeName() const {
|
|
return templatedTypeName() + " of " + mElementType->typeName();
|
|
}
|
|
|
|
void TemplatedType::setElementType(const Reference<Type>& elementType) {
|
|
// can only be set once.
|
|
CHECK(mElementType.isEmptyReference());
|
|
CHECK(!elementType.isEmptyReference());
|
|
|
|
mElementType = elementType;
|
|
mDefinedName = mDefinedName + "<" + mElementType.localName() + ">";
|
|
}
|
|
|
|
const Type* TemplatedType::getElementType() const {
|
|
return mElementType.get();
|
|
}
|
|
|
|
bool TemplatedType::isTemplatedType() const {
|
|
return true;
|
|
}
|
|
|
|
std::vector<const Reference<Type>*> TemplatedType::getReferences() const {
|
|
return {&mElementType};
|
|
}
|
|
|
|
status_t TemplatedType::validate() const {
|
|
if (!isCompatibleElementType(mElementType.get())) {
|
|
std::cerr << "ERROR: " << typeName() /* contains element type */
|
|
<< " is not supported at " << mElementType.location() << "\n";
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return Type::validate();
|
|
}
|
|
|
|
void TemplatedType::emitVtsTypeDeclarations(Formatter& out) const {
|
|
out << "type: " << getVtsType() << "\n";
|
|
out << getVtsValueName() << ": {\n";
|
|
out.indent();
|
|
mElementType->emitVtsTypeDeclarations(out);
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
|
|
void TemplatedType::emitVtsAttributeType(Formatter& out) const {
|
|
out << "type: " << getVtsType() << "\n";
|
|
out << getVtsValueName() << ": {\n";
|
|
out.indent();
|
|
mElementType->emitVtsAttributeType(out);
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
|
|
} // namespace android
|
|
|