/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "AST.h" #include "Coordinator.h" #include "EnumType.h" #include "HandleType.h" #include "Interface.h" #include "Location.h" #include "FmqType.h" #include "Scope.h" #include "TypeDef.h" #include #include #include #include #include namespace android { AST::AST(Coordinator *coordinator, const std::string &path) : mCoordinator(coordinator), mPath(path), mScanner(NULL), mRootScope(new Scope("" /* localName */, Location::startOf(path))) { enterScope(mRootScope); } AST::~AST() { delete mRootScope; mRootScope = nullptr; CHECK(mScanner == NULL); // Ownership of "coordinator" was NOT transferred. } // used by the parser. void AST::addSyntaxError() { mSyntaxErrors++; } size_t AST::syntaxErrors() const { return mSyntaxErrors; } void *AST::scanner() { return mScanner; } void AST::setScanner(void *scanner) { mScanner = scanner; } const std::string &AST::getFilename() const { return mPath; } bool AST::setPackage(const char *package) { mPackage.setTo(package); CHECK(mPackage.isValid()); if (mPackage.package().empty() || mPackage.version().empty() || !mPackage.name().empty()) { return false; } return true; } FQName AST::package() const { return mPackage; } bool AST::isInterface(std::string *ifaceName) const { return mRootScope->containsSingleInterface(ifaceName); } bool AST::containsInterfaces() const { return mRootScope->containsInterfaces(); } bool AST::addImport(const char *import) { FQName fqName(import); CHECK(fqName.isValid()); fqName.applyDefaults(mPackage.package(), mPackage.version()); // LOG(INFO) << "importing " << fqName.string(); if (fqName.name().empty()) { // import a package std::vector packageInterfaces; status_t err = mCoordinator->appendPackageInterfacesToVector(fqName, &packageInterfaces); if (err != OK) { return false; } for (const auto &subFQName : packageInterfaces) { // Do not enforce restrictions on imports. AST *ast = mCoordinator->parse(subFQName, &mImportedASTs, false /* enforce */); if (ast == nullptr) { return false; } // all previous single type imports are ignored. mImportedTypes.erase(ast); } return true; } AST *importAST; // cases like android.hardware.foo@1.0::IFoo.Internal // android.hardware.foo@1.0::Abc.Internal // assume it is an interface, and try to import it. const FQName interfaceName = fqName.getTopLevelType(); // Do not enforce restrictions on imports. importAST = mCoordinator->parse(interfaceName, &mImportedASTs, false /* enforce */); if (importAST != nullptr) { // cases like android.hardware.foo@1.0::IFoo.Internal // and android.hardware.foo@1.0::IFoo if (fqName == interfaceName) { // import a single file. // all previous single type imports are ignored. // cases like android.hardware.foo@1.0::IFoo // and android.hardware.foo@1.0::types mImportedTypes.erase(importAST); return true; } // import a single type from this file // cases like android.hardware.foo@1.0::IFoo.Internal FQName matchingName; Type *match = importAST->findDefinedType(fqName, &matchingName); if (match == nullptr) { return false; } // will automatically create a set if it does not exist mImportedTypes[importAST].insert(match); return true; } // probably a type in types.hal, like android.hardware.foo@1.0::Abc.Internal FQName typesFQName = fqName.getTypesForPackage(); // Do not enforce restrictions on imports. importAST = mCoordinator->parse(typesFQName, &mImportedASTs, false /* enforce */); if (importAST != nullptr) { // Attempt to find Abc.Internal in types. FQName matchingName; Type *match = importAST->findDefinedType(fqName, &matchingName); if (match == nullptr) { return false; } // will automatically create a set if not exist mImportedTypes[importAST].insert(match); return true; } // can't find an appropriate AST for fqName. return false; } void AST::addImportedAST(AST *ast) { mImportedASTs.insert(ast); } void AST::enterScope(Scope *container) { mScopePath.push_back(container); } void AST::leaveScope() { mScopePath.pop_back(); } Scope *AST::scope() { CHECK(!mScopePath.empty()); return mScopePath.back(); } bool AST::addTypeDef(const char *localName, Type *type, const Location &location, std::string *errorMsg) { // The reason we wrap the given type in a TypeDef is simply to suppress // emitting any type definitions later on, since this is just an alias // to a type defined elsewhere. return addScopedTypeInternal( new TypeDef(localName, location, type), errorMsg); } bool AST::addScopedType(NamedType *type, std::string *errorMsg) { return addScopedTypeInternal( type, errorMsg); } bool AST::addScopedTypeInternal( NamedType *type, std::string *errorMsg) { bool success = scope()->addType(type, errorMsg); if (!success) { return false; } std::string path; for (size_t i = 1; i < mScopePath.size(); ++i) { path.append(mScopePath[i]->localName()); path.append("."); } path.append(type->localName()); FQName fqName(mPackage.package(), mPackage.version(), path); type->setFullName(fqName); mDefinedTypesByFullName[fqName] = type; return true; } EnumValue *AST::lookupEnumValue(const FQName &fqName, std::string *errorMsg) { FQName enumTypeName = fqName.typeName(); std::string enumValueName = fqName.valueName(); CHECK(enumTypeName.isValid()); CHECK(!enumValueName.empty()); Type *type = lookupType(enumTypeName); if(type == nullptr) { *errorMsg = "Cannot find type " + enumTypeName.string(); return nullptr; } if(!type->isEnum()) { *errorMsg = "Type " + enumTypeName.string() + " is not an enum type"; return nullptr; } EnumType *enumType = static_cast(type); EnumValue *v = static_cast(enumType->lookupIdentifier(enumValueName)); if(v == nullptr) { *errorMsg = "Enum type " + enumTypeName.string() + " does not have " + enumValueName; return nullptr; } return v; } Type *AST::lookupType(const FQName &fqName) { CHECK(fqName.isValid()); if (fqName.name().empty()) { // Given a package and version??? return nullptr; } Type *returnedType = nullptr; if (fqName.package().empty() && fqName.version().empty()) { // resolve locally first if possible. returnedType = lookupTypeLocally(fqName); if (returnedType != nullptr) { return returnedType; } } if (!fqName.isFullyQualified()) { status_t status = lookupAutofilledType(fqName, &returnedType); if (status != OK) { return nullptr; } if (returnedType != nullptr) { return returnedType; } } return lookupTypeFromImports(fqName); } // Rule 0: try resolve locally Type *AST::lookupTypeLocally(const FQName &fqName) { CHECK(fqName.package().empty() && fqName.version().empty() && !fqName.name().empty() && fqName.valueName().empty()); for (size_t i = mScopePath.size(); i-- > 0;) { Type *type = mScopePath[i]->lookupType(fqName); if (type != nullptr) { // Resolve typeDefs to the target type. while (type->isTypeDef()) { type = static_cast(type)->referencedType(); } return type; } } return nullptr; } // Rule 1: auto-fill with current package status_t AST::lookupAutofilledType(const FQName &fqName, Type **returnedType) { CHECK(!fqName.isFullyQualified() && !fqName.name().empty() && fqName.valueName().empty()); FQName autofilled = fqName; autofilled.applyDefaults(mPackage.package(), mPackage.version()); FQName matchingName; // Given this fully-qualified name, the type may be defined in this AST, or other files // in import. Type *local = findDefinedType(autofilled, &matchingName); CHECK(local == nullptr || autofilled == matchingName); Type *fromImport = lookupType(autofilled); if (local != nullptr && fromImport != nullptr && local != fromImport) { // Something bad happen; two types have the same FQName. std::cerr << "ERROR: Unable to resolve type name '" << fqName.string() << "' (i.e. '" << autofilled.string() << "'), multiple definitions found.\n"; return UNKNOWN_ERROR; } if (local != nullptr) { *returnedType = local; return OK; } // If fromImport is nullptr as well, return nullptr to fall through to next rule. *returnedType = fromImport; return OK; } // Rule 2: look at imports Type *AST::lookupTypeFromImports(const FQName &fqName) { Type *resolvedType = nullptr; Type *returnedType = nullptr; FQName resolvedName; for (const auto &importedAST : mImportedASTs) { if (mImportedTypes.find(importedAST) != mImportedTypes.end()) { // ignore single type imports continue; } FQName matchingName; Type *match = importedAST->findDefinedType(fqName, &matchingName); if (match != nullptr) { if (resolvedType != nullptr) { std::cerr << "ERROR: Unable to resolve type name '" << fqName.string() << "', multiple matches found:\n"; std::cerr << " " << resolvedName.string() << "\n"; std::cerr << " " << matchingName.string() << "\n"; return nullptr; } resolvedType = match; returnedType = resolvedType; resolvedName = matchingName; // Keep going even after finding a match. } } for (const auto &pair : mImportedTypes) { AST *importedAST = pair.first; std::set importedTypes = pair.second; FQName matchingName; Type *match = importedAST->findDefinedType(fqName, &matchingName); if (match != nullptr && importedTypes.find(match) != importedTypes.end()) { if (resolvedType != nullptr) { std::cerr << "ERROR: Unable to resolve type name '" << fqName.string() << "', multiple matches found:\n"; std::cerr << " " << resolvedName.string() << "\n"; std::cerr << " " << matchingName.string() << "\n"; return nullptr; } resolvedType = match; returnedType = resolvedType; resolvedName = matchingName; // Keep going even after finding a match. } } if (resolvedType) { #if 0 LOG(INFO) << "found '" << resolvedName.string() << "' after looking for '" << fqName.string() << "'."; #endif // Resolve typeDefs to the target type. while (resolvedType->isTypeDef()) { resolvedType = static_cast(resolvedType)->referencedType(); } returnedType = resolvedType; // If the resolved type is not an interface, we need to determine // whether it is defined in types.hal, or in some other interface. In // the latter case, we need to emit a dependency for the interface in // which the type is defined. // // Consider the following: // android.hardware.tests.foo@1.0::Record // android.hardware.tests.foo@1.0::IFoo.Folder // android.hardware.tests.foo@1.0::Folder // // If Record is an interface, then we keep track of it for the purpose // of emitting dependencies in the target language (for example #include // in C++). If Record is a UDT, then we assume it is defined in // types.hal in android.hardware.tests.foo@1.0. // // In the case of IFoo.Folder, the same applies. If IFoo is an // interface, we need to track this for the purpose of emitting // dependencies. If not, then it must have been defined in types.hal. // // In the case of just specifying Folder, the resolved type is // android.hardware.tests.foo@1.0::Folder, and the same logic as // above applies. if (!resolvedType->isInterface()) { FQName ifc = resolvedName.getTopLevelType(); for (const auto &importedAST : mImportedASTs) { FQName matchingName; Type *match = importedAST->findDefinedType(ifc, &matchingName); if (match != nullptr && match->isInterface()) { resolvedType = match; } } } if (!resolvedType->isInterface()) { // Non-interface types are declared in the associated types header. FQName typesName = resolvedName.getTypesForPackage(); mImportedNames.insert(typesName); } else { // Do _not_ use fqName, i.e. the name we used to look up the type, // but instead use the name of the interface we found. // This is necessary because if fqName pointed to a typedef which // in turn referenced the found interface we'd mistakenly use the // name of the typedef instead of the proper name of the interface. mImportedNames.insert( static_cast(resolvedType)->fqName()); } } return returnedType; } Type *AST::findDefinedType(const FQName &fqName, FQName *matchingName) const { for (const auto &pair : mDefinedTypesByFullName) { const FQName &key = pair.first; Type* type = pair.second; if (key.endsWith(fqName)) { *matchingName = key; return type; } } return nullptr; } void AST::getImportedPackages(std::set *importSet) const { for (const auto &fqName : mImportedNames) { FQName packageName = fqName.getPackageAndVersion(); if (packageName == mPackage) { // We only care about external imports, not our own package. continue; } importSet->insert(packageName); } } void AST::getImportedPackagesHierarchy(std::set *importSet) const { getImportedPackages(importSet); std::set newSet; for (const auto &ast : mImportedASTs) { if (importSet->find(ast->package()) != importSet->end()) { ast->getImportedPackagesHierarchy(&newSet); } } importSet->insert(newSet.begin(), newSet.end()); } void AST::getAllImportedNames(std::set *allImportNames) const { for (const auto& name : mImportedNames) { allImportNames->insert(name); AST *ast = mCoordinator->parse(name, nullptr /* imported */, false /* enforce */); ast->getAllImportedNames(allImportNames); } } bool AST::isJavaCompatible() const { std::string ifaceName; if (!AST::isInterface(&ifaceName)) { for (const auto *type : mRootScope->getSubTypes()) { if (!type->isJavaCompatible()) { return false; } } return true; } const Interface *iface = mRootScope->getInterface(); return iface->isJavaCompatible(); } void AST::appendToExportedTypesVector( std::vector *exportedTypes) const { mRootScope->appendToExportedTypesVector(exportedTypes); } bool AST::isIBase() const { Interface *iface = mRootScope->getInterface(); return iface != nullptr && iface->isIBase(); } const Interface *AST::getInterface() const { return mRootScope->getInterface(); } } // namespace android;