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
diff --git a/AST.h b/AST.h
index 47f0846..e9c1367 100644
--- a/AST.h
+++ b/AST.h
@@ -161,6 +161,8 @@
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;
diff --git a/Android.bp b/Android.bp
index 830be46..b712dbe 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,6 +110,7 @@
"generateCppAdapter.cpp",
"generateCppImpl.cpp",
"generateDependencies.cpp",
+ "generateFormattedHidl.cpp",
"generateInheritanceHierarchy.cpp",
"generateJava.cpp",
"generateJavaImpl.cpp",
diff --git a/Annotation.cpp b/Annotation.cpp
index 438cff6..4c9637f 100644
--- a/Annotation.cpp
+++ b/Annotation.cpp
@@ -158,7 +158,7 @@
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 33424d8..5e491cf 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 68bcedf..a431912 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -632,6 +632,24 @@
}
}
+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 3dec6af..2c5a055 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -100,6 +100,7 @@
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 002bf56..6badf57 100644
--- a/ConstantExpression.cpp
+++ b/ConstantExpression.cpp
@@ -164,17 +164,19 @@
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 @@
CHECK(mUnary->isEvaluated());
mIsEvaluated = true;
- mExpr = std::string("(") + mOp + mUnary->mExpr + ")";
mValueKind = mUnary->mValueKind;
#define CASE_UNARY(__type__) \
@@ -270,8 +271,6 @@
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 @@
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 @@
}
const std::string& ConstantExpression::expression() const {
- CHECK(isEvaluated());
return mExpr;
}
@@ -683,7 +679,7 @@
}
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 @@
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 @@
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 @@
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 @@
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 b770716..9f20fd5 100644
--- a/ConstantExpression.h
+++ b/ConstantExpression.h
@@ -46,6 +46,7 @@
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 @@
/* 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 abc69fc..1aa22ed 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 707679a..2a1c981 100644
--- a/DocComment.cpp
+++ b/DocComment.cpp
@@ -63,8 +63,16 @@
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 58c8e17..315ef60 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 6a3a002..d0e88a3 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -251,6 +251,31 @@
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 @@
} 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 @@
////////////////////////////////////////////////////////////////////////////////
-BitFieldType::BitFieldType(Scope* parent) : TemplatedType(parent) {}
+BitFieldType::BitFieldType(Scope* parent) : TemplatedType(parent, "bitfield") {}
bool BitFieldType::isBitField() const {
return true;
diff --git a/EnumType.h b/EnumType.h
index b429e39..ab796d1 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -96,6 +96,7 @@
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 f5eaaa6..ed323f2 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;
diff --git a/FmqType.h b/FmqType.h
index 747b10a..f6b1f18 100644
--- a/FmqType.h
+++ b/FmqType.h
@@ -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 0000000..1ab5a17
--- /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 56660a6..1c612e5 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 b6d2f38..ff33972 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -822,6 +822,31 @@
}
}
+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 56570f5..e0fcb8b 100644
--- a/Interface.h
+++ b/Interface.h
@@ -111,6 +111,8 @@
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 444ba92..380214f 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 {
diff --git a/Method.cpp b/Method.cpp
index 7954462..42b4d5c 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -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 @@
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); })) {
diff --git a/Method.h b/Method.h
index 4b43a4b..5c5ac47 100644
--- a/Method.h
+++ b/Method.h
@@ -103,6 +103,8 @@
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 645c63d..dba9248 100644
--- a/NamedType.cpp
+++ b/NamedType.cpp
@@ -20,7 +20,7 @@
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 @@
}
} // namespace android
-
diff --git a/PointerType.cpp b/PointerType.cpp
index 2b8e5a4..f6eaf54 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 ba39ac4..b817514 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 @@
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 @@
return mLocation;
}
- private:
+ const std::string& localName() const { return mLocalName; }
+
+ private:
/* Referred type */
T* mResolved = nullptr;
/* Reference name for lookup */
@@ -109,6 +120,9 @@
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 e6f3fe4..142aac2 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;
diff --git a/Scope.cpp b/Scope.cpp
index d4953aa..cfe004d 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -122,6 +122,16 @@
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::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;
diff --git a/Scope.h b/Scope.h
index bf7d1cd..a62bad8 100644
--- a/Scope.h
+++ b/Scope.h
@@ -69,6 +69,8 @@
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 @@
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 b4f72be..edb183f 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;
diff --git a/Type.cpp b/Type.cpp
index d576615..80bce2a 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -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 @@
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 @@
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 @@
////////////////////////////////////////
-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 @@
CHECK(!elementType.isEmptyReference());
mElementType = elementType;
+ mDefinedName = mDefinedName + "<" + mElementType.localName() + ">";
}
const Type* TemplatedType::getElementType() const {
diff --git a/Type.h b/Type.h
index 6131068..0ed120b 100644
--- a/Type.h
+++ b/Type.h
@@ -38,7 +38,7 @@
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 @@
Scope* parent();
const Scope* parent() const;
+ const std::string& definedName() const;
+
enum StorageMode {
StorageMode_Stack,
StorageMode_Argument,
@@ -251,6 +253,8 @@
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 @@
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 @@
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 80522a2..2e36c28 100644
--- a/TypeDef.cpp
+++ b/TypeDef.cpp
@@ -80,5 +80,9 @@
<< ";\n\n";
}
+void TypeDef::emitHidlDefinition(Formatter& out) const {
+ out << "typedef " << mReferencedType.localName() << " " << localName() << ";\n";
+}
+
} // namespace android
diff --git a/TypeDef.h b/TypeDef.h
index 5ebba3e..d620765 100644
--- a/TypeDef.h
+++ b/TypeDef.h
@@ -44,8 +44,9 @@
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 b5e8e22..3bd2d38 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 0000000..742652e
--- /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 81fe151..7d76832 100644
--- a/hidl-gen_l.ll
+++ b/hidl-gen_l.ll
@@ -129,8 +129,8 @@
"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 58f78d0..7d4650d 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -529,11 +529,11 @@
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 @@
}
if (superType == nullptr) {
- superType = new Reference<Type>(gIBaseFqName, convertYYLoc(@$, ast));
+ superType = new Reference<Type>(gIBaseFqName.string(), gIBaseFqName, convertYYLoc(@$, ast));
}
}
@@ -788,12 +788,12 @@
}
$$ = 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 @@
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 @@
| 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 @@
: 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 { $$ = $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 534e8cd..2268e30 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 @@
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 @@
}
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 @@
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 @@
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 bdb89be..5ce2351 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 @@
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 @@
void unsetLinePrefix();
bool isValid() const;
+ size_t getIndentation() const;
- private:
+ private:
// Creates an invalid formatter object.
Formatter();
diff --git a/main.cpp b/main.cpp
index 27151d6..2a13fff 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1283,6 +1283,21 @@
},
},
},
+ {
+ "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 efa835a..dd191c6 100644
--- a/utils/FQName.cpp
+++ b/utils/FQName.cpp
@@ -160,6 +160,31 @@
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 416340a..9d90302 100644
--- a/utils/include/hidl-util/FQName.h
+++ b/utils/include/hidl-util/FQName.h
@@ -108,6 +108,13 @@
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