EnumType.cpp revision db1b1b638865a2043c9cddd8c865751e9742b181
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    return OK;
271}
272
273status_t EnumType::emitJavaTypeDeclarations(Formatter &out, bool) const {
274    const ScalarType *scalarType = mStorageType->resolveToScalarType();
275    CHECK(scalarType != NULL);
276
277    out << "public final class "
278        << localName()
279        << " {\n";
280
281    out.indent();
282
283    const std::string typeName =
284        scalarType->getJavaType(false /* forInitializer */);
285
286    std::vector<const EnumType *> chain;
287    getTypeChain(&chain);
288
289    for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
290        const auto &type = *it;
291
292        for (const auto &entry : type->values()) {
293            out << "public static final "
294                << typeName
295                << " "
296                << entry->name()
297                << " = ";
298
299            // javaValue will make the number signed.
300            std::string value = entry->javaValue(scalarType->getKind());
301            CHECK(!value.empty()); // use autofilled values for java.
302            out << value;
303
304            out << ";";
305
306            std::string comment = entry->comment();
307            if (!comment.empty() && comment != value) {
308                out << " // " << comment;
309            }
310
311            out << "\n";
312        }
313    }
314
315    out.unindent();
316    out << "};\n\n";
317
318    return OK;
319}
320
321status_t EnumType::emitVtsTypeDeclarations(Formatter &out) const {
322    const ScalarType *scalarType = mStorageType->resolveToScalarType();
323
324    out << "name: \"" << fullName() << "\"\n";
325    out << "type: " << getVtsType() << "\n";
326    out << "enum_value: {\n";
327    out.indent();
328
329    out << "scalar_type: \""
330        << scalarType->getVtsScalarType()
331        << "\"\n\n";
332    std::vector<const EnumType *> chain;
333    getTypeChain(&chain);
334
335    for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
336        const auto &type = *it;
337
338        for (const auto &entry : type->values()) {
339            out << "enumerator: \"" << entry->name() << "\"\n";
340            out << "scalar_value: {\n";
341            out.indent();
342            // use autofilled values for vts.
343            std::string value = entry->value(scalarType->getKind());
344            CHECK(!value.empty());
345            out << mStorageType->resolveToScalarType()->getVtsScalarType()
346                << ": "
347                << value
348                << "\n";
349            out.unindent();
350            out << "}\n";
351        }
352    }
353
354    out.unindent();
355    out << "}\n";
356    return OK;
357}
358
359status_t EnumType::emitVtsAttributeType(Formatter &out) const {
360    out << "type: " << getVtsType() << "\n";
361    out << "predefined_type: \"" << fullName() << "\"\n";
362    return OK;
363}
364
365void EnumType::getTypeChain(std::vector<const EnumType *> *out) const {
366    out->clear();
367    const EnumType *type = this;
368    for (;;) {
369        out->push_back(type);
370
371        const Type *superType = type->storageType();
372        if (superType == NULL || !superType->isEnum()) {
373            break;
374        }
375
376        type = static_cast<const EnumType *>(superType);
377    }
378}
379
380void EnumType::getAlignmentAndSize(size_t *align, size_t *size) const {
381    mStorageType->getAlignmentAndSize(align, size);
382}
383
384const Annotation *EnumType::findExportAnnotation() const {
385    for (const auto &annotation : annotations()) {
386        if (annotation->name() == "export") {
387            return annotation;
388        }
389    }
390
391    return nullptr;
392}
393
394void EnumType::appendToExportedTypesVector(
395        std::vector<const Type *> *exportedTypes) const {
396    if (findExportAnnotation() != nullptr) {
397        exportedTypes->push_back(this);
398    }
399}
400
401status_t EnumType::emitExportedHeader(Formatter &out, bool forJava) const {
402    const Annotation *annotation = findExportAnnotation();
403    CHECK(annotation != nullptr);
404
405    std::string name = localName();
406
407    const AnnotationParam *nameParam = annotation->getParam("name");
408    if (nameParam != nullptr) {
409        name = nameParam->getSingleString();
410    }
411
412    bool exportParent = true;
413    const AnnotationParam *exportParentParam = annotation->getParam("export_parent");
414    if (exportParentParam != nullptr) {
415        exportParent = exportParentParam->getSingleBool();
416    }
417
418    std::string valuePrefix;
419    const AnnotationParam *prefixParam = annotation->getParam("value_prefix");
420    if (prefixParam != nullptr) {
421        valuePrefix = prefixParam->getSingleString();
422    }
423
424    std::string valueSuffix;
425    const AnnotationParam *suffixParam = annotation->getParam("value_suffix");
426    if (suffixParam != nullptr) {
427        valueSuffix = suffixParam->getSingleString();
428    }
429
430    const ScalarType *scalarType = mStorageType->resolveToScalarType();
431    CHECK(scalarType != nullptr);
432
433    std::vector<const EnumType *> chain;
434    if (exportParent) {
435        getTypeChain(&chain);
436    } else {
437        chain = { this };
438    }
439
440    if (forJava) {
441        if (!name.empty()) {
442            out << "public final class "
443                << name
444                << " {\n";
445
446            out.indent();
447        } else {
448            out << "// Values declared in " << localName() << " follow.\n";
449        }
450
451        const std::string typeName =
452            scalarType->getJavaType(false /* forInitializer */);
453
454        for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
455            const auto &type = *it;
456
457            for (const auto &entry : type->values()) {
458                out << "public static final "
459                    << typeName
460                    << " "
461                    << valuePrefix
462                    << entry->name()
463                    << valueSuffix
464                    << " = ";
465
466                // javaValue will make the number signed.
467                std::string value = entry->javaValue(scalarType->getKind());
468                CHECK(!value.empty()); // use autofilled values for java.
469                out << value;
470
471                out << ";";
472
473                std::string comment = entry->comment();
474                if (!comment.empty() && comment != value) {
475                    out << " // " << comment;
476                }
477
478                out << "\n";
479            }
480        }
481
482        if (!name.empty()) {
483            out.unindent();
484            out << "};\n";
485        }
486        out << "\n";
487
488        return OK;
489    }
490
491    if (!name.empty()) {
492        out << "typedef ";
493    }
494
495    out << "enum {\n";
496
497    out.indent();
498
499    for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
500        const auto &type = *it;
501
502        for (const auto &entry : type->values()) {
503            out << valuePrefix << entry->name() << valueSuffix;
504
505            std::string value = entry->cppValue(scalarType->getKind());
506            CHECK(!value.empty()); // use autofilled values for c++.
507            out << " = " << value;
508
509            out << ",";
510
511            std::string comment = entry->comment();
512            if (!comment.empty() && comment != value) {
513                out << " // " << comment;
514            }
515
516            out << "\n";
517        }
518    }
519
520    out.unindent();
521    out << "}";
522
523    if (!name.empty()) {
524        out << " " << name;
525    }
526
527    out << ";\n\n";
528
529    return OK;
530}
531
532////////////////////////////////////////////////////////////////////////////////
533
534EnumValue::EnumValue(const char *name, ConstantExpression *value)
535    : mName(name),
536      mValue(value),
537      mIsAutoFill(false) {
538}
539
540std::string EnumValue::name() const {
541    return mName;
542}
543
544std::string EnumValue::value(ScalarType::Kind castKind) const {
545    CHECK(mValue != nullptr);
546    return mValue->value(castKind);
547}
548
549std::string EnumValue::cppValue(ScalarType::Kind castKind) const {
550    CHECK(mValue != nullptr);
551    return mValue->cppValue(castKind);
552}
553std::string EnumValue::javaValue(ScalarType::Kind castKind) const {
554    CHECK(mValue != nullptr);
555    return mValue->javaValue(castKind);
556}
557
558std::string EnumValue::comment() const {
559    CHECK(mValue != nullptr);
560    return mValue->description();
561}
562
563ConstantExpression *EnumValue::constExpr() const {
564    CHECK(mValue != nullptr);
565    return mValue;
566}
567
568void EnumValue::autofill(const EnumValue *prev, const ScalarType *type) {
569    if(mValue != nullptr)
570        return;
571    mIsAutoFill = true;
572    ConstantExpression *value = new ConstantExpression();
573    if(prev == nullptr) {
574        *value = ConstantExpression::Zero(type->getKind());
575    } else {
576        CHECK(prev->mValue != nullptr);
577        *value = prev->mValue->addOne();
578    }
579    mValue = value;
580}
581
582bool EnumValue::isAutoFill() const {
583    return mIsAutoFill;
584}
585
586bool EnumValue::isEnumValue() const {
587    return true;
588}
589
590////////////////////////////////////////////////////////////////////////////////
591
592bool BitFieldType::isBitField() const {
593    return true;
594}
595
596std::string BitFieldType::typeName() const {
597    return "mask" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName()));
598}
599
600void BitFieldType::addNamedTypesToSet(std::set<const FQName> &) const {
601}
602
603bool BitFieldType::isCompatibleElementType(Type *elementType) const {
604    return elementType->isEnum();
605}
606
607const ScalarType *BitFieldType::resolveToScalarType() const {
608    return mElementType->resolveToScalarType();
609}
610
611std::string BitFieldType::getCppType(StorageMode mode,
612                                 bool specifyNamespaces) const {
613    return resolveToScalarType()->getCppType(mode, specifyNamespaces);
614}
615
616std::string BitFieldType::getJavaType(bool forInitializer) const {
617    return resolveToScalarType()->getJavaType(forInitializer);
618}
619
620std::string BitFieldType::getJavaSuffix() const {
621    return resolveToScalarType()->getJavaSuffix();
622}
623
624std::string BitFieldType::getJavaWrapperType() const {
625    return resolveToScalarType()->getJavaWrapperType();
626}
627
628std::string BitFieldType::getVtsType() const {
629    return "TYPE_MASK";
630}
631
632bool BitFieldType::isElidableType() const {
633    return resolveToScalarType()->isElidableType();
634}
635
636status_t BitFieldType::emitVtsTypeDeclarations(Formatter &out) const {
637    out << "type: " << getVtsType() << "\n";
638    out << "enum_value: {\n";
639    out.indent();
640    status_t err = mElementType->emitVtsTypeDeclarations(out);
641    if (err != OK) {
642        return err;
643    }
644    out.unindent();
645    out << "}\n";
646    return OK;
647}
648
649status_t BitFieldType::emitVtsAttributeType(Formatter &out) const {
650    out << "type: " << getVtsType() << "\n";
651    out << "enum_value: {\n";
652    out.indent();
653    status_t err = mElementType->emitVtsAttributeType(out);
654    if (err != OK) {
655        return err;
656    }
657    out.unindent();
658    out << "}\n";
659    return OK;
660}
661
662void BitFieldType::getAlignmentAndSize(size_t *align, size_t *size) const {
663    resolveToScalarType()->getAlignmentAndSize(align, size);
664}
665
666void BitFieldType::emitReaderWriter(
667        Formatter &out,
668        const std::string &name,
669        const std::string &parcelObj,
670        bool parcelObjIsPointer,
671        bool isReader,
672        ErrorMode mode) const {
673    resolveToScalarType()->emitReaderWriterWithCast(
674            out,
675            name,
676            parcelObj,
677            parcelObjIsPointer,
678            isReader,
679            mode,
680            true /* needsCast */);
681}
682
683void BitFieldType::emitJavaFieldReaderWriter(
684        Formatter &out,
685        size_t depth,
686        const std::string &parcelName,
687        const std::string &blobName,
688        const std::string &fieldName,
689        const std::string &offset,
690        bool isReader) const {
691    return resolveToScalarType()->emitJavaFieldReaderWriter(
692            out, depth, parcelName, blobName, fieldName, offset, isReader);
693}
694
695}  // namespace android
696
697