diff options
author | Neel Mehta <mneel@google.com> | 2019-07-02 15:47:48 -0700 |
---|---|---|
committer | Neel Mehta <mneel@google.com> | 2019-07-19 10:59:40 -0700 |
commit | 3b414a8de5643fdf7ff0e1aa6d162830f081c4e4 (patch) | |
tree | 0df703db3d8845e6b76d13ebabd271e4be953c37 | |
parent | 8d5421845fe329fe38fca17f7d1eee736a6e600b (diff) | |
download | hidl-3b414a8de5643fdf7ff0e1aa6d162830f081c4e4.tar.gz |
Add -Lformat option to format .hal files
Formats .hal files.
Bug: 137553653
Test: hidl-gen -Lformat <IFACE>
Test: aosp/1051701
Test: hidl-gen -Lformat (google-interfaces) & hidl-gen -Lcheck
(google-interfaces)
Change-Id: I5aa554d99fd4977acb7939d8c793081680a3f598
42 files changed, 577 insertions, 70 deletions
@@ -161,6 +161,8 @@ struct AST { void generateDependencies(Formatter& out) const; void generateInheritanceHierarchy(Formatter& out) const; + void generateFormattedHidl(Formatter& out) const; + const std::vector<ImportStatement>& getImportStatements() const; void getImportedPackages(std::set<FQName> *importSet) const; @@ -110,6 +110,7 @@ cc_library_host_shared { "generateCppAdapter.cpp", "generateCppImpl.cpp", "generateDependencies.cpp", + "generateFormattedHidl.cpp", "generateInheritanceHierarchy.cpp", "generateJava.cpp", "generateJavaImpl.cpp", diff --git a/Annotation.cpp b/Annotation.cpp index 438cff65..4c9637fd 100644 --- a/Annotation.cpp +++ b/Annotation.cpp @@ -158,7 +158,7 @@ void Annotation::dump(Formatter &out) const { const AnnotationParam* param = mParams->at(i); - out << param->getName() << "="; + out << param->getName() << " = "; const std::vector<std::string>& values = param->getValues(); if (values.size() > 1) { diff --git a/ArrayType.cpp b/ArrayType.cpp index 33424d84..5e491cf0 100644 --- a/ArrayType.cpp +++ b/ArrayType.cpp @@ -25,12 +25,15 @@ namespace android { ArrayType::ArrayType(const Reference<Type>& elementType, ConstantExpression* size, Scope* parent) - : Type(parent), mElementType(elementType), mSizes{size} { + : Type(parent, elementType.localName()), mElementType(elementType) { CHECK(!elementType.isEmptyReference()); + + appendDimension(size); } void ArrayType::appendDimension(ConstantExpression *size) { mSizes.push_back(size); + mDefinedName = mDefinedName + "[" + size->expression() + "]"; } size_t ArrayType::countDimensions() const { diff --git a/CompoundType.cpp b/CompoundType.cpp index 68bcedf0..a431912b 100644 --- a/CompoundType.cpp +++ b/CompoundType.cpp @@ -632,6 +632,24 @@ void CompoundType::emitSafeUnionTypeDeclarations(Formatter& out) const { } } +void CompoundType::emitHidlDefinition(Formatter& out) const { + if (getDocComment() != nullptr) getDocComment()->emit(out); + out << typeName() << " "; + + out.block([&] { + for (const Type* t : getSortedDefinedTypes()) { + t->emitHidlDefinition(out); + } + + for (const NamedReference<Type>* ref : *mFields) { + if (ref->getDocComment() != nullptr) ref->getDocComment()->emit(out); + out << ref->localName() << " " << ref->name() << ";\n"; + } + }); + + out << ";\n"; +} + void CompoundType::emitTypeDeclarations(Formatter& out) const { if (mStyle == STYLE_SAFE_UNION) { emitSafeUnionTypeDeclarations(out); diff --git a/CompoundType.h b/CompoundType.h index 3dec6afd..2c5a055c 100644 --- a/CompoundType.h +++ b/CompoundType.h @@ -100,6 +100,7 @@ struct CompoundType : public Scope { const std::string &offset, bool isReader) const override; + void emitHidlDefinition(Formatter& out) const override; void emitTypeDeclarations(Formatter& out) const override; void emitTypeForwardDeclaration(Formatter& out) const override; void emitPackageTypeDeclarations(Formatter& out) const override; diff --git a/ConstantExpression.cpp b/ConstantExpression.cpp index 002bf566..6badf579 100644 --- a/ConstantExpression.cpp +++ b/ConstantExpression.cpp @@ -164,17 +164,19 @@ std::unique_ptr<ConstantExpression> ConstantExpression::ValueOf(ScalarType::Kind return std::make_unique<LiteralConstantExpression>(kind, value); } +ConstantExpression::ConstantExpression(const std::string& expr) : mExpr(expr) {} + bool ConstantExpression::isEvaluated() const { return mIsEvaluated; } -LiteralConstantExpression::LiteralConstantExpression( - ScalarType::Kind kind, uint64_t value, const std::string& expr) { - +LiteralConstantExpression::LiteralConstantExpression(ScalarType::Kind kind, uint64_t value, + const std::string& expr) + : ConstantExpression(expr) { CHECK(!expr.empty()); CHECK(isSupported(kind)); + mTrivialDescription = std::to_string(value) == expr; - mExpr = expr; mValueKind = kind; mValue = value; mIsEvaluated = true; @@ -254,7 +256,6 @@ void UnaryConstantExpression::evaluate() { CHECK(mUnary->isEvaluated()); mIsEvaluated = true; - mExpr = std::string("(") + mOp + mUnary->mExpr + ")"; mValueKind = mUnary->mValueKind; #define CASE_UNARY(__type__) \ @@ -270,8 +271,6 @@ void BinaryConstantExpression::evaluate() { CHECK(mRval->isEvaluated()); mIsEvaluated = true; - mExpr = std::string("(") + mLval->mExpr + " " + mOp + " " + mRval->mExpr + ")"; - bool isArithmeticOrBitflip = OP_IS_BIN_ARITHMETIC || OP_IS_BIN_BITFLIP; // CASE 1: + - * / % | ^ & < > <= >= == != @@ -330,8 +329,6 @@ void TernaryConstantExpression::evaluate() { CHECK(mFalseVal->isEvaluated()); mIsEvaluated = true; - mExpr = std::string("(") + mCond->mExpr + "?" + mTrueVal->mExpr + ":" + mFalseVal->mExpr + ")"; - // note: for ?:, unlike arithmetic ops, integral promotion is not processed. mValueKind = usualArithmeticConversion(mTrueVal->mValueKind, mFalseVal->mValueKind); @@ -466,7 +463,6 @@ std::string ConstantExpression::javaValue(ScalarType::Kind castKind) const { } const std::string& ConstantExpression::expression() const { - CHECK(isEvaluated()); return mExpr; } @@ -683,7 +679,7 @@ std::vector<const ConstantExpression*> LiteralConstantExpression::getConstantExp } UnaryConstantExpression::UnaryConstantExpression(const std::string& op, ConstantExpression* value) - : mUnary(value), mOp(op) {} + : ConstantExpression(std::string("(") + op + value->mExpr + ")"), mUnary(value), mOp(op) {} std::vector<const ConstantExpression*> UnaryConstantExpression::getConstantExpressions() const { return {mUnary}; @@ -691,7 +687,10 @@ std::vector<const ConstantExpression*> UnaryConstantExpression::getConstantExpre BinaryConstantExpression::BinaryConstantExpression(ConstantExpression* lval, const std::string& op, ConstantExpression* rval) - : mLval(lval), mRval(rval), mOp(op) {} + : ConstantExpression(std::string("(") + lval->mExpr + " " + op + " " + rval->mExpr + ")"), + mLval(lval), + mRval(rval), + mOp(op) {} std::vector<const ConstantExpression*> BinaryConstantExpression::getConstantExpressions() const { return {mLval, mRval}; @@ -700,7 +699,11 @@ std::vector<const ConstantExpression*> BinaryConstantExpression::getConstantExpr TernaryConstantExpression::TernaryConstantExpression(ConstantExpression* cond, ConstantExpression* trueVal, ConstantExpression* falseVal) - : mCond(cond), mTrueVal(trueVal), mFalseVal(falseVal) {} + : ConstantExpression(std::string("(") + cond->mExpr + "?" + trueVal->mExpr + ":" + + falseVal->mExpr + ")"), + mCond(cond), + mTrueVal(trueVal), + mFalseVal(falseVal) {} std::vector<const ConstantExpression*> TernaryConstantExpression::getConstantExpressions() const { return {mCond, mTrueVal, mFalseVal}; @@ -708,8 +711,7 @@ std::vector<const ConstantExpression*> TernaryConstantExpression::getConstantExp ReferenceConstantExpression::ReferenceConstantExpression(const Reference<LocalIdentifier>& value, const std::string& expr) - : mReference(value) { - mExpr = expr; + : ConstantExpression(expr), mReference(value) { mTrivialDescription = mExpr.empty(); } @@ -729,9 +731,7 @@ std::vector<const Reference<LocalIdentifier>*> ReferenceConstantExpression::getR AttributeConstantExpression::AttributeConstantExpression(const Reference<Type>& value, const std::string& fqname, const std::string& tag) - : mReference(value), mTag(tag) { - mExpr = fqname + "#" + tag; -} + : ConstantExpression(fqname + "#" + tag), mReference(value), mTag(tag) {} std::vector<const ConstantExpression*> AttributeConstantExpression::getConstantExpressions() const { // Returns reference instead diff --git a/ConstantExpression.h b/ConstantExpression.h index b7707166..9f20fd5d 100644 --- a/ConstantExpression.h +++ b/ConstantExpression.h @@ -46,6 +46,7 @@ struct ConstantExpression { static std::unique_ptr<ConstantExpression> One(ScalarType::Kind kind); static std::unique_ptr<ConstantExpression> ValueOf(ScalarType::Kind kind, uint64_t value); + ConstantExpression(const std::string& expr); virtual ~ConstantExpression() {} virtual bool isReferenceConstantExpression() const; @@ -136,7 +137,7 @@ struct ConstantExpression { /* If the result value has been evaluated. */ bool mIsEvaluated = false; /* The formatted expression. */ - std::string mExpr; + const std::string mExpr; /* The kind of the result value. */ ScalarType::Kind mValueKind; /* The stored result value. */ diff --git a/DeathRecipientType.cpp b/DeathRecipientType.cpp index abc69fcc..1aa22ed0 100644 --- a/DeathRecipientType.cpp +++ b/DeathRecipientType.cpp @@ -21,7 +21,7 @@ namespace android { -DeathRecipientType::DeathRecipientType(Scope* parent) : Type(parent) {} +DeathRecipientType::DeathRecipientType(Scope* parent) : Type(parent, "death_recipient") {} std::string DeathRecipientType::typeName() const { return "death recipient"; diff --git a/DocComment.cpp b/DocComment.cpp index 707679a5..2a1c9816 100644 --- a/DocComment.cpp +++ b/DocComment.cpp @@ -63,8 +63,16 @@ void DocComment::merge(const DocComment* comment) { mLocation.setLocation(mLocation.begin(), comment->mLocation.end()); } -void DocComment::emit(Formatter& out) const { - out << "/**\n"; +void DocComment::emit(Formatter& out, CommentType type) const { + switch (type) { + case CommentType::DOC_MULTILINE: + out << "/**\n"; + break; + case CommentType::MULTILINE: + out << "/*\n"; + break; + } + out.setLinePrefix(" *"); for (const std::string& line : mLines) { diff --git a/DocComment.h b/DocComment.h index 58c8e17a..315ef607 100644 --- a/DocComment.h +++ b/DocComment.h @@ -27,12 +27,19 @@ namespace android { +enum class CommentType { + // multiline comment that begins with /** + DOC_MULTILINE, + // begins with /* (used for headers) + MULTILINE +}; + struct DocComment { DocComment(const std::string& comment, const Location& location); void merge(const DocComment* comment); - void emit(Formatter& out) const; + void emit(Formatter& out, CommentType type = CommentType::DOC_MULTILINE) const; const std::vector<std::string>& lines() const { return mLines; } diff --git a/EnumType.cpp b/EnumType.cpp index 6a3a002c..d0e88a35 100644 --- a/EnumType.cpp +++ b/EnumType.cpp @@ -251,6 +251,31 @@ void EnumType::emitJavaFieldReaderWriter( out, depth, parcelName, blobName, fieldName, offset, isReader); } +void EnumType::emitHidlDefinition(Formatter& out) const { + if (getDocComment() != nullptr) getDocComment()->emit(out); + + if (annotations().size() != 0) { + out.join(annotations().begin(), annotations().end(), " ", + [&](auto annotation) { annotation->dump(out); }); + out << "\n"; + } + + out << typeName() << " : " << mStorageType.localName() << " {\n"; + + out.indent([&] { + for (const EnumValue* val : mValues) { + if (val->getDocComment() != nullptr) val->getDocComment()->emit(out); + out << val->name(); + if (!val->isAutoFill()) { + out << " = " << val->constExpr()->expression(); + } + out << ",\n"; + } + }); + + out << "};\n"; +} + void EnumType::emitTypeDeclarations(Formatter& out) const { const ScalarType *scalarType = mStorageType->resolveToScalarType(); CHECK(scalarType != nullptr); @@ -783,7 +808,7 @@ void EnumValue::autofill(const EnumType* prevType, EnumValue* prevValue, const S } else { std::string description = prevType->fullName() + "." + prevValue->name() + " implicitly"; auto* prevReference = new ReferenceConstantExpression( - Reference<LocalIdentifier>(prevValue, mLocation), description); + Reference<LocalIdentifier>(prevValue->mName, prevValue, mLocation), description); mValue = prevReference->addOne(type->getKind()).release(); } } @@ -802,7 +827,7 @@ const Location& EnumValue::location() const { //////////////////////////////////////////////////////////////////////////////// -BitFieldType::BitFieldType(Scope* parent) : TemplatedType(parent) {} +BitFieldType::BitFieldType(Scope* parent) : TemplatedType(parent, "bitfield") {} bool BitFieldType::isBitField() const { return true; @@ -96,6 +96,7 @@ struct EnumType : public Scope { const std::string &offset, bool isReader) const override; + void emitHidlDefinition(Formatter& out) const override; void emitTypeDeclarations(Formatter& out) const override; void emitTypeForwardDeclaration(Formatter& out) const override; void emitGlobalTypeDeclarations(Formatter& out) const override; diff --git a/FmqType.cpp b/FmqType.cpp index f5eaaa68..ed323f2e 100644 --- a/FmqType.cpp +++ b/FmqType.cpp @@ -23,8 +23,8 @@ namespace android { -FmqType::FmqType(const char* nsp, const char* name, Scope* parent) - : TemplatedType(parent), mNamespace(nsp), mName(name) {} +FmqType::FmqType(const char* nsp, const char* name, Scope* parent, const char* definedName) + : TemplatedType(parent, definedName), mNamespace(nsp), mName(name) {} std::string FmqType::templatedTypeName() const { return mName; @@ -23,7 +23,7 @@ namespace android { struct FmqType : public TemplatedType { - FmqType(const char* nsp, const char* name, Scope* parent); + FmqType(const char* nsp, const char* name, Scope* parent, const char* definedName); std::string fullName() const; diff --git a/FormattingConstants.h b/FormattingConstants.h new file mode 100644 index 00000000..1ab5a179 --- /dev/null +++ b/FormattingConstants.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cstddef> + +namespace android { +constexpr size_t MAX_LINE_LENGTH = 100; +};
\ No newline at end of file diff --git a/HandleType.cpp b/HandleType.cpp index 56660a6e..1c612e59 100644 --- a/HandleType.cpp +++ b/HandleType.cpp @@ -23,7 +23,7 @@ namespace android { -HandleType::HandleType(Scope* parent) : Type(parent) {} +HandleType::HandleType(Scope* parent) : Type(parent, "handle") {} bool HandleType::isHandle() const { return true; diff --git a/Interface.cpp b/Interface.cpp index b6d2f38d..ff33972d 100644 --- a/Interface.cpp +++ b/Interface.cpp @@ -822,6 +822,31 @@ void Interface::emitReaderWriter( } } +void Interface::emitHidlDefinition(Formatter& out) const { + if (getDocComment() != nullptr) getDocComment()->emit(out); + out << typeName() << " "; + + const Interface* super = superType(); + if (super != nullptr && !super->isIBase()) { + out << "extends " << super->fqName().getRelativeFQName(fqName()) << " "; + } + + out << "{\n"; + + out.indent([&] { + const std::vector<const NamedType*>& definedTypes = getSortedDefinedTypes(); + out.join(definedTypes.begin(), definedTypes.end(), "\n", + [&](auto t) { t->emitHidlDefinition(out); }); + + if (definedTypes.size() > 0 && userDefinedMethods().size() > 0) out << "\n"; + + out.join(userDefinedMethods().begin(), userDefinedMethods().end(), "\n", + [&](auto method) { method->emitHidlDefinition(out); }); + }); + + out << "};\n"; +} + void Interface::emitPackageTypeDeclarations(Formatter& out) const { Scope::emitPackageTypeDeclarations(out); diff --git a/Interface.h b/Interface.h index 56570f5c..e0fcb8b2 100644 --- a/Interface.h +++ b/Interface.h @@ -111,6 +111,8 @@ struct Interface : public Scope { bool isReader, ErrorMode mode) const override; + void emitHidlDefinition(Formatter& out) const override; + void emitPackageTypeDeclarations(Formatter& out) const override; void emitPackageTypeHeaderDefinitions(Formatter& out) const override; void emitTypeDefinitions(Formatter& out, const std::string& prefix) const override; diff --git a/MemoryType.cpp b/MemoryType.cpp index 444ba92c..380214fa 100644 --- a/MemoryType.cpp +++ b/MemoryType.cpp @@ -23,7 +23,7 @@ namespace android { -MemoryType::MemoryType(Scope* parent) : Type(parent) {} +MemoryType::MemoryType(Scope* parent) : Type(parent, "memory") {} std::string MemoryType::getCppType(StorageMode mode, bool specifyNamespaces) const { @@ -18,12 +18,15 @@ #include "Annotation.h" #include "ConstantExpression.h" +#include "FormattingConstants.h" #include "ScalarType.h" #include "Type.h" #include <android-base/logging.h> +#include <hidl-util/FQName.h> #include <hidl-util/Formatter.h> #include <algorithm> +#include <vector> namespace android { @@ -263,6 +266,53 @@ void Method::emitJavaSignature(Formatter& out) const { out << ")"; } +static void fillHidlArgResultTokens(const std::vector<NamedReference<Type>*>& args, + WrappedOutput* wrappedOutput) { + for (auto iter = args.begin(); iter != args.end(); ++iter) { + auto arg = *iter; + std::string out = arg->localName() + " " + arg->name(); + if (iter != args.begin()) { + *wrappedOutput << ","; + wrappedOutput->group([&] { + wrappedOutput->printUnlessWrapped(" "); + *wrappedOutput << out; + }); + } else { + wrappedOutput->group([&] { *wrappedOutput << out; }); + } + } +} + +void Method::emitHidlDefinition(Formatter& out) const { + if (getDocComment() != nullptr) getDocComment()->emit(out); + + out.join(mAnnotations->begin(), mAnnotations->end(), "\n", + [&](auto annotation) { annotation->dump(out); }); + if (!mAnnotations->empty()) out << "\n"; + + WrappedOutput wrappedOutput(MAX_LINE_LENGTH); + + if (isOneway()) wrappedOutput << "oneway "; + wrappedOutput << name() << "("; + + wrappedOutput.group([&] { fillHidlArgResultTokens(args(), &wrappedOutput); }); + + wrappedOutput << ")"; + + if (!results().empty()) { + wrappedOutput.group([&] { + wrappedOutput.printUnlessWrapped(" "); + wrappedOutput << "generates ("; + fillHidlArgResultTokens(results(), &wrappedOutput); + wrappedOutput << ")"; + }); + } + + wrappedOutput << ";\n"; + + out << wrappedOutput; +} + bool Method::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const { if (!std::all_of(mArgs->begin(), mArgs->end(), [&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) { @@ -103,6 +103,8 @@ struct Method : DocCommentable { void emitJavaResultSignature(Formatter &out) const; void emitJavaSignature(Formatter& out) const; + void emitHidlDefinition(Formatter& out) const; + const NamedReference<Type>* canElideCallback() const; bool deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const; diff --git a/NamedType.cpp b/NamedType.cpp index 645c63d8..dba92487 100644 --- a/NamedType.cpp +++ b/NamedType.cpp @@ -20,7 +20,7 @@ namespace android { NamedType::NamedType(const char* localName, const FQName& fullName, const Location& loc, Scope* parent) - : Type(parent), mLocalName(localName), mFullName(fullName), mLocation(loc) {} + : Type(parent, localName), mLocalName(localName), mFullName(fullName), mLocation(loc) {} bool NamedType::isNamedType() const { return true; @@ -54,4 +54,3 @@ void NamedType::emitDump( } } // namespace android - diff --git a/PointerType.cpp b/PointerType.cpp index 2b8e5a48..f6eaf541 100644 --- a/PointerType.cpp +++ b/PointerType.cpp @@ -21,7 +21,7 @@ namespace android { -PointerType::PointerType(Scope* parent) : Type(parent) {} +PointerType::PointerType(Scope* parent) : Type(parent, "pointer") {} bool PointerType::isPointer() const { return true; diff --git a/Reference.h b/Reference.h index ba39ac42..b8175148 100644 --- a/Reference.h +++ b/Reference.h @@ -21,6 +21,8 @@ #include <android-base/logging.h> #include <hidl-util/FQName.h> +#include <string> + #include "DocComment.h" #include "Location.h" @@ -34,20 +36,27 @@ struct Reference { Reference() = default; virtual ~Reference() {} - Reference(const FQName& fqName, const Location& location) - : mResolved(nullptr), mFqName(fqName), mLocation(location) {} + Reference(const std::string& localName, const FQName& fqName, const Location& location) + : mResolved(nullptr), mFqName(fqName), mLocation(location), mLocalName(localName) {} - Reference(T* type, const Location& location) : mResolved(type), mLocation(location) { + Reference(const std::string& localName, T* type, const Location& location) + : mResolved(type), mLocation(location), mLocalName(localName) { CHECK(type != nullptr); } template <class OtherT> Reference(const Reference<OtherT>& ref) - : mResolved(ref.mResolved), mFqName(ref.mFqName), mLocation(ref.mLocation) {} + : mResolved(ref.mResolved), + mFqName(ref.mFqName), + mLocation(ref.mLocation), + mLocalName(ref.mLocalName) {} template <class OtherT> Reference(const Reference<OtherT>& ref, const Location& location) - : mResolved(ref.mResolved), mFqName(ref.mFqName), mLocation(location) {} + : mResolved(ref.mResolved), + mFqName(ref.mFqName), + mLocation(location), + mLocalName(ref.mLocalName) {} /* Returns true iff referred type is resolved Referred type's field might be not resolved */ @@ -100,7 +109,9 @@ struct Reference { return mLocation; } - private: + const std::string& localName() const { return mLocalName; } + + private: /* Referred type */ T* mResolved = nullptr; /* Reference name for lookup */ @@ -109,6 +120,9 @@ struct Reference { and handling forward reference restrictions */ Location mLocation; + /* Name used in the .hal file */ + std::string mLocalName; + bool hasLookupFqName() const { // Valid only while not resolved to prevent confusion when // ref.hasLookupFqName() is false while ref,get()->fqName is valid. diff --git a/ScalarType.cpp b/ScalarType.cpp index e6f3fe49..142aac27 100644 --- a/ScalarType.cpp +++ b/ScalarType.cpp @@ -20,7 +20,12 @@ namespace android { -ScalarType::ScalarType(Kind kind, Scope* parent) : Type(parent), mKind(kind) {} +static const char* const hidlIdentifiers[] = {"bool", "int8_t", "uint8_t", "int16_t", + "uint16_t", "int32_t", "uint32_t", "int64_t", + "uint64_t", "float", "double"}; + +ScalarType::ScalarType(Kind kind, Scope* parent) + : Type(parent, hidlIdentifiers[kind]), mKind(kind) {} const ScalarType *ScalarType::resolveToScalarType() const { return this; @@ -122,6 +122,16 @@ std::vector<const Type*> Scope::getDefinedTypes() const { return ret; } +std::vector<const NamedType*> Scope::getSortedDefinedTypes() const { + std::vector<const NamedType*> ret; + ret.insert(ret.end(), mTypes.begin(), mTypes.end()); + + std::sort(ret.begin(), ret.end(), [](const NamedType* lhs, const NamedType* rhs) -> bool { + return lhs->location() < rhs->location(); + }); + return ret; +} + std::vector<const ConstantExpression*> Scope::getConstantExpressions() const { std::vector<const ConstantExpression*> ret; for (const auto* annotation : mAnnotations) { @@ -146,6 +156,12 @@ void Scope::topologicalReorder(const std::unordered_map<const Type*, size_t>& re } } +void Scope::emitHidlDefinition(Formatter& out) const { + const std::vector<const NamedType*>& definedTypes = getSortedDefinedTypes(); + out.join(definedTypes.begin(), definedTypes.end(), "\n", + [&](auto t) { t->emitHidlDefinition(out); }); +} + void Scope::emitTypeDeclarations(Formatter& out) const { if (mTypes.empty()) return; @@ -69,6 +69,8 @@ struct Scope : public NamedType { void emitPackageTypeHeaderDefinitions(Formatter& out) const override; void emitPackageHwDeclarations(Formatter& out) const override; + void emitHidlDefinition(Formatter& out) const override; + void emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const override; void emitTypeDefinitions(Formatter& out, const std::string& prefix) const override; @@ -82,7 +84,10 @@ struct Scope : public NamedType { void appendToExportedTypesVector( std::vector<const Type *> *exportedTypes) const override; - private: + protected: + std::vector<const NamedType*> getSortedDefinedTypes() const; + + private: std::vector<NamedType *> mTypes; std::map<std::string, size_t> mTypeIndexByName; std::vector<Annotation*> mAnnotations; diff --git a/StringType.cpp b/StringType.cpp index b4f72bee..edb183f7 100644 --- a/StringType.cpp +++ b/StringType.cpp @@ -22,7 +22,7 @@ namespace android { -StringType::StringType(Scope* parent) : Type(parent) {} +StringType::StringType(Scope* parent) : Type(parent, "string") {} bool StringType::isString() const { return true; @@ -25,10 +25,12 @@ #include <hidl-util/Formatter.h> #include <algorithm> #include <iostream> +#include <string> namespace android { -Type::Type(Scope* parent) : mParent(parent) {} +Type::Type(Scope* parent, const std::string& definedName) + : mDefinedName(definedName), mParent(parent) {} Type::~Type() {} @@ -369,6 +371,10 @@ const Scope* Type::parent() const { return mParent; } +const std::string& Type::definedName() const { + return mDefinedName; +} + std::string Type::getCppType(StorageMode, bool) const { CHECK(!"Should not be here") << typeName(); return std::string(); @@ -597,6 +603,10 @@ void Type::emitReaderWriterEmbeddedForTypeName( handleError(out, mode); } +void Type::emitHidlDefinition(Formatter&) const { + CHECK(!"Should not be here.") << typeName(); +} + void Type::emitTypeDeclarations(Formatter&) const {} void Type::emitTypeForwardDeclaration(Formatter&) const {} @@ -725,7 +735,8 @@ bool Type::isNeverStrongReference() const { //////////////////////////////////////// -TemplatedType::TemplatedType(Scope* parent) : Type(parent) {} +TemplatedType::TemplatedType(Scope* parent, const std::string& definedName) + : Type(parent, definedName) {} std::string TemplatedType::typeName() const { return templatedTypeName() + " of " + mElementType->typeName(); @@ -737,6 +748,7 @@ void TemplatedType::setElementType(const Reference<Type>& elementType) { CHECK(!elementType.isEmptyReference()); mElementType = elementType; + mDefinedName = mDefinedName + "<" + mElementType.localName() + ">"; } const Type* TemplatedType::getElementType() const { @@ -38,7 +38,7 @@ struct ScalarType; struct Scope; struct Type : DocCommentable { - Type(Scope* parent); + Type(Scope* parent, const std::string& definedName); virtual ~Type(); virtual bool isArray() const; @@ -147,6 +147,8 @@ struct Type : DocCommentable { Scope* parent(); const Scope* parent() const; + const std::string& definedName() const; + enum StorageMode { StorageMode_Stack, StorageMode_Argument, @@ -251,6 +253,8 @@ struct Type : DocCommentable { const std::string &offset, bool isReader) const; + virtual void emitHidlDefinition(Formatter& out) const; + virtual void emitTypeDeclarations(Formatter& out) const; virtual void emitGlobalTypeDeclarations(Formatter& out) const; @@ -344,7 +348,10 @@ struct Type : DocCommentable { const std::string &methodName, const std::string &name) const; - private: + // This is the name given to the type in the hidl file + std::string mDefinedName; + + private: ParseStage mParseStage = ParseStage::PARSE; Scope* const mParent; @@ -370,8 +377,8 @@ struct TemplatedType : public Type { void emitVtsAttributeType(Formatter& out) const override; protected: - TemplatedType(Scope* parent); - Reference<Type> mElementType; + TemplatedType(Scope* parent, const std::string& definedName); + Reference<Type> mElementType; private: DISALLOW_COPY_AND_ASSIGN(TemplatedType); diff --git a/TypeDef.cpp b/TypeDef.cpp index 80522a28..2e36c285 100644 --- a/TypeDef.cpp +++ b/TypeDef.cpp @@ -80,5 +80,9 @@ void TypeDef::emitTypeDeclarations(Formatter& out) const { << ";\n\n"; } +void TypeDef::emitHidlDefinition(Formatter& out) const { + out << "typedef " << mReferencedType.localName() << " " << localName() << ";\n"; +} + } // namespace android @@ -44,8 +44,9 @@ struct TypeDef : public NamedType { std::vector<const Reference<Type>*> getReferences() const override; void emitTypeDeclarations(Formatter& out) const override; + void emitHidlDefinition(Formatter& out) const override; - private: + private: Reference<Type> mReferencedType; DISALLOW_COPY_AND_ASSIGN(TypeDef); diff --git a/VectorType.cpp b/VectorType.cpp index b5e8e225..3bd2d383 100644 --- a/VectorType.cpp +++ b/VectorType.cpp @@ -25,7 +25,7 @@ namespace android { -VectorType::VectorType(Scope* parent) : TemplatedType(parent) {} +VectorType::VectorType(Scope* parent) : TemplatedType(parent, "vec") {} std::string VectorType::templatedTypeName() const { return "vector"; diff --git a/generateFormattedHidl.cpp b/generateFormattedHidl.cpp new file mode 100644 index 00000000..742652e2 --- /dev/null +++ b/generateFormattedHidl.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <hidl-util/FQName.h> +#include <hidl-util/Formatter.h> + +#include "AST.h" + +namespace android { + +void AST::generateFormattedHidl(Formatter& out) const { + if (mHeader != nullptr) { + mHeader->emit(out, CommentType::MULTILINE); + out << "\n"; + } + + out << "package " << mPackage.string() << ";\n\n"; + + out.join(mImportStatements.begin(), mImportStatements.end(), "\n", [&](const auto& import) { + if (import.fqName.name().empty()) { + out << "import " << import.fqName.string() << ";"; + } else { + out << "import " << import.fqName.getRelativeFQName(mPackage) << ";"; + } + }); + if (!mImportStatements.empty()) out << "\n\n"; + + mRootScope.emitHidlDefinition(out); +} + +} // namespace android diff --git a/hidl-gen_l.ll b/hidl-gen_l.ll index 81fe1511..7d768329 100644 --- a/hidl-gen_l.ll +++ b/hidl-gen_l.ll @@ -129,8 +129,8 @@ using token = yy::parser::token; "pointer" { yylval->type = new PointerType(*scope); return token::TYPE; } "string" { yylval->type = new StringType(*scope); return token::TYPE; } -"fmq_sync" { yylval->type = new FmqType("::android::hardware", "MQDescriptorSync", *scope); return token::TEMPLATED; } -"fmq_unsync" { yylval->type = new FmqType("::android::hardware", "MQDescriptorUnsync", *scope); return token::TEMPLATED; } +"fmq_sync" { yylval->type = new FmqType("::android::hardware", "MQDescriptorSync", *scope, "fmq_sync"); return token::TEMPLATED; } +"fmq_unsync" { yylval->type = new FmqType("::android::hardware", "MQDescriptorUnsync", *scope, "fmq_unsync"); return token::TEMPLATED; } "(" { return('('); } ")" { return(')'); } diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy index 58f78d05..7d4650d3 100644 --- a/hidl-gen_y.yy +++ b/hidl-gen_y.yy @@ -529,11 +529,11 @@ fqname fqtype : fqname { - $$ = new Reference<Type>(*$1, convertYYLoc(@1, ast)); + $$ = new Reference<Type>($1->string(), *$1, convertYYLoc(@1, ast)); } | TYPE { - $$ = new Reference<Type>($1, convertYYLoc(@1, ast)); + $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast)); } ; @@ -713,7 +713,7 @@ interface_declaration } if (superType == nullptr) { - superType = new Reference<Type>(gIBaseFqName, convertYYLoc(@$, ast)); + superType = new Reference<Type>(gIBaseFqName.string(), gIBaseFqName, convertYYLoc(@$, ast)); } } @@ -788,12 +788,12 @@ const_expr } $$ = new ReferenceConstantExpression( - Reference<LocalIdentifier>(*$1, convertYYLoc(@1, ast)), $1->string()); + Reference<LocalIdentifier>($1->string(), *$1, convertYYLoc(@1, ast)), $1->string()); } | fqname '#' IDENTIFIER { $$ = new AttributeConstantExpression( - Reference<Type>(*$1, convertYYLoc(@1, ast)), $1->string(), $3); + Reference<Type>($1->string(), *$1, convertYYLoc(@1, ast)), $1->string(), $3); } | const_expr '?' const_expr ':' const_expr { @@ -1045,8 +1045,8 @@ named_enum_declaration std::cerr << "ERROR: Must explicitly specify enum storage type for " << $2 << " at " << @2 << "\n"; ast->addSyntaxError(); - storageType = new Reference<Type>( - new ScalarType(ScalarType::KIND_INT64, *scope), convertYYLoc(@2, ast)); + ScalarType* scalar = new ScalarType(ScalarType::KIND_INT64, *scope); + storageType = new Reference<Type>(scalar->definedName(), scalar, convertYYLoc(@2, ast)); } EnumType* enumType = new EnumType( @@ -1123,13 +1123,13 @@ array_type_base | TEMPLATED '<' type '>' { $1->setElementType(*$3); - $$ = new Reference<Type>($1, convertYYLoc(@1, ast)); + $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast)); } | TEMPLATED '<' TEMPLATED '<' type RSHIFT { $3->setElementType(*$5); - $1->setElementType(Reference<Type>($3, convertYYLoc(@3, ast))); - $$ = new Reference<Type>($1, convertYYLoc(@1, ast)); + $1->setElementType(Reference<Type>($3->definedName(), $3, convertYYLoc(@3, ast))); + $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast)); } ; @@ -1149,12 +1149,12 @@ type : array_type_base ignore_doc_comments { $$ = $1; } | array_type ignore_doc_comments { - $$ = new Reference<Type>($1, convertYYLoc(@1, ast)); + $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast)); } | INTERFACE ignore_doc_comments { // "interface" is a synonym of android.hidl.base@1.0::IBase - $$ = new Reference<Type>(gIBaseFqName, convertYYLoc(@1, ast)); + $$ = new Reference<Type>("interface", gIBaseFqName, convertYYLoc(@1, ast)); } ; @@ -1162,7 +1162,7 @@ type_or_inplace_compound_declaration : type { $$ = $1; } | annotated_compound_declaration ignore_doc_comments { - $$ = new Reference<Type>($1, convertYYLoc(@1, ast)); + $$ = new Reference<Type>($1->definedName(), $1, convertYYLoc(@1, ast)); } ; diff --git a/host_utils/Formatter.cpp b/host_utils/Formatter.cpp index 534e8cdc..2268e30c 100644 --- a/host_utils/Formatter.cpp +++ b/host_utils/Formatter.cpp @@ -19,6 +19,7 @@ #include <assert.h> #include <android-base/logging.h> +#include <vector> namespace android { @@ -123,7 +124,7 @@ Formatter &Formatter::operator<<(const std::string &out) { if (pos == std::string::npos) { if (mAtStartOfLine) { - fprintf(mFile, "%*s", (int)(mSpacesPerIndent * mIndentDepth), ""); + fprintf(mFile, "%*s", (int)(getIndentation()), ""); fprintf(mFile, "%s", mLinePrefix.c_str()); mAtStartOfLine = false; } @@ -133,7 +134,7 @@ Formatter &Formatter::operator<<(const std::string &out) { } if (mAtStartOfLine && (pos > start || !mLinePrefix.empty())) { - fprintf(mFile, "%*s", (int)(mSpacesPerIndent * mIndentDepth), ""); + fprintf(mFile, "%*s", (int)(getIndentation()), ""); fprintf(mFile, "%s", mLinePrefix.c_str()); } @@ -151,6 +152,56 @@ Formatter &Formatter::operator<<(const std::string &out) { return *this; } +Formatter& Formatter::operator<<(const WrappedOutput& wrappedOutput) { + CHECK(mAtStartOfLine) << "This function should only be called at the start of a new line"; + + size_t currentPosition = getIndentation(); + std::function<void(Formatter&, const WrappedOutput::Block&)> printBlock = + [&](Formatter& out, const WrappedOutput::Block& block) { + size_t blockSize = block.computeSize(false); + if (blockSize + currentPosition < wrappedOutput.mLineLength) { + block.print(out, false); + currentPosition += blockSize; + return; + } + + // Everything will not fit on this line. Try to fit it on the next line. + blockSize = block.computeSize(true); + if (blockSize + getIndentation() + mSpacesPerIndent < wrappedOutput.mLineLength) { + out << "\n"; + out.indent(); + + block.print(out, true); + currentPosition = getIndentation() + blockSize; + + out.unindent(); + return; + } + + if (!block.content.empty()) { + // Doesn't have subblocks. This means that the block itself is too big. + // Have to print it out. + out << "\n"; + out.indent(); + + block.print(out, true); + currentPosition = getIndentation() + blockSize; + + out.unindent(); + return; + } + + // Everything will not fit on this line. Go through all the children + for (const WrappedOutput::Block& subBlock : block.blocks) { + printBlock(out, subBlock); + } + }; + + printBlock(*this, wrappedOutput.mRootBlock); + + return *this; +} + // NOLINT to suppress missing parentheses warning about __type__. #define FORMATTER_INPUT_INTEGER(__type__) \ Formatter& Formatter::operator<<(__type__ n) { /* NOLINT */ \ @@ -187,10 +238,101 @@ bool Formatter::isValid() const { return mFile != nullptr; } +size_t Formatter::getIndentation() const { + return mSpacesPerIndent * mIndentDepth; +} + void Formatter::output(const std::string &text) const { CHECK(isValid()); fprintf(mFile, "%s", text.c_str()); } +WrappedOutput::Block::Block(const std::string& content, Block* const parent) + : content(content), parent(parent) {} + +size_t WrappedOutput::Block::computeSize(bool wrapped) const { + CHECK(content.empty() || blocks.empty()); + + // There is a wrap, so the block would not be printed + if (printUnlessWrapped && wrapped) return 0; + + size_t size = content.size(); + for (auto block = blocks.begin(); block != blocks.end(); ++block) { + if (block == blocks.begin()) { + // Only the first one can be wrapped (since content.empty()) + size += block->computeSize(wrapped); + } else { + size += block->computeSize(false); + } + } + + return size; +} + +void WrappedOutput::Block::print(Formatter& out, bool wrapped) const { + CHECK(content.empty() || blocks.empty()); + + // There is a wrap, so the block should not be printed + if (printUnlessWrapped && wrapped) return; + + out << content; + for (auto block = blocks.begin(); block != blocks.end(); ++block) { + if (block == blocks.begin()) { + // Only the first one can be wrapped (since content.empty()) + block->print(out, wrapped); + } else { + block->print(out, false); + } + } +} + +WrappedOutput::WrappedOutput(size_t lineLength) + : mLineLength(lineLength), mRootBlock(Block("", nullptr)) { + mCurrentBlock = &mRootBlock; +} + +WrappedOutput& WrappedOutput::operator<<(const std::string& str) { + std::vector<Block>& blockVec = mCurrentBlock->blocks; + if (!blockVec.empty()) { + Block& last = blockVec.back(); + if (!last.populated && last.blocks.empty()) { + last.content += str; + + return *this; + } + } + + blockVec.emplace_back(str, mCurrentBlock); + return *this; +} + +WrappedOutput& WrappedOutput::printUnlessWrapped(const std::string& str) { + std::vector<Block>& blockVec = mCurrentBlock->blocks; + if (!blockVec.empty()) { + blockVec.back().populated = true; + } + + blockVec.emplace_back(str, mCurrentBlock); + blockVec.back().populated = true; + blockVec.back().printUnlessWrapped = true; + + return *this; +} + +void WrappedOutput::group(const std::function<void(void)>& block) { + std::vector<Block>& blockVec = mCurrentBlock->blocks; + if (!blockVec.empty()) { + blockVec.back().populated = true; + } + + blockVec.emplace_back("", mCurrentBlock); + mCurrentBlock = &blockVec.back(); + + block(); + + mCurrentBlock->populated = true; + mCurrentBlock = mCurrentBlock->parent; +} + } // namespace android diff --git a/host_utils/include/hidl-util/Formatter.h b/host_utils/include/hidl-util/Formatter.h index bdb89be4..5ce23511 100644 --- a/host_utils/include/hidl-util/Formatter.h +++ b/host_utils/include/hidl-util/Formatter.h @@ -20,9 +20,47 @@ #include <functional> #include <string> +#include <vector> namespace android { +struct Formatter; + +struct WrappedOutput { + WrappedOutput(size_t lineLength); + + void group(const std::function<void(void)>& block); + WrappedOutput& operator<<(const std::string& str); + WrappedOutput& printUnlessWrapped(const std::string& str); + + private: + struct Block { + Block(const std::string& content, Block* const parent); + + // populated helps indicate if we are done filling up the Block. + // this allows WrappedOutput to keep adding content to this block + // till it is determined that it is full. + bool populated = false; + bool printUnlessWrapped = false; + + // Only one of content or blocks can have content. + std::string content; + std::vector<Block> blocks; + + Block* const parent; + + size_t computeSize(bool wrapped) const; + void print(Formatter& out, bool wrapped) const; + }; + + size_t mLineLength; + + Block mRootBlock; + Block* mCurrentBlock; + + friend struct Formatter; +}; + // Two styles to use a Formatter. // One is with .indent() calls and operator<<. // out << "if (good) {\n"; out.indent(); out << "blah\nblah\n"; out.unindent(); out << "}\n"; @@ -128,6 +166,9 @@ struct Formatter { Formatter &operator<<(double c); Formatter &operator<<(long double c); + // This assumes that the formatter is currently on a newline + Formatter& operator<<(const WrappedOutput& wrappedOutput); + // Puts a prefix before each line. This is useful if // you want to start a // comment block, for example. // The prefix will be put before the indentation. @@ -137,8 +178,9 @@ struct Formatter { void unsetLinePrefix(); bool isValid() const; + size_t getIndentation() const; - private: + private: // Creates an invalid formatter object. Formatter(); @@ -1283,6 +1283,21 @@ static const std::vector<OutputHandler> kFormats = { }, }, }, + { + "format", + "Reformats the .hal files", + OutputMode::NEEDS_SRC, + Coordinator::Location::PACKAGE_ROOT, + GenerationGranularity::PER_FILE, + validateForSource, + { + { + FileGenerator::alwaysGenerate, + [](const FQName& fqName) { return fqName.name() + ".hal"; }, + astGenerationFunction(&AST::generateFormattedHidl), + }, + } + }, }; // clang-format on diff --git a/utils/FQName.cpp b/utils/FQName.cpp index efa835ac..dd191c60 100644 --- a/utils/FQName.cpp +++ b/utils/FQName.cpp @@ -160,6 +160,31 @@ bool FQName::setTo(const std::string &s) { return !invalid; } +std::string FQName::getRelativeFQName(const FQName& relativeTo) const { + if (relativeTo.mPackage != mPackage) { + return string(); + } + + // Package is the same + std::string out; + if (relativeTo.version() != version()) { + out.append(atVersion()); + if (!mName.empty() && !version().empty()) { + out.append("::"); + } + } + + if (!mName.empty()) { + out.append(mName); + if (!mValueName.empty()) { + out.append(":"); + out.append(mValueName); + } + } + + return out; +} + const std::string& FQName::package() const { return mPackage; } diff --git a/utils/include/hidl-util/FQName.h b/utils/include/hidl-util/FQName.h index 416340a3..9d903026 100644 --- a/utils/include/hidl-util/FQName.h +++ b/utils/include/hidl-util/FQName.h @@ -108,6 +108,13 @@ struct FQName { bool operator==(const FQName &other) const; bool operator!=(const FQName &other) const; + // Provides the FQName relative to "relativeTo" + // If this is android.hardware.foo@1.0::IFoo it returns + // relativeTo: android.hardware.foo@1.0::IBar - IFoo + // relativeTo: android.hardware.foo@1.2::IFoo - @1.0::IFoo + // relativeTo: android.hardware.bar@1.0::IFoo - android.hardware.foo@1.0::IFoo + std::string getRelativeFQName(const FQName& relativeTo) const; + // Must be called on an interface // android.hardware.foo@1.0::IBar // -> Bar |