/* * 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 #include #include #include #include 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(static_cast(this)->resolve()); } const Type* Type::resolve() const { return this; } std::vector Type::getDefinedTypes() { const auto& constRet = static_cast(this)->getDefinedTypes(); std::vector ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* type) { return const_cast(type); }); return ret; } std::vector Type::getDefinedTypes() const { return {}; } std::vector*> Type::getReferences() { const auto& constRet = static_cast(this)->getReferences(); std::vector*> ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* ref) { return const_cast*>(ref); }); return ret; } std::vector*> Type::getReferences() const { return {}; } std::vector Type::getConstantExpressions() { const auto& constRet = static_cast(this)->getConstantExpressions(); std::vector ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* ce) { return const_cast(ce); }); return ret; } std::vector Type::getConstantExpressions() const { return {}; } std::vector*> Type::getStrongReferences() { const auto& constRet = static_cast(this)->getStrongReferences(); std::vector*> ret(constRet.size()); std::transform(constRet.begin(), constRet.end(), ret.begin(), [](const auto* ref) { return const_cast*>(ref); }); return ret; } std::vector*> Type::getStrongReferences() const { std::vector*> 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& func, std::unordered_set* 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& func, std::unordered_set* 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* reversedOrder, std::unordered_set* 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(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& 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* innerRef : refType->getReferences()) { status_t err = checkForwardReferenceRestrictions(*innerRef); if (err != OK) return err; } return OK; } const Location& typeLoc = static_cast(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 visited; return canCheckEquality(&visited); } bool Type::canCheckEquality(std::unordered_set* 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* /* 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 "(" + 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 visited; return isJavaCompatible(&visited); } bool Type::containsPointer() const { std::unordered_set visited; return containsPointer(&visited); } bool Type::isJavaCompatible(std::unordered_set* 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* 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* /* visited */) const { return true; } bool Type::deepContainsPointer(std::unordered_set* /* 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 * /* 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& 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*> 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