• 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 <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