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