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