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