1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Method.h"
18
19#include "Annotation.h"
20#include "ScalarType.h"
21#include "Type.h"
22
23#include <android-base/logging.h>
24#include <hidl-util/Formatter.h>
25
26namespace android {
27
28Method::Method(const char *name,
29       std::vector<TypedVar *> *args,
30       std::vector<TypedVar *> *results,
31       bool oneway,
32       std::vector<Annotation *> *annotations)
33    : mName(name),
34      mArgs(args),
35      mResults(results),
36      mOneway(oneway),
37      mAnnotations(annotations) {
38}
39
40void Method::fillImplementation(
41        size_t serial,
42        MethodImpl cppImpl,
43        MethodImpl javaImpl) {
44    mIsHidlReserved = true;
45    mSerial = serial;
46    mCppImpl = cppImpl;
47    mJavaImpl = javaImpl;
48
49    CHECK(mJavaImpl.find(IMPL_STUB_IMPL) == mJavaImpl.end())
50            << "FATAL: mJavaImpl should not use IMPL_STUB_IMPL; use IMPL_INTERFACE instead.";
51    CHECK(mCppImpl.find(IMPL_STUB_IMPL) == mCppImpl.end() ||
52          mCppImpl.find(IMPL_STUB) == mCppImpl.end())
53            << "FATAL: mCppImpl IMPL_STUB will override IMPL_STUB_IMPL.";
54}
55
56std::string Method::name() const {
57    return mName;
58}
59
60const std::vector<TypedVar *> &Method::args() const {
61    return *mArgs;
62}
63
64const std::vector<TypedVar *> &Method::results() const {
65    return *mResults;
66}
67
68const std::vector<Annotation *> &Method::annotations() const {
69    return *mAnnotations;
70}
71
72void Method::cppImpl(MethodImplType type, Formatter &out) const {
73    CHECK(mIsHidlReserved);
74    auto it = mCppImpl.find(type);
75    if (it != mCppImpl.end()) {
76        if (it->second != nullptr) {
77            it->second(out);
78        }
79    }
80}
81
82void Method::javaImpl(MethodImplType type, Formatter &out) const {
83    CHECK(mIsHidlReserved);
84    auto it = mJavaImpl.find(type);
85    if (it != mJavaImpl.end()) {
86        if (it->second != nullptr) {
87            it->second(out);
88        }
89    }
90}
91
92bool Method::isHiddenFromJava() const {
93    return isHidlReserved() && name() == "debug";
94}
95
96bool Method::overridesCppImpl(MethodImplType type) const {
97    CHECK(mIsHidlReserved);
98    return mCppImpl.find(type) != mCppImpl.end();
99}
100
101bool Method::overridesJavaImpl(MethodImplType type) const {
102    CHECK(mIsHidlReserved);
103    return mJavaImpl.find(type) != mJavaImpl.end();
104}
105
106Method *Method::copySignature() const {
107    return new Method(mName.c_str(), mArgs, mResults, mOneway, mAnnotations);
108}
109
110void Method::setSerialId(size_t serial) {
111    CHECK(!mIsHidlReserved);
112    mSerial = serial;
113}
114
115size_t Method::getSerialId() const {
116    return mSerial;
117}
118
119void Method::generateCppSignature(Formatter &out,
120                                  const std::string &className,
121                                  bool specifyNamespaces) const {
122    const bool returnsValue = !results().empty();
123
124    const TypedVar *elidedReturn = canElideCallback();
125
126    std::string space = (specifyNamespaces ? "::android::hardware::" : "");
127
128    if (elidedReturn == nullptr) {
129        out << space << "Return<void> ";
130    } else {
131        out << space
132            << "Return<"
133            << elidedReturn->type().getCppResultType( specifyNamespaces)
134            << "> ";
135    }
136
137    if (!className.empty()) {
138        out << className << "::";
139    }
140
141    out << name()
142        << "(";
143    emitCppArgSignature(out, specifyNamespaces);
144
145    if (returnsValue && elidedReturn == nullptr) {
146        if (!args().empty()) {
147            out << ", ";
148        }
149
150        out << name() << "_cb _hidl_cb";
151    }
152
153    out << ")";
154}
155
156static void emitCppArgResultSignature(Formatter &out,
157                         const std::vector<TypedVar *> &args,
158                         bool specifyNamespaces) {
159    out.join(args.begin(), args.end(), ", ", [&](auto arg) {
160        out << arg->type().getCppArgumentType(specifyNamespaces);
161        out << " ";
162        out << arg->name();
163    });
164}
165
166static void emitJavaArgResultSignature(Formatter &out, const std::vector<TypedVar *> &args) {
167    out.join(args.begin(), args.end(), ", ", [&](auto arg) {
168        out << arg->type().getJavaType();
169        out << " ";
170        out << arg->name();
171    });
172}
173
174void Method::emitCppArgSignature(Formatter &out, bool specifyNamespaces) const {
175    emitCppArgResultSignature(out, args(), specifyNamespaces);
176}
177void Method::emitCppResultSignature(Formatter &out, bool specifyNamespaces) const {
178    emitCppArgResultSignature(out, results(), specifyNamespaces);
179}
180void Method::emitJavaArgSignature(Formatter &out) const {
181    emitJavaArgResultSignature(out, args());
182}
183void Method::emitJavaResultSignature(Formatter &out) const {
184    emitJavaArgResultSignature(out, results());
185}
186
187void Method::dumpAnnotations(Formatter &out) const {
188    if (mAnnotations->size() == 0) {
189        return;
190    }
191
192    out << "// ";
193    for (size_t i = 0; i < mAnnotations->size(); ++i) {
194        if (i > 0) {
195            out << " ";
196        }
197        mAnnotations->at(i)->dump(out);
198    }
199    out << "\n";
200}
201
202bool Method::isJavaCompatible() const {
203    if (isHiddenFromJava()) {
204        return true;
205    }
206
207    for (const auto &arg : *mArgs) {
208        if (!arg->isJavaCompatible()) {
209            return false;
210        }
211    }
212
213    for (const auto &result : *mResults) {
214        if (!result->isJavaCompatible()) {
215            return false;
216        }
217    }
218
219    return true;
220}
221
222const TypedVar* Method::canElideCallback() const {
223    // Can't elide callback for void or tuple-returning methods
224    if (mResults->size() != 1) {
225        return nullptr;
226    }
227
228    const TypedVar *typedVar = mResults->at(0);
229
230    if (typedVar->type().isElidableType()) {
231        return typedVar;
232    }
233
234    return nullptr;
235}
236
237////////////////////////////////////////////////////////////////////////////////
238
239TypedVar::TypedVar(const char *name, Type *type)
240    : mName(name),
241      mType(type) {
242}
243
244std::string TypedVar::name() const {
245    return mName;
246}
247
248const Type &TypedVar::type() const {
249    return *mType;
250}
251
252bool TypedVar::isJavaCompatible() const {
253    return mType->isJavaCompatible();
254}
255
256////////////////////////////////////////////////////////////////////////////////
257bool TypedVarVector::add(TypedVar *v) {
258    if (mNames.emplace(v->name()).second) {
259        push_back(v);
260        return true;
261    }
262    return false;
263}
264
265}  // namespace android
266
267