• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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