EnumType.cpp revision 870d1a7ccd70bd710128993de401278614d1975e
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "EnumType.h" 18 19#include "Annotation.h" 20#include "ScalarType.h" 21 22#include <inttypes.h> 23#include <hidl-util/Formatter.h> 24#include <android-base/logging.h> 25 26namespace android { 27 28EnumType::EnumType( 29 const char *localName, 30 const Location &location, 31 Type *storageType) 32 : Scope(localName, location), 33 mValues(), 34 mStorageType(storageType) { 35} 36 37const Type *EnumType::storageType() const { 38 return mStorageType; 39} 40 41const std::vector<EnumValue *> &EnumType::values() const { 42 return mValues; 43} 44 45void EnumType::addValue(EnumValue *value) { 46 CHECK(value != nullptr); 47 48 EnumValue *prev = nullptr; 49 std::vector<const EnumType *> chain; 50 getTypeChain(&chain); 51 for (auto it = chain.begin(); it != chain.end(); ++it) { 52 const auto &type = *it; 53 if(!type->values().empty()) { 54 prev = type->values().back(); 55 break; 56 } 57 } 58 59 value->autofill(prev, resolveToScalarType()); 60 mValues.push_back(value); 61} 62 63bool EnumType::isElidableType() const { 64 return mStorageType->isElidableType(); 65} 66 67const ScalarType *EnumType::resolveToScalarType() const { 68 return mStorageType->resolveToScalarType(); 69} 70 71std::string EnumType::typeName() const { 72 return "enum " + localName(); 73} 74 75bool EnumType::isEnum() const { 76 return true; 77} 78 79bool EnumType::canCheckEquality() const { 80 return true; 81} 82 83std::string EnumType::getCppType(StorageMode, 84 bool specifyNamespaces) const { 85 return specifyNamespaces ? fullName() : partialCppName(); 86} 87 88std::string EnumType::getJavaType(bool forInitializer) const { 89 return mStorageType->resolveToScalarType()->getJavaType(forInitializer); 90} 91 92std::string EnumType::getJavaSuffix() const { 93 return mStorageType->resolveToScalarType()->getJavaSuffix(); 94} 95 96std::string EnumType::getJavaWrapperType() const { 97 return mStorageType->resolveToScalarType()->getJavaWrapperType(); 98} 99 100std::string EnumType::getVtsType() const { 101 return "TYPE_ENUM"; 102} 103 104LocalIdentifier *EnumType::lookupIdentifier(const std::string &name) const { 105 std::vector<const EnumType *> chain; 106 getTypeChain(&chain); 107 for (auto it = chain.begin(); it != chain.end(); ++it) { 108 const auto &type = *it; 109 for(EnumValue *v : type->values()) { 110 if(v->name() == name) { 111 return v; 112 } 113 } 114 } 115 return nullptr; 116} 117 118void EnumType::emitReaderWriter( 119 Formatter &out, 120 const std::string &name, 121 const std::string &parcelObj, 122 bool parcelObjIsPointer, 123 bool isReader, 124 ErrorMode mode) const { 125 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 126 CHECK(scalarType != NULL); 127 128 scalarType->emitReaderWriterWithCast( 129 out, 130 name, 131 parcelObj, 132 parcelObjIsPointer, 133 isReader, 134 mode, 135 true /* needsCast */); 136} 137 138void EnumType::emitJavaFieldReaderWriter( 139 Formatter &out, 140 size_t depth, 141 const std::string &parcelName, 142 const std::string &blobName, 143 const std::string &fieldName, 144 const std::string &offset, 145 bool isReader) const { 146 return mStorageType->emitJavaFieldReaderWriter( 147 out, depth, parcelName, blobName, fieldName, offset, isReader); 148} 149 150status_t EnumType::emitTypeDeclarations(Formatter &out) const { 151 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 152 CHECK(scalarType != nullptr); 153 154 const std::string storageType = scalarType->getCppStackType(); 155 156 out << "enum class " 157 << localName() 158 << " : " 159 << storageType 160 << " {\n"; 161 162 out.indent(); 163 164 std::vector<const EnumType *> chain; 165 getTypeChain(&chain); 166 167 for (auto it = chain.rbegin(); it != chain.rend(); ++it) { 168 const auto &type = *it; 169 170 for (const auto &entry : type->values()) { 171 out << entry->name(); 172 173 std::string value = entry->cppValue(scalarType->getKind()); 174 CHECK(!value.empty()); // use autofilled values for c++. 175 out << " = " << value; 176 177 out << ","; 178 179 std::string comment = entry->comment(); 180 if (!comment.empty() && comment != value) { 181 out << " // " << comment; 182 } 183 184 out << "\n"; 185 } 186 } 187 188 out.unindent(); 189 out << "};\n\n"; 190 191 return OK; 192} 193 194void EnumType::emitEnumBitwiseOperator( 195 Formatter &out, 196 bool lhsIsEnum, 197 bool rhsIsEnum, 198 const std::string &op) const { 199 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 200 CHECK(scalarType != nullptr); 201 202 const std::string storageType = scalarType->getCppStackType(); 203 204 out << "constexpr " 205 << storageType 206 << " operator" 207 << op 208 << "(const " 209 << (lhsIsEnum ? fullName() : storageType) 210 << " lhs, const " 211 << (rhsIsEnum ? fullName() : storageType) 212 << " rhs) {\n"; 213 214 out.indent([&] { 215 out << "return static_cast<" 216 << storageType 217 << ">("; 218 219 if (lhsIsEnum) { 220 out << "static_cast<" 221 << storageType 222 << ">(lhs)"; 223 } else { 224 out << "lhs"; 225 } 226 out << " " << op << " "; 227 if (rhsIsEnum) { 228 out << "static_cast<" 229 << storageType 230 << ">(rhs)"; 231 } else { 232 out << "rhs"; 233 } 234 out << ");\n"; 235 }); 236 237 out << "}\n\n"; 238} 239 240void EnumType::emitBitFieldBitwiseAssignmentOperator( 241 Formatter &out, 242 const std::string &op) const { 243 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 244 CHECK(scalarType != nullptr); 245 246 const std::string storageType = scalarType->getCppStackType(); 247 248 out << "constexpr " << storageType << " &operator" << op << "=(" 249 << storageType << "& v, const " << fullName() << " e) {\n"; 250 251 out.indent([&] { 252 out << "v " << op << "= static_cast<" << storageType << ">(e);\n"; 253 out << "return v;\n"; 254 }); 255 256 out << "}\n\n"; 257} 258 259status_t EnumType::emitGlobalTypeDeclarations(Formatter &out) const { 260 emitEnumBitwiseOperator(out, true /* lhsIsEnum */, true /* rhsIsEnum */, "|"); 261 emitEnumBitwiseOperator(out, false /* lhsIsEnum */, true /* rhsIsEnum */, "|"); 262 emitEnumBitwiseOperator(out, true /* lhsIsEnum */, false /* rhsIsEnum */, "|"); 263 emitEnumBitwiseOperator(out, true /* lhsIsEnum */, true /* rhsIsEnum */, "&"); 264 emitEnumBitwiseOperator(out, false /* lhsIsEnum */, true /* rhsIsEnum */, "&"); 265 emitEnumBitwiseOperator(out, true /* lhsIsEnum */, false /* rhsIsEnum */, "&"); 266 267 emitBitFieldBitwiseAssignmentOperator(out, "|"); 268 emitBitFieldBitwiseAssignmentOperator(out, "&"); 269 270 // toString for bitfields, equivalent to dumpBitfield in Java 271 out << "template<typename>\n" 272 << "std::string toString(" 273 << resolveToScalarType()->getCppArgumentType() 274 << " o);\n"; 275 out << "template<>\n" 276 << "std::string toString<" << getCppStackType() << ">(" 277 << resolveToScalarType()->getCppArgumentType() 278 << " o);\n\n"; 279 280 // toString for enum itself 281 out << "std::string toString(" 282 << getCppArgumentType() 283 << " o);\n\n"; 284 285 return OK; 286} 287 288status_t EnumType::emitTypeDefinitions(Formatter &out, const std::string /* prefix */) const { 289 290 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 291 CHECK(scalarType != NULL); 292 293 out << "template<>\n" 294 << "std::string toString<" << getCppStackType() << ">(" 295 << scalarType->getCppArgumentType() 296 << " o) "; 297 out.block([&] { 298 // include toHexString for scalar types 299 out << "using ::android::hardware::details::toHexString;\n" 300 << "std::string os;\n" 301 << getBitfieldType()->getCppStackType() << " flipped = 0;\n" 302 << "bool first = true;\n"; 303 for (EnumValue *value : values()) { 304 std::string valueName = fullName() + "::" + value->name(); 305 out.sIf("(o & " + valueName + ")" + 306 " == static_cast<" + scalarType->getCppStackType() + 307 ">(" + valueName + ")", [&] { 308 out << "os += (first ? \"\" : \" | \");\n" 309 << "os += \"" << value->name() << "\";\n" 310 << "first = false;\n" 311 << "flipped |= " << valueName << ";\n"; 312 }).endl(); 313 } 314 // put remaining bits 315 out.sIf("o != flipped", [&] { 316 out << "os += (first ? \"\" : \" | \");\n"; 317 scalarType->emitHexDump(out, "os", "o & (~flipped)"); 318 }); 319 out << "os += \" (\";\n"; 320 scalarType->emitHexDump(out, "os", "o"); 321 out << "os += \")\";\n"; 322 323 out << "return os;\n"; 324 }).endl().endl(); 325 326 out << "std::string toString(" 327 << getCppArgumentType() 328 << " o) "; 329 330 out.block([&] { 331 out << "using ::android::hardware::details::toHexString;\n"; 332 for (EnumValue *value : values()) { 333 out.sIf("o == " + fullName() + "::" + value->name(), [&] { 334 out << "return \"" << value->name() << "\";\n"; 335 }).endl(); 336 } 337 out << "std::string os;\n"; 338 scalarType->emitHexDump(out, "os", 339 "static_cast<" + scalarType->getCppStackType() + ">(o)"); 340 out << "return os;\n"; 341 }).endl().endl(); 342 343 return OK; 344} 345 346status_t EnumType::emitJavaTypeDeclarations(Formatter &out, bool) const { 347 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 348 CHECK(scalarType != NULL); 349 350 out << "public final class " 351 << localName() 352 << " {\n"; 353 354 out.indent(); 355 356 const std::string typeName = 357 scalarType->getJavaType(false /* forInitializer */); 358 359 std::vector<const EnumType *> chain; 360 getTypeChain(&chain); 361 362 for (auto it = chain.rbegin(); it != chain.rend(); ++it) { 363 const auto &type = *it; 364 365 for (const auto &entry : type->values()) { 366 out << "public static final " 367 << typeName 368 << " " 369 << entry->name() 370 << " = "; 371 372 // javaValue will make the number signed. 373 std::string value = entry->javaValue(scalarType->getKind()); 374 CHECK(!value.empty()); // use autofilled values for java. 375 out << value; 376 377 out << ";"; 378 379 std::string comment = entry->comment(); 380 if (!comment.empty() && comment != value) { 381 out << " // " << comment; 382 } 383 384 out << "\n"; 385 } 386 } 387 388 out.unindent(); 389 out << "};\n\n"; 390 391 return OK; 392} 393 394status_t EnumType::emitVtsTypeDeclarations(Formatter &out) const { 395 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 396 397 out << "name: \"" << fullName() << "\"\n"; 398 out << "type: " << getVtsType() << "\n"; 399 out << "enum_value: {\n"; 400 out.indent(); 401 402 out << "scalar_type: \"" 403 << scalarType->getVtsScalarType() 404 << "\"\n\n"; 405 std::vector<const EnumType *> chain; 406 getTypeChain(&chain); 407 408 for (auto it = chain.rbegin(); it != chain.rend(); ++it) { 409 const auto &type = *it; 410 411 for (const auto &entry : type->values()) { 412 out << "enumerator: \"" << entry->name() << "\"\n"; 413 out << "scalar_value: {\n"; 414 out.indent(); 415 // use autofilled values for vts. 416 std::string value = entry->value(scalarType->getKind()); 417 CHECK(!value.empty()); 418 out << mStorageType->resolveToScalarType()->getVtsScalarType() 419 << ": " 420 << value 421 << "\n"; 422 out.unindent(); 423 out << "}\n"; 424 } 425 } 426 427 out.unindent(); 428 out << "}\n"; 429 return OK; 430} 431 432status_t EnumType::emitVtsAttributeType(Formatter &out) const { 433 out << "type: " << getVtsType() << "\n"; 434 out << "predefined_type: \"" << fullName() << "\"\n"; 435 return OK; 436} 437 438void EnumType::getTypeChain(std::vector<const EnumType *> *out) const { 439 out->clear(); 440 const EnumType *type = this; 441 for (;;) { 442 out->push_back(type); 443 444 const Type *superType = type->storageType(); 445 if (superType == NULL || !superType->isEnum()) { 446 break; 447 } 448 449 type = static_cast<const EnumType *>(superType); 450 } 451} 452 453void EnumType::getAlignmentAndSize(size_t *align, size_t *size) const { 454 mStorageType->getAlignmentAndSize(align, size); 455} 456 457const Annotation *EnumType::findExportAnnotation() const { 458 for (const auto &annotation : annotations()) { 459 if (annotation->name() == "export") { 460 return annotation; 461 } 462 } 463 464 return nullptr; 465} 466 467void EnumType::appendToExportedTypesVector( 468 std::vector<const Type *> *exportedTypes) const { 469 if (findExportAnnotation() != nullptr) { 470 exportedTypes->push_back(this); 471 } 472} 473 474status_t EnumType::emitExportedHeader(Formatter &out, bool forJava) const { 475 const Annotation *annotation = findExportAnnotation(); 476 CHECK(annotation != nullptr); 477 478 std::string name = localName(); 479 480 const AnnotationParam *nameParam = annotation->getParam("name"); 481 if (nameParam != nullptr) { 482 name = nameParam->getSingleString(); 483 } 484 485 bool exportParent = true; 486 const AnnotationParam *exportParentParam = annotation->getParam("export_parent"); 487 if (exportParentParam != nullptr) { 488 exportParent = exportParentParam->getSingleBool(); 489 } 490 491 std::string valuePrefix; 492 const AnnotationParam *prefixParam = annotation->getParam("value_prefix"); 493 if (prefixParam != nullptr) { 494 valuePrefix = prefixParam->getSingleString(); 495 } 496 497 std::string valueSuffix; 498 const AnnotationParam *suffixParam = annotation->getParam("value_suffix"); 499 if (suffixParam != nullptr) { 500 valueSuffix = suffixParam->getSingleString(); 501 } 502 503 const ScalarType *scalarType = mStorageType->resolveToScalarType(); 504 CHECK(scalarType != nullptr); 505 506 std::vector<const EnumType *> chain; 507 if (exportParent) { 508 getTypeChain(&chain); 509 } else { 510 chain = { this }; 511 } 512 513 if (forJava) { 514 if (!name.empty()) { 515 out << "public final class " 516 << name 517 << " {\n"; 518 519 out.indent(); 520 } else { 521 out << "// Values declared in " << localName() << " follow.\n"; 522 } 523 524 const std::string typeName = 525 scalarType->getJavaType(false /* forInitializer */); 526 527 for (auto it = chain.rbegin(); it != chain.rend(); ++it) { 528 const auto &type = *it; 529 530 for (const auto &entry : type->values()) { 531 out << "public static final " 532 << typeName 533 << " " 534 << valuePrefix 535 << entry->name() 536 << valueSuffix 537 << " = "; 538 539 // javaValue will make the number signed. 540 std::string value = entry->javaValue(scalarType->getKind()); 541 CHECK(!value.empty()); // use autofilled values for java. 542 out << value; 543 544 out << ";"; 545 546 std::string comment = entry->comment(); 547 if (!comment.empty() && comment != value) { 548 out << " // " << comment; 549 } 550 551 out << "\n"; 552 } 553 } 554 555 if (!name.empty()) { 556 out.unindent(); 557 out << "};\n"; 558 } 559 out << "\n"; 560 561 return OK; 562 } 563 564 if (!name.empty()) { 565 out << "typedef "; 566 } 567 568 out << "enum {\n"; 569 570 out.indent(); 571 572 for (auto it = chain.rbegin(); it != chain.rend(); ++it) { 573 const auto &type = *it; 574 575 for (const auto &entry : type->values()) { 576 out << valuePrefix << entry->name() << valueSuffix; 577 578 std::string value = entry->cppValue(scalarType->getKind()); 579 CHECK(!value.empty()); // use autofilled values for c++. 580 out << " = " << value; 581 582 out << ","; 583 584 std::string comment = entry->comment(); 585 if (!comment.empty() && comment != value) { 586 out << " // " << comment; 587 } 588 589 out << "\n"; 590 } 591 } 592 593 out.unindent(); 594 out << "}"; 595 596 if (!name.empty()) { 597 out << " " << name; 598 } 599 600 out << ";\n\n"; 601 602 return OK; 603} 604 605//////////////////////////////////////////////////////////////////////////////// 606 607EnumValue::EnumValue(const char *name, ConstantExpression *value) 608 : mName(name), 609 mValue(value), 610 mIsAutoFill(false) { 611} 612 613std::string EnumValue::name() const { 614 return mName; 615} 616 617std::string EnumValue::value(ScalarType::Kind castKind) const { 618 CHECK(mValue != nullptr); 619 return mValue->value(castKind); 620} 621 622std::string EnumValue::cppValue(ScalarType::Kind castKind) const { 623 CHECK(mValue != nullptr); 624 return mValue->cppValue(castKind); 625} 626std::string EnumValue::javaValue(ScalarType::Kind castKind) const { 627 CHECK(mValue != nullptr); 628 return mValue->javaValue(castKind); 629} 630 631std::string EnumValue::comment() const { 632 CHECK(mValue != nullptr); 633 return mValue->description(); 634} 635 636ConstantExpression *EnumValue::constExpr() const { 637 CHECK(mValue != nullptr); 638 return mValue; 639} 640 641void EnumValue::autofill(const EnumValue *prev, const ScalarType *type) { 642 if(mValue != nullptr) 643 return; 644 mIsAutoFill = true; 645 ConstantExpression *value = new ConstantExpression(); 646 if(prev == nullptr) { 647 *value = ConstantExpression::Zero(type->getKind()); 648 } else { 649 CHECK(prev->mValue != nullptr); 650 *value = prev->mValue->addOne(); 651 } 652 mValue = value; 653} 654 655bool EnumValue::isAutoFill() const { 656 return mIsAutoFill; 657} 658 659bool EnumValue::isEnumValue() const { 660 return true; 661} 662 663//////////////////////////////////////////////////////////////////////////////// 664 665bool BitFieldType::isBitField() const { 666 return true; 667} 668 669std::string BitFieldType::typeName() const { 670 return "mask" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName())); 671} 672 673void BitFieldType::addNamedTypesToSet(std::set<const FQName> &) const { 674} 675 676bool BitFieldType::isCompatibleElementType(Type *elementType) const { 677 return elementType->isEnum(); 678} 679 680const ScalarType *BitFieldType::resolveToScalarType() const { 681 return mElementType->resolveToScalarType(); 682} 683 684std::string BitFieldType::getCppType(StorageMode mode, 685 bool specifyNamespaces) const { 686 return resolveToScalarType()->getCppType(mode, specifyNamespaces); 687} 688 689std::string BitFieldType::getJavaType(bool forInitializer) const { 690 return resolveToScalarType()->getJavaType(forInitializer); 691} 692 693std::string BitFieldType::getJavaSuffix() const { 694 return resolveToScalarType()->getJavaSuffix(); 695} 696 697std::string BitFieldType::getJavaWrapperType() const { 698 return resolveToScalarType()->getJavaWrapperType(); 699} 700 701std::string BitFieldType::getVtsType() const { 702 return "TYPE_MASK"; 703} 704 705bool BitFieldType::isElidableType() const { 706 return resolveToScalarType()->isElidableType(); 707} 708 709bool BitFieldType::canCheckEquality() const { 710 return resolveToScalarType()->canCheckEquality(); 711} 712 713status_t BitFieldType::emitVtsAttributeType(Formatter &out) const { 714 out << "type: " << getVtsType() << "\n"; 715 out << "scalar_type: \"" 716 << mElementType->resolveToScalarType()->getVtsScalarType() 717 << "\"\n"; 718 out << "predefined_type: \"" 719 << static_cast<NamedType *>(mElementType)->fullName() << "\"\n"; 720 return OK; 721} 722 723void BitFieldType::getAlignmentAndSize(size_t *align, size_t *size) const { 724 resolveToScalarType()->getAlignmentAndSize(align, size); 725} 726 727void BitFieldType::emitReaderWriter( 728 Formatter &out, 729 const std::string &name, 730 const std::string &parcelObj, 731 bool parcelObjIsPointer, 732 bool isReader, 733 ErrorMode mode) const { 734 resolveToScalarType()->emitReaderWriterWithCast( 735 out, 736 name, 737 parcelObj, 738 parcelObjIsPointer, 739 isReader, 740 mode, 741 true /* needsCast */); 742} 743 744// a bitfield maps to the underlying scalar type in C++, so operator<< is 745// already defined. We can still emit useful information if the bitfield is 746// in a struct / union by overriding emitDump as below. 747void BitFieldType::emitDump( 748 Formatter &out, 749 const std::string &streamName, 750 const std::string &name) const { 751 CHECK(mElementType->isEnum()); 752 const EnumType *enumType = static_cast<EnumType *>(mElementType); 753 out << streamName << " += "<< enumType->fqName().cppNamespace() 754 << "::toString<" << enumType->getCppStackType() 755 << ">(" << name << ");\n"; 756} 757 758void BitFieldType::emitJavaFieldReaderWriter( 759 Formatter &out, 760 size_t depth, 761 const std::string &parcelName, 762 const std::string &blobName, 763 const std::string &fieldName, 764 const std::string &offset, 765 bool isReader) const { 766 return resolveToScalarType()->emitJavaFieldReaderWriter( 767 out, depth, parcelName, blobName, fieldName, offset, isReader); 768} 769 770} // namespace android 771 772