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 "ConstantExpression.h"
21 #include "ScalarType.h"
22 #include "Type.h"
23 
24 #include <android-base/logging.h>
25 #include <hidl-util/Formatter.h>
26 #include <algorithm>
27 
28 namespace android {
29 
Method(const char * name,std::vector<NamedReference<Type> * > * args,std::vector<NamedReference<Type> * > * results,bool oneway,std::vector<Annotation * > * annotations,const Location & location)30 Method::Method(const char* name, std::vector<NamedReference<Type>*>* args,
31                std::vector<NamedReference<Type>*>* results, bool oneway,
32                std::vector<Annotation*>* annotations, const Location& location)
33     : mName(name),
34       mArgs(args),
35       mResults(results),
36       mOneway(oneway),
37       mAnnotations(annotations),
38       mLocation(location) {}
39 
fillImplementation(size_t serial,MethodImpl cppImpl,MethodImpl javaImpl)40 void 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 
name() const56 std::string Method::name() const {
57     return mName;
58 }
59 
args() const60 const std::vector<NamedReference<Type>*>& Method::args() const {
61     return *mArgs;
62 }
63 
results() const64 const std::vector<NamedReference<Type>*>& Method::results() const {
65     return *mResults;
66 }
67 
annotations() const68 const std::vector<Annotation *> &Method::annotations() const {
69     return *mAnnotations;
70 }
71 
getReferences()72 std::vector<Reference<Type>*> Method::getReferences() {
73     const auto& constRet = static_cast<const Method*>(this)->getReferences();
74     std::vector<Reference<Type>*> ret(constRet.size());
75     std::transform(constRet.begin(), constRet.end(), ret.begin(),
76                    [](const auto* ref) { return const_cast<Reference<Type>*>(ref); });
77     return ret;
78 }
79 
getReferences() const80 std::vector<const Reference<Type>*> Method::getReferences() const {
81     std::vector<const Reference<Type>*> ret;
82     ret.insert(ret.end(), mArgs->begin(), mArgs->end());
83     ret.insert(ret.end(), mResults->begin(), mResults->end());
84     return ret;
85 }
86 
getStrongReferences()87 std::vector<Reference<Type>*> Method::getStrongReferences() {
88     const auto& constRet = static_cast<const Method*>(this)->getStrongReferences();
89     std::vector<Reference<Type>*> ret(constRet.size());
90     std::transform(constRet.begin(), constRet.end(), ret.begin(),
91                    [](const auto* ref) { return const_cast<Reference<Type>*>(ref); });
92     return ret;
93 }
94 
getStrongReferences() const95 std::vector<const Reference<Type>*> Method::getStrongReferences() const {
96     std::vector<const Reference<Type>*> ret;
97     for (const auto* ref : getReferences()) {
98         if (!ref->shallowGet()->isNeverStrongReference()) {
99             ret.push_back(ref);
100         }
101     }
102     return ret;
103 }
104 
getConstantExpressions()105 std::vector<ConstantExpression*> Method::getConstantExpressions() {
106     const auto& constRet = static_cast<const Method*>(this)->getConstantExpressions();
107     std::vector<ConstantExpression*> ret(constRet.size());
108     std::transform(constRet.begin(), constRet.end(), ret.begin(),
109                    [](const auto* ce) { return const_cast<ConstantExpression*>(ce); });
110     return ret;
111 }
112 
getConstantExpressions() const113 std::vector<const ConstantExpression*> Method::getConstantExpressions() const {
114     std::vector<const ConstantExpression*> ret;
115     for (const auto* annotation : *mAnnotations) {
116         const auto& retAnnotation = annotation->getConstantExpressions();
117         ret.insert(ret.end(), retAnnotation.begin(), retAnnotation.end());
118     }
119     return ret;
120 }
121 
cppImpl(MethodImplType type,Formatter & out) const122 void Method::cppImpl(MethodImplType type, Formatter &out) const {
123     CHECK(mIsHidlReserved);
124     auto it = mCppImpl.find(type);
125     if (it != mCppImpl.end()) {
126         if (it->second != nullptr) {
127             it->second(out);
128         }
129     }
130 }
131 
javaImpl(MethodImplType type,Formatter & out) const132 void Method::javaImpl(MethodImplType type, Formatter &out) const {
133     CHECK(mIsHidlReserved);
134     auto it = mJavaImpl.find(type);
135     if (it != mJavaImpl.end()) {
136         if (it->second != nullptr) {
137             it->second(out);
138         }
139     }
140 }
141 
isHiddenFromJava() const142 bool Method::isHiddenFromJava() const {
143     return isHidlReserved() && name() == "debug";
144 }
145 
overridesCppImpl(MethodImplType type) const146 bool Method::overridesCppImpl(MethodImplType type) const {
147     CHECK(mIsHidlReserved);
148     return mCppImpl.find(type) != mCppImpl.end();
149 }
150 
overridesJavaImpl(MethodImplType type) const151 bool Method::overridesJavaImpl(MethodImplType type) const {
152     CHECK(mIsHidlReserved);
153     return mJavaImpl.find(type) != mJavaImpl.end();
154 }
155 
copySignature() const156 Method *Method::copySignature() const {
157     return new Method(mName.c_str(), mArgs, mResults, mOneway, mAnnotations, Location());
158 }
159 
setSerialId(size_t serial)160 void Method::setSerialId(size_t serial) {
161     CHECK(!mIsHidlReserved);
162     mSerial = serial;
163 }
164 
getSerialId() const165 size_t Method::getSerialId() const {
166     return mSerial;
167 }
168 
hasEmptyCppArgSignature() const169 bool Method::hasEmptyCppArgSignature() const {
170     return args().empty() && (results().empty() || canElideCallback() != nullptr);
171 }
172 
generateCppReturnType(Formatter & out,bool specifyNamespaces) const173 void Method::generateCppReturnType(Formatter &out, bool specifyNamespaces) const {
174     const NamedReference<Type>* elidedReturn = canElideCallback();
175     const std::string space = (specifyNamespaces ? "::android::hardware::" : "");
176 
177     if (elidedReturn == nullptr) {
178         out << space << "Return<void> ";
179     } else {
180         out << space
181             << "Return<"
182             << elidedReturn->type().getCppResultType( specifyNamespaces)
183             << "> ";
184     }
185 }
186 
generateCppSignature(Formatter & out,const std::string & className,bool specifyNamespaces) const187 void Method::generateCppSignature(Formatter &out,
188                                   const std::string &className,
189                                   bool specifyNamespaces) const {
190     generateCppReturnType(out, specifyNamespaces);
191 
192     if (!className.empty()) {
193         out << className << "::";
194     }
195 
196     out << name()
197         << "(";
198     emitCppArgSignature(out, specifyNamespaces);
199     out << ")";
200 }
201 
emitCppArgResultSignature(Formatter & out,const std::vector<NamedReference<Type> * > & args,bool specifyNamespaces)202 static void emitCppArgResultSignature(Formatter& out,
203                                       const std::vector<NamedReference<Type>*>& args,
204                                       bool specifyNamespaces) {
205     out.join(args.begin(), args.end(), ", ", [&](auto arg) {
206         out << arg->type().getCppArgumentType(specifyNamespaces);
207         out << " ";
208         out << arg->name();
209     });
210 }
211 
emitJavaArgResultSignature(Formatter & out,const std::vector<NamedReference<Type> * > & args)212 static void emitJavaArgResultSignature(Formatter& out,
213                                        const std::vector<NamedReference<Type>*>& args) {
214     out.join(args.begin(), args.end(), ", ", [&](auto arg) {
215         out << arg->type().getJavaType();
216         out << " ";
217         out << arg->name();
218     });
219 }
220 
emitCppArgSignature(Formatter & out,bool specifyNamespaces) const221 void Method::emitCppArgSignature(Formatter &out, bool specifyNamespaces) const {
222     emitCppArgResultSignature(out, args(), specifyNamespaces);
223 
224     const bool returnsValue = !results().empty();
225     const NamedReference<Type>* elidedReturn = canElideCallback();
226     if (returnsValue && elidedReturn == nullptr) {
227         if (!args().empty()) {
228             out << ", ";
229         }
230 
231         out << name() << "_cb _hidl_cb";
232     }
233 }
emitCppResultSignature(Formatter & out,bool specifyNamespaces) const234 void Method::emitCppResultSignature(Formatter &out, bool specifyNamespaces) const {
235     emitCppArgResultSignature(out, results(), specifyNamespaces);
236 }
emitJavaArgSignature(Formatter & out) const237 void Method::emitJavaArgSignature(Formatter &out) const {
238     emitJavaArgResultSignature(out, args());
239 }
emitJavaResultSignature(Formatter & out) const240 void Method::emitJavaResultSignature(Formatter &out) const {
241     emitJavaArgResultSignature(out, results());
242 }
243 
dumpAnnotations(Formatter & out) const244 void Method::dumpAnnotations(Formatter &out) const {
245     if (mAnnotations->size() == 0) {
246         return;
247     }
248 
249     out << "// ";
250     for (size_t i = 0; i < mAnnotations->size(); ++i) {
251         if (i > 0) {
252             out << " ";
253         }
254         mAnnotations->at(i)->dump(out);
255     }
256     out << "\n";
257 }
258 
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const259 bool Method::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
260     if (isHiddenFromJava()) {
261         return true;
262     }
263 
264     if (!std::all_of(mArgs->begin(), mArgs->end(),
265                      [&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) {
266         return false;
267     }
268 
269     if (!std::all_of(mResults->begin(), mResults->end(),
270                      [&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) {
271         return false;
272     }
273 
274     return true;
275 }
276 
canElideCallback() const277 const NamedReference<Type>* Method::canElideCallback() const {
278     // Can't elide callback for void or tuple-returning methods
279     if (mResults->size() != 1) {
280         return nullptr;
281     }
282 
283     const NamedReference<Type>* typedVar = mResults->at(0);
284 
285     if (typedVar->type().isElidableType()) {
286         return typedVar;
287     }
288 
289     return nullptr;
290 }
291 
location() const292 const Location& Method::location() const {
293     return mLocation;
294 }
295 
296 ////////////////////////////////////////////////////////////////////////////////
297 
add(NamedReference<Type> * v)298 bool TypedVarVector::add(NamedReference<Type>* v) {
299     if (mNames.emplace(v->name()).second) {
300         push_back(v);
301         return true;
302     }
303     return false;
304 }
305 
306 }  // namespace android
307 
308