You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
345 lines
10 KiB
345 lines
10 KiB
/*
|
|
* Copyright (C) 2016 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 "Method.h"
|
|
|
|
#include "Annotation.h"
|
|
#include "ConstantExpression.h"
|
|
#include "FormattingConstants.h"
|
|
#include "Reference.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 <string>
|
|
#include <vector>
|
|
|
|
namespace android {
|
|
|
|
Method::Method(const std::string& name, std::vector<NamedReference<Type>*>* args,
|
|
std::vector<NamedReference<Type>*>* results, bool oneway,
|
|
std::vector<Annotation*>* annotations, const Location& location)
|
|
: mName(name),
|
|
mArgs(args),
|
|
mResults(results),
|
|
mOneway(oneway),
|
|
mAnnotations(annotations),
|
|
mLocation(location) {}
|
|
|
|
void Method::fillImplementation(
|
|
size_t serial,
|
|
MethodImpl cppImpl,
|
|
MethodImpl javaImpl) {
|
|
mIsHidlReserved = true;
|
|
mSerial = serial;
|
|
mCppImpl = cppImpl;
|
|
mJavaImpl = javaImpl;
|
|
|
|
CHECK(mJavaImpl.find(IMPL_STUB_IMPL) == mJavaImpl.end())
|
|
<< "FATAL: mJavaImpl should not use IMPL_STUB_IMPL; use IMPL_INTERFACE instead.";
|
|
CHECK(mCppImpl.find(IMPL_STUB_IMPL) == mCppImpl.end() ||
|
|
mCppImpl.find(IMPL_STUB) == mCppImpl.end())
|
|
<< "FATAL: mCppImpl IMPL_STUB will override IMPL_STUB_IMPL.";
|
|
}
|
|
|
|
std::string Method::name() const {
|
|
return mName;
|
|
}
|
|
|
|
const std::vector<NamedReference<Type>*>& Method::args() const {
|
|
return *mArgs;
|
|
}
|
|
|
|
const std::vector<NamedReference<Type>*>& Method::results() const {
|
|
return *mResults;
|
|
}
|
|
|
|
const std::vector<Annotation *> &Method::annotations() const {
|
|
return *mAnnotations;
|
|
}
|
|
|
|
std::vector<Reference<Type>*> Method::getReferences() {
|
|
const auto& constRet = static_cast<const Method*>(this)->getReferences();
|
|
std::vector<Reference<Type>*> ret(constRet.size());
|
|
std::transform(constRet.begin(), constRet.end(), ret.begin(),
|
|
[](const auto* ref) { return const_cast<Reference<Type>*>(ref); });
|
|
return ret;
|
|
}
|
|
|
|
std::vector<const Reference<Type>*> Method::getReferences() const {
|
|
std::vector<const Reference<Type>*> ret;
|
|
ret.insert(ret.end(), mArgs->begin(), mArgs->end());
|
|
ret.insert(ret.end(), mResults->begin(), mResults->end());
|
|
return ret;
|
|
}
|
|
|
|
std::vector<Reference<Type>*> Method::getStrongReferences() {
|
|
const auto& constRet = static_cast<const Method*>(this)->getStrongReferences();
|
|
std::vector<Reference<Type>*> ret(constRet.size());
|
|
std::transform(constRet.begin(), constRet.end(), ret.begin(),
|
|
[](const auto* ref) { return const_cast<Reference<Type>*>(ref); });
|
|
return ret;
|
|
}
|
|
|
|
std::vector<const Reference<Type>*> Method::getStrongReferences() const {
|
|
std::vector<const Reference<Type>*> ret;
|
|
for (const auto* ref : getReferences()) {
|
|
if (!ref->shallowGet()->isNeverStrongReference()) {
|
|
ret.push_back(ref);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void Method::cppImpl(MethodImplType type, Formatter &out) const {
|
|
CHECK(mIsHidlReserved);
|
|
auto it = mCppImpl.find(type);
|
|
if (it != mCppImpl.end()) {
|
|
if (it->second != nullptr) {
|
|
it->second(out);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Method::javaImpl(MethodImplType type, Formatter &out) const {
|
|
CHECK(mIsHidlReserved);
|
|
auto it = mJavaImpl.find(type);
|
|
if (it != mJavaImpl.end()) {
|
|
if (it->second != nullptr) {
|
|
it->second(out);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Method::overridesCppImpl(MethodImplType type) const {
|
|
CHECK(mIsHidlReserved);
|
|
return mCppImpl.find(type) != mCppImpl.end();
|
|
}
|
|
|
|
bool Method::overridesJavaImpl(MethodImplType type) const {
|
|
CHECK(mIsHidlReserved);
|
|
return mJavaImpl.find(type) != mJavaImpl.end();
|
|
}
|
|
|
|
Method* Method::copySignature() const {
|
|
Method* method = new Method(mName, mArgs, mResults, mOneway, mAnnotations, location());
|
|
method->setDocComment(getDocComment());
|
|
return method;
|
|
}
|
|
|
|
void Method::setSerialId(size_t serial) {
|
|
CHECK(!mIsHidlReserved);
|
|
mSerial = serial;
|
|
}
|
|
|
|
size_t Method::getSerialId() const {
|
|
return mSerial;
|
|
}
|
|
|
|
bool Method::hasEmptyCppArgSignature() const {
|
|
return args().empty() && (results().empty() || canElideCallback() != nullptr);
|
|
}
|
|
|
|
void Method::generateCppReturnType(Formatter &out, bool specifyNamespaces) const {
|
|
const NamedReference<Type>* elidedReturn = canElideCallback();
|
|
const std::string space = (specifyNamespaces ? "::android::hardware::" : "");
|
|
|
|
if (elidedReturn == nullptr) {
|
|
out << space << "Return<void> ";
|
|
} else {
|
|
out << space
|
|
<< "Return<"
|
|
<< elidedReturn->type().getCppResultType( specifyNamespaces)
|
|
<< "> ";
|
|
}
|
|
}
|
|
|
|
void Method::generateCppSignature(Formatter &out,
|
|
const std::string &className,
|
|
bool specifyNamespaces) const {
|
|
generateCppReturnType(out, specifyNamespaces);
|
|
|
|
if (!className.empty()) {
|
|
out << className << "::";
|
|
}
|
|
|
|
out << name()
|
|
<< "(";
|
|
emitCppArgSignature(out, specifyNamespaces);
|
|
out << ")";
|
|
}
|
|
|
|
static void emitCppArgResultSignature(Formatter& out,
|
|
const std::vector<NamedReference<Type>*>& args,
|
|
bool specifyNamespaces) {
|
|
out.join(args.begin(), args.end(), ", ", [&](auto arg) {
|
|
out << arg->type().getCppArgumentType(specifyNamespaces);
|
|
out << " ";
|
|
out << arg->name();
|
|
});
|
|
}
|
|
|
|
static void emitJavaArgResultSignature(Formatter& out,
|
|
const std::vector<NamedReference<Type>*>& args) {
|
|
out.join(args.begin(), args.end(), ", ", [&](auto arg) {
|
|
out << arg->type().getJavaType();
|
|
out << " ";
|
|
out << arg->name();
|
|
});
|
|
}
|
|
|
|
void Method::emitCppArgSignature(Formatter &out, bool specifyNamespaces) const {
|
|
emitCppArgResultSignature(out, args(), specifyNamespaces);
|
|
|
|
const bool returnsValue = !results().empty();
|
|
const NamedReference<Type>* elidedReturn = canElideCallback();
|
|
if (returnsValue && elidedReturn == nullptr) {
|
|
if (!args().empty()) {
|
|
out << ", ";
|
|
}
|
|
|
|
out << name() << "_cb _hidl_cb";
|
|
}
|
|
}
|
|
void Method::emitCppResultSignature(Formatter &out, bool specifyNamespaces) const {
|
|
emitCppArgResultSignature(out, results(), specifyNamespaces);
|
|
}
|
|
void Method::emitJavaArgSignature(Formatter &out) const {
|
|
emitJavaArgResultSignature(out, args());
|
|
}
|
|
void Method::emitJavaResultSignature(Formatter &out) const {
|
|
emitJavaArgResultSignature(out, results());
|
|
}
|
|
|
|
void Method::emitJavaSignature(Formatter& out) const {
|
|
const bool returnsValue = !results().empty();
|
|
const bool needsCallback = results().size() > 1;
|
|
|
|
if (returnsValue && !needsCallback) {
|
|
out << results()[0]->type().getJavaType();
|
|
} else {
|
|
out << "void";
|
|
}
|
|
|
|
out << " " << name() << "(";
|
|
emitJavaArgSignature(out);
|
|
|
|
if (needsCallback) {
|
|
if (!args().empty()) {
|
|
out << ", ";
|
|
}
|
|
|
|
out << name() << "Callback _hidl_cb";
|
|
}
|
|
|
|
out << ")";
|
|
}
|
|
|
|
static void fillHidlArgResultTokens(const std::vector<NamedReference<Type>*>& args,
|
|
WrappedOutput* wrappedOutput, const std::string& attachToLast) {
|
|
for (size_t i = 0; i < args.size(); i++) {
|
|
const NamedReference<Type>* arg = args[i];
|
|
std::string out = arg->localName() + " " + arg->name();
|
|
wrappedOutput->group([&] {
|
|
if (i != 0) wrappedOutput->printUnlessWrapped(" ");
|
|
*wrappedOutput << out;
|
|
if (i == args.size() - 1) {
|
|
if (!attachToLast.empty()) *wrappedOutput << attachToLast;
|
|
} else {
|
|
*wrappedOutput << ",";
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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() << "(";
|
|
|
|
if (!args().empty()) {
|
|
fillHidlArgResultTokens(args(), &wrappedOutput, results().empty() ? ");\n" : ")");
|
|
} else {
|
|
wrappedOutput << (results().empty() ? ");\n" : ")");
|
|
}
|
|
|
|
if (!results().empty()) {
|
|
wrappedOutput.group([&] {
|
|
wrappedOutput.printUnlessWrapped(" ");
|
|
wrappedOutput << "generates (";
|
|
fillHidlArgResultTokens(results(), &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); })) {
|
|
return false;
|
|
}
|
|
|
|
if (!std::all_of(mResults->begin(), mResults->end(),
|
|
[&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const NamedReference<Type>* Method::canElideCallback() const {
|
|
// Can't elide callback for void or tuple-returning methods
|
|
if (mResults->size() != 1) {
|
|
return nullptr;
|
|
}
|
|
|
|
const NamedReference<Type>* typedVar = mResults->at(0);
|
|
|
|
if (typedVar->type().isElidableType()) {
|
|
return typedVar;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const Location& Method::location() const {
|
|
return mLocation;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool TypedVarVector::add(NamedReference<Type>* v) {
|
|
if (mNames.emplace(v->name()).second) {
|
|
push_back(v);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace android
|
|
|