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 "AST.h"
18
19 #include "Coordinator.h"
20 #include "EnumType.h"
21 #include "HandleType.h"
22 #include "Interface.h"
23 #include "Location.h"
24 #include "FmqType.h"
25 #include "Scope.h"
26 #include "TypeDef.h"
27
28 #include <hidl-util/Formatter.h>
29 #include <hidl-util/FQName.h>
30 #include <android-base/logging.h>
31 #include <iostream>
32 #include <stdlib.h>
33
34 namespace android {
35
AST(Coordinator * coordinator,const std::string & path)36 AST::AST(Coordinator *coordinator, const std::string &path)
37 : mCoordinator(coordinator),
38 mPath(path),
39 mScanner(NULL),
40 mRootScope(new Scope("" /* localName */, Location::startOf(path))) {
41 enterScope(mRootScope);
42 }
43
~AST()44 AST::~AST() {
45 delete mRootScope;
46 mRootScope = nullptr;
47
48 CHECK(mScanner == NULL);
49
50 // Ownership of "coordinator" was NOT transferred.
51 }
52
53 // used by the parser.
addSyntaxError()54 void AST::addSyntaxError() {
55 mSyntaxErrors++;
56 }
57
syntaxErrors() const58 size_t AST::syntaxErrors() const {
59 return mSyntaxErrors;
60 }
61
scanner()62 void *AST::scanner() {
63 return mScanner;
64 }
65
setScanner(void * scanner)66 void AST::setScanner(void *scanner) {
67 mScanner = scanner;
68 }
69
getFilename() const70 const std::string &AST::getFilename() const {
71 return mPath;
72 }
73
setPackage(const char * package)74 bool AST::setPackage(const char *package) {
75 mPackage.setTo(package);
76 CHECK(mPackage.isValid());
77
78 if (mPackage.package().empty()
79 || mPackage.version().empty()
80 || !mPackage.name().empty()) {
81 return false;
82 }
83
84 return true;
85 }
86
package() const87 FQName AST::package() const {
88 return mPackage;
89 }
90
isInterface(std::string * ifaceName) const91 bool AST::isInterface(std::string *ifaceName) const {
92 return mRootScope->containsSingleInterface(ifaceName);
93 }
94
containsInterfaces() const95 bool AST::containsInterfaces() const {
96 return mRootScope->containsInterfaces();
97 }
98
addImport(const char * import)99 bool AST::addImport(const char *import) {
100 FQName fqName(import);
101 CHECK(fqName.isValid());
102
103 fqName.applyDefaults(mPackage.package(), mPackage.version());
104
105 // LOG(INFO) << "importing " << fqName.string();
106
107 if (fqName.name().empty()) {
108 // import a package
109 std::vector<FQName> packageInterfaces;
110
111 status_t err =
112 mCoordinator->appendPackageInterfacesToVector(fqName,
113 &packageInterfaces);
114
115 if (err != OK) {
116 return false;
117 }
118
119 for (const auto &subFQName : packageInterfaces) {
120 // Do not enforce restrictions on imports.
121 AST *ast = mCoordinator->parse(subFQName, &mImportedASTs, false /* enforce */);
122 if (ast == nullptr) {
123 return false;
124 }
125 // all previous single type imports are ignored.
126 mImportedTypes.erase(ast);
127 }
128
129 return true;
130 }
131
132 AST *importAST;
133
134 // cases like android.hardware.foo@1.0::IFoo.Internal
135 // android.hardware.foo@1.0::Abc.Internal
136
137 // assume it is an interface, and try to import it.
138 const FQName interfaceName = fqName.getTopLevelType();
139 // Do not enforce restrictions on imports.
140 importAST = mCoordinator->parse(interfaceName, &mImportedASTs, false /* enforce */);
141
142 if (importAST != nullptr) {
143 // cases like android.hardware.foo@1.0::IFoo.Internal
144 // and android.hardware.foo@1.0::IFoo
145 if (fqName == interfaceName) {
146 // import a single file.
147 // all previous single type imports are ignored.
148 // cases like android.hardware.foo@1.0::IFoo
149 // and android.hardware.foo@1.0::types
150 mImportedTypes.erase(importAST);
151 return true;
152 }
153
154 // import a single type from this file
155 // cases like android.hardware.foo@1.0::IFoo.Internal
156 FQName matchingName;
157 Type *match = importAST->findDefinedType(fqName, &matchingName);
158 if (match == nullptr) {
159 return false;
160 }
161 // will automatically create a set if it does not exist
162 mImportedTypes[importAST].insert(match);
163 return true;
164 }
165
166 // probably a type in types.hal, like android.hardware.foo@1.0::Abc.Internal
167 FQName typesFQName = fqName.getTypesForPackage();
168
169 // Do not enforce restrictions on imports.
170 importAST = mCoordinator->parse(typesFQName, &mImportedASTs, false /* enforce */);
171
172 if (importAST != nullptr) {
173 // Attempt to find Abc.Internal in types.
174 FQName matchingName;
175 Type *match = importAST->findDefinedType(fqName, &matchingName);
176 if (match == nullptr) {
177 return false;
178 }
179 // will automatically create a set if not exist
180 mImportedTypes[importAST].insert(match);
181 return true;
182 }
183
184 // can't find an appropriate AST for fqName.
185 return false;
186 }
187
addImportedAST(AST * ast)188 void AST::addImportedAST(AST *ast) {
189 mImportedASTs.insert(ast);
190 }
191
enterScope(Scope * container)192 void AST::enterScope(Scope *container) {
193 mScopePath.push_back(container);
194 }
195
leaveScope()196 void AST::leaveScope() {
197 mScopePath.pop_back();
198 }
199
scope()200 Scope *AST::scope() {
201 CHECK(!mScopePath.empty());
202 return mScopePath.back();
203 }
204
addTypeDef(const char * localName,Type * type,const Location & location,std::string * errorMsg)205 bool AST::addTypeDef(const char *localName, Type *type, const Location &location,
206 std::string *errorMsg) {
207 // The reason we wrap the given type in a TypeDef is simply to suppress
208 // emitting any type definitions later on, since this is just an alias
209 // to a type defined elsewhere.
210 return addScopedTypeInternal(
211 new TypeDef(localName, location, type), errorMsg);
212 }
213
addScopedType(NamedType * type,std::string * errorMsg)214 bool AST::addScopedType(NamedType *type, std::string *errorMsg) {
215 return addScopedTypeInternal(
216 type, errorMsg);
217 }
218
addScopedTypeInternal(NamedType * type,std::string * errorMsg)219 bool AST::addScopedTypeInternal(
220 NamedType *type,
221 std::string *errorMsg) {
222
223 bool success = scope()->addType(type, errorMsg);
224 if (!success) {
225 return false;
226 }
227
228 std::string path;
229 for (size_t i = 1; i < mScopePath.size(); ++i) {
230 path.append(mScopePath[i]->localName());
231 path.append(".");
232 }
233 path.append(type->localName());
234
235 FQName fqName(mPackage.package(), mPackage.version(), path);
236
237 type->setFullName(fqName);
238
239 mDefinedTypesByFullName[fqName] = type;
240
241 return true;
242 }
243
lookupEnumValue(const FQName & fqName,std::string * errorMsg)244 EnumValue *AST::lookupEnumValue(const FQName &fqName, std::string *errorMsg) {
245
246 FQName enumTypeName = fqName.typeName();
247 std::string enumValueName = fqName.valueName();
248
249 CHECK(enumTypeName.isValid());
250 CHECK(!enumValueName.empty());
251
252 Type *type = lookupType(enumTypeName);
253 if(type == nullptr) {
254 *errorMsg = "Cannot find type " + enumTypeName.string();
255 return nullptr;
256 }
257 if(!type->isEnum()) {
258 *errorMsg = "Type " + enumTypeName.string() + " is not an enum type";
259 return nullptr;
260 }
261
262 EnumType *enumType = static_cast<EnumType *>(type);
263 EnumValue *v = static_cast<EnumValue *>(enumType->lookupIdentifier(enumValueName));
264 if(v == nullptr) {
265 *errorMsg = "Enum type " + enumTypeName.string() + " does not have " + enumValueName;
266 return nullptr;
267 }
268 return v;
269 }
270
lookupType(const FQName & fqName)271 Type *AST::lookupType(const FQName &fqName) {
272 CHECK(fqName.isValid());
273
274 if (fqName.name().empty()) {
275 // Given a package and version???
276 return nullptr;
277 }
278
279 Type *returnedType = nullptr;
280
281 if (fqName.package().empty() && fqName.version().empty()) {
282 // resolve locally first if possible.
283 returnedType = lookupTypeLocally(fqName);
284 if (returnedType != nullptr) {
285 return returnedType;
286 }
287 }
288
289 if (!fqName.isFullyQualified()) {
290 status_t status = lookupAutofilledType(fqName, &returnedType);
291 if (status != OK) {
292 return nullptr;
293 }
294 if (returnedType != nullptr) {
295 return returnedType;
296 }
297 }
298
299 return lookupTypeFromImports(fqName);
300 }
301
302 // Rule 0: try resolve locally
lookupTypeLocally(const FQName & fqName)303 Type *AST::lookupTypeLocally(const FQName &fqName) {
304 CHECK(fqName.package().empty() && fqName.version().empty()
305 && !fqName.name().empty() && fqName.valueName().empty());
306
307 for (size_t i = mScopePath.size(); i-- > 0;) {
308 Type *type = mScopePath[i]->lookupType(fqName);
309
310 if (type != nullptr) {
311 // Resolve typeDefs to the target type.
312 while (type->isTypeDef()) {
313 type = static_cast<TypeDef *>(type)->referencedType();
314 }
315
316 return type;
317 }
318 }
319
320 return nullptr;
321 }
322
323 // Rule 1: auto-fill with current package
lookupAutofilledType(const FQName & fqName,Type ** returnedType)324 status_t AST::lookupAutofilledType(const FQName &fqName, Type **returnedType) {
325 CHECK(!fqName.isFullyQualified() && !fqName.name().empty() && fqName.valueName().empty());
326
327 FQName autofilled = fqName;
328 autofilled.applyDefaults(mPackage.package(), mPackage.version());
329 FQName matchingName;
330 // Given this fully-qualified name, the type may be defined in this AST, or other files
331 // in import.
332 Type *local = findDefinedType(autofilled, &matchingName);
333 CHECK(local == nullptr || autofilled == matchingName);
334 Type *fromImport = lookupType(autofilled);
335
336 if (local != nullptr && fromImport != nullptr && local != fromImport) {
337 // Something bad happen; two types have the same FQName.
338 std::cerr << "ERROR: Unable to resolve type name '"
339 << fqName.string()
340 << "' (i.e. '"
341 << autofilled.string()
342 << "'), multiple definitions found.\n";
343
344 return UNKNOWN_ERROR;
345 }
346 if (local != nullptr) {
347 *returnedType = local;
348 return OK;
349 }
350 // If fromImport is nullptr as well, return nullptr to fall through to next rule.
351 *returnedType = fromImport;
352 return OK;
353 }
354
355 // Rule 2: look at imports
lookupTypeFromImports(const FQName & fqName)356 Type *AST::lookupTypeFromImports(const FQName &fqName) {
357
358 Type *resolvedType = nullptr;
359 Type *returnedType = nullptr;
360 FQName resolvedName;
361
362 for (const auto &importedAST : mImportedASTs) {
363 if (mImportedTypes.find(importedAST) != mImportedTypes.end()) {
364 // ignore single type imports
365 continue;
366 }
367 FQName matchingName;
368 Type *match = importedAST->findDefinedType(fqName, &matchingName);
369
370 if (match != nullptr) {
371 if (resolvedType != nullptr) {
372 std::cerr << "ERROR: Unable to resolve type name '"
373 << fqName.string()
374 << "', multiple matches found:\n";
375
376 std::cerr << " " << resolvedName.string() << "\n";
377 std::cerr << " " << matchingName.string() << "\n";
378
379 return nullptr;
380 }
381
382 resolvedType = match;
383 returnedType = resolvedType;
384 resolvedName = matchingName;
385
386 // Keep going even after finding a match.
387 }
388 }
389
390 for (const auto &pair : mImportedTypes) {
391 AST *importedAST = pair.first;
392 std::set<Type *> importedTypes = pair.second;
393
394 FQName matchingName;
395 Type *match = importedAST->findDefinedType(fqName, &matchingName);
396 if (match != nullptr &&
397 importedTypes.find(match) != importedTypes.end()) {
398 if (resolvedType != nullptr) {
399 std::cerr << "ERROR: Unable to resolve type name '"
400 << fqName.string()
401 << "', multiple matches found:\n";
402
403 std::cerr << " " << resolvedName.string() << "\n";
404 std::cerr << " " << matchingName.string() << "\n";
405
406 return nullptr;
407 }
408
409 resolvedType = match;
410 returnedType = resolvedType;
411 resolvedName = matchingName;
412
413 // Keep going even after finding a match.
414 }
415 }
416
417 if (resolvedType) {
418 #if 0
419 LOG(INFO) << "found '"
420 << resolvedName.string()
421 << "' after looking for '"
422 << fqName.string()
423 << "'.";
424 #endif
425
426 // Resolve typeDefs to the target type.
427 while (resolvedType->isTypeDef()) {
428 resolvedType =
429 static_cast<TypeDef *>(resolvedType)->referencedType();
430 }
431
432 returnedType = resolvedType;
433
434 // If the resolved type is not an interface, we need to determine
435 // whether it is defined in types.hal, or in some other interface. In
436 // the latter case, we need to emit a dependency for the interface in
437 // which the type is defined.
438 //
439 // Consider the following:
440 // android.hardware.tests.foo@1.0::Record
441 // android.hardware.tests.foo@1.0::IFoo.Folder
442 // android.hardware.tests.foo@1.0::Folder
443 //
444 // If Record is an interface, then we keep track of it for the purpose
445 // of emitting dependencies in the target language (for example #include
446 // in C++). If Record is a UDT, then we assume it is defined in
447 // types.hal in android.hardware.tests.foo@1.0.
448 //
449 // In the case of IFoo.Folder, the same applies. If IFoo is an
450 // interface, we need to track this for the purpose of emitting
451 // dependencies. If not, then it must have been defined in types.hal.
452 //
453 // In the case of just specifying Folder, the resolved type is
454 // android.hardware.tests.foo@1.0::Folder, and the same logic as
455 // above applies.
456
457 if (!resolvedType->isInterface()) {
458 FQName ifc = resolvedName.getTopLevelType();
459 for (const auto &importedAST : mImportedASTs) {
460 FQName matchingName;
461 Type *match = importedAST->findDefinedType(ifc, &matchingName);
462 if (match != nullptr && match->isInterface()) {
463 resolvedType = match;
464 }
465 }
466 }
467
468 if (!resolvedType->isInterface()) {
469 // Non-interface types are declared in the associated types header.
470 FQName typesName = resolvedName.getTypesForPackage();
471
472 mImportedNames.insert(typesName);
473 } else {
474 // Do _not_ use fqName, i.e. the name we used to look up the type,
475 // but instead use the name of the interface we found.
476 // This is necessary because if fqName pointed to a typedef which
477 // in turn referenced the found interface we'd mistakenly use the
478 // name of the typedef instead of the proper name of the interface.
479
480 mImportedNames.insert(
481 static_cast<Interface *>(resolvedType)->fqName());
482 }
483 }
484
485 return returnedType;
486 }
487
findDefinedType(const FQName & fqName,FQName * matchingName) const488 Type *AST::findDefinedType(const FQName &fqName, FQName *matchingName) const {
489 for (const auto &pair : mDefinedTypesByFullName) {
490 const FQName &key = pair.first;
491 Type* type = pair.second;
492
493 if (key.endsWith(fqName)) {
494 *matchingName = key;
495 return type;
496 }
497 }
498
499 return nullptr;
500 }
501
getImportedPackages(std::set<FQName> * importSet) const502 void AST::getImportedPackages(std::set<FQName> *importSet) const {
503 for (const auto &fqName : mImportedNames) {
504 FQName packageName = fqName.getPackageAndVersion();
505
506 if (packageName == mPackage) {
507 // We only care about external imports, not our own package.
508 continue;
509 }
510
511 importSet->insert(packageName);
512 }
513 }
514
getImportedPackagesHierarchy(std::set<FQName> * importSet) const515 void AST::getImportedPackagesHierarchy(std::set<FQName> *importSet) const {
516 getImportedPackages(importSet);
517 std::set<FQName> newSet;
518 for (const auto &ast : mImportedASTs) {
519 if (importSet->find(ast->package()) != importSet->end()) {
520 ast->getImportedPackagesHierarchy(&newSet);
521 }
522 }
523 importSet->insert(newSet.begin(), newSet.end());
524 }
525
getAllImportedNames(std::set<FQName> * allImportNames) const526 void AST::getAllImportedNames(std::set<FQName> *allImportNames) const {
527 for (const auto& name : mImportedNames) {
528 allImportNames->insert(name);
529 AST *ast = mCoordinator->parse(name, nullptr /* imported */, false /* enforce */);
530 ast->getAllImportedNames(allImportNames);
531 }
532 }
533
isJavaCompatible() const534 bool AST::isJavaCompatible() const {
535 std::string ifaceName;
536 if (!AST::isInterface(&ifaceName)) {
537 for (const auto *type : mRootScope->getSubTypes()) {
538 if (!type->isJavaCompatible()) {
539 return false;
540 }
541 }
542
543 return true;
544 }
545
546 const Interface *iface = mRootScope->getInterface();
547 return iface->isJavaCompatible();
548 }
549
appendToExportedTypesVector(std::vector<const Type * > * exportedTypes) const550 void AST::appendToExportedTypesVector(
551 std::vector<const Type *> *exportedTypes) const {
552 mRootScope->appendToExportedTypesVector(exportedTypes);
553 }
554
isIBase() const555 bool AST::isIBase() const {
556 Interface *iface = mRootScope->getInterface();
557 return iface != nullptr && iface->isIBase();
558 }
559
getInterface() const560 const Interface *AST::getInterface() const {
561 return mRootScope->getInterface();
562 }
563
564 } // namespace android;
565