/* * Copyright (C) 2015, 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 "aidl_language.h" #include "aidl_typenames.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "aidl_language_y-module.h" #include "logging.h" #include "aidl.h" #ifdef _WIN32 int isatty(int fd) { return (fd == 0); } #endif using android::aidl::IoDelegate; using android::base::Join; using android::base::Split; using std::cerr; using std::endl; using std::pair; using std::set; using std::string; using std::unique_ptr; using std::vector; namespace { bool IsJavaKeyword(const char* str) { static const std::vector kJavaKeywords{ "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", "true", "false", "null", }; return std::find(kJavaKeywords.begin(), kJavaKeywords.end(), str) != kJavaKeywords.end(); } void AddHideComment(CodeWriter* writer) { writer->Write("/* @hide */\n"); } inline bool HasHideComment(const std::string& comment) { return std::regex_search(comment, std::regex("@hide\\b")); } } // namespace void yylex_init(void **); void yylex_destroy(void *); void yyset_in(FILE *f, void *); int yyparse(Parser*); YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *); void yy_delete_buffer(YY_BUFFER_STATE, void *); AidlToken::AidlToken(const std::string& text, const std::string& comments) : text_(text), comments_(comments) {} AidlLocation::AidlLocation(const std::string& file, Point begin, Point end) : file_(file), begin_(begin), end_(end) {} std::ostream& operator<<(std::ostream& os, const AidlLocation& l) { os << l.file_ << ":" << l.begin_.line << "." << l.begin_.column << "-"; if (l.begin_.line != l.end_.line) { os << l.end_.line << "."; } os << l.end_.column; return os; } AidlNode::AidlNode(const AidlLocation& location) : location_(location) {} std::string AidlNode::PrintLine() const { std::stringstream ss; ss << location_.file_ << ":" << location_.begin_.line; return ss.str(); } std::string AidlNode::PrintLocation() const { std::stringstream ss; ss << location_.file_ << ":" << location_.begin_.line << ":" << location_.begin_.column << ":" << location_.end_.line << ":" << location_.end_.column; return ss.str(); } AidlError::AidlError(bool fatal) : os_(std::cerr), fatal_(fatal) { sHadError = true; os_ << "ERROR: "; } bool AidlError::sHadError = false; static const string kNullable("nullable"); static const string kUtf8InCpp("utf8InCpp"); static const string kVintfStability("VintfStability"); static const string kUnsupportedAppUsage("UnsupportedAppUsage"); static const string kJavaStableParcelable("JavaOnlyStableParcelable"); static const string kHide("Hide"); static const string kBacking("Backing"); static const std::map> kAnnotationParameters{ {kNullable, {}}, {kUtf8InCpp, {}}, {kVintfStability, {}}, {kUnsupportedAppUsage, {{"expectedSignature", "String"}, {"implicitMember", "String"}, {"maxTargetSdk", "int"}, {"publicAlternatives", "String"}, {"trackingBug", "long"}}}, {kJavaStableParcelable, {}}, {kHide, {}}, {kBacking, {{"type", "String"}}}}; AidlAnnotation* AidlAnnotation::Parse( const AidlLocation& location, const string& name, std::map>* parameter_list) { if (kAnnotationParameters.find(name) == kAnnotationParameters.end()) { std::ostringstream stream; stream << "'" << name << "' is not a recognized annotation. "; stream << "It must be one of:"; for (const auto& kv : kAnnotationParameters) { stream << " " << kv.first; } stream << "."; AIDL_ERROR(location) << stream.str(); return nullptr; } if (parameter_list == nullptr) { return new AidlAnnotation(location, name); } return new AidlAnnotation(location, name, std::move(*parameter_list)); } AidlAnnotation::AidlAnnotation(const AidlLocation& location, const string& name) : AidlAnnotation(location, name, {}) {} AidlAnnotation::AidlAnnotation( const AidlLocation& location, const string& name, std::map>&& parameters) : AidlNode(location), name_(name), parameters_(std::move(parameters)) {} bool AidlAnnotation::CheckValid() const { auto supported_params_iterator = kAnnotationParameters.find(GetName()); if (supported_params_iterator == kAnnotationParameters.end()) { AIDL_ERROR(this) << GetName() << " annotation does not have any supported parameters."; return false; } const auto& supported_params = supported_params_iterator->second; for (const auto& name_and_param : parameters_) { const std::string& param_name = name_and_param.first; const std::shared_ptr& param = name_and_param.second; if (!param->CheckValid()) { AIDL_ERROR(this) << "Invalid value for parameter " << param_name << " on annotation " << GetName() << "."; return false; } auto parameter_mapping_it = supported_params.find(param_name); if (parameter_mapping_it == supported_params.end()) { std::ostringstream stream; stream << "Parameter " << param_name << " not supported "; stream << "for annotation " << GetName() << "."; stream << "It must be one of:"; for (const auto& kv : supported_params) { stream << " " << kv.first; } AIDL_ERROR(this) << stream.str(); return false; } AidlTypeSpecifier type{AIDL_LOCATION_HERE, parameter_mapping_it->second, false, nullptr, ""}; const std::string param_value = param->ValueString(type, AidlConstantValueDecorator); // Assume error on empty string. if (param_value == "") { AIDL_ERROR(this) << "Invalid value for parameter " << param_name << " on annotation " << GetName() << "."; return false; } } return true; } std::map AidlAnnotation::AnnotationParams( const ConstantValueDecorator& decorator) const { std::map raw_params; const auto& supported_params = kAnnotationParameters.at(GetName()); for (const auto& name_and_param : parameters_) { const std::string& param_name = name_and_param.first; const std::shared_ptr& param = name_and_param.second; AidlTypeSpecifier type{AIDL_LOCATION_HERE, supported_params.at(param_name), false, nullptr, ""}; if (!param->CheckValid()) { AIDL_ERROR(this) << "Invalid value for parameter " << param_name << " on annotation " << GetName() << "."; raw_params.clear(); return raw_params; } raw_params.emplace(param_name, param->ValueString(type, decorator)); } return raw_params; } std::string AidlAnnotation::ToString(const ConstantValueDecorator& decorator) const { if (parameters_.empty()) { return "@" + GetName(); } else { vector param_strings; for (const auto& [name, value] : AnnotationParams(decorator)) { param_strings.emplace_back(name + "=" + value); } return "@" + GetName() + "(" + Join(param_strings, ", ") + ")"; } } static bool HasAnnotation(const vector& annotations, const string& name) { for (const auto& a : annotations) { if (a.GetName() == name) { return true; } } return false; } static const AidlAnnotation* GetAnnotation(const vector& annotations, const string& name) { for (const auto& a : annotations) { if (a.GetName() == name) { return &a; } } return nullptr; } AidlAnnotatable::AidlAnnotatable(const AidlLocation& location) : AidlNode(location) {} bool AidlAnnotatable::IsNullable() const { return HasAnnotation(annotations_, kNullable); } bool AidlAnnotatable::IsUtf8InCpp() const { return HasAnnotation(annotations_, kUtf8InCpp); } bool AidlAnnotatable::IsVintfStability() const { return HasAnnotation(annotations_, kVintfStability); } const AidlAnnotation* AidlAnnotatable::UnsupportedAppUsage() const { return GetAnnotation(annotations_, kUnsupportedAppUsage); } const AidlTypeSpecifier* AidlAnnotatable::BackingType(const AidlTypenames& typenames) const { auto annotation = GetAnnotation(annotations_, kBacking); if (annotation != nullptr) { auto annotation_params = annotation->AnnotationParams(AidlConstantValueDecorator); if (auto it = annotation_params.find("type"); it != annotation_params.end()) { const string& type = it->second; AidlTypeSpecifier* type_specifier = new AidlTypeSpecifier(AIDL_LOCATION_HERE, // Strip the quotes off the type String. type.substr(1, type.length() - 2), false, nullptr, ""); type_specifier->Resolve(typenames); return type_specifier; } } return nullptr; } bool AidlAnnotatable::IsStableApiParcelable(Options::Language lang) const { return HasAnnotation(annotations_, kJavaStableParcelable) && lang == Options::Language::JAVA; } bool AidlAnnotatable::IsHide() const { return HasAnnotation(annotations_, kHide); } void AidlAnnotatable::DumpAnnotations(CodeWriter* writer) const { if (annotations_.empty()) return; writer->Write("%s\n", AidlAnnotatable::ToString().c_str()); } bool AidlAnnotatable::CheckValidAnnotations() const { for (const auto& annotation : GetAnnotations()) { if (!annotation.CheckValid()) { return false; } } return true; } string AidlAnnotatable::ToString() const { vector ret; for (const auto& a : annotations_) { ret.emplace_back(a.ToString(AidlConstantValueDecorator)); } std::sort(ret.begin(), ret.end()); return Join(ret, " "); } AidlTypeSpecifier::AidlTypeSpecifier(const AidlLocation& location, const string& unresolved_name, bool is_array, vector>* type_params, const string& comments) : AidlAnnotatable(location), AidlParameterizable>(type_params), unresolved_name_(unresolved_name), is_array_(is_array), comments_(comments), split_name_(Split(unresolved_name, ".")) {} AidlTypeSpecifier AidlTypeSpecifier::ArrayBase() const { AIDL_FATAL_IF(!is_array_, this); // Declaring array of generic type cannot happen, it is grammar error. AIDL_FATAL_IF(IsGeneric(), this); AidlTypeSpecifier array_base = *this; array_base.is_array_ = false; return array_base; } bool AidlTypeSpecifier::IsHidden() const { return HasHideComment(GetComments()); } string AidlTypeSpecifier::ToString() const { string ret = GetName(); if (IsGeneric()) { vector arg_names; for (const auto& ta : GetTypeParameters()) { arg_names.emplace_back(ta->ToString()); } ret += "<" + Join(arg_names, ",") + ">"; } if (IsArray()) { ret += "[]"; } return ret; } string AidlTypeSpecifier::Signature() const { string ret = ToString(); string annotations = AidlAnnotatable::ToString(); if (annotations != "") { ret = annotations + " " + ret; } return ret; } bool AidlTypeSpecifier::Resolve(const AidlTypenames& typenames) { CHECK(!IsResolved()); pair result = typenames.ResolveTypename(unresolved_name_); if (result.second) { fully_qualified_name_ = result.first; split_name_ = Split(fully_qualified_name_, "."); } return result.second; } bool AidlTypeSpecifier::CheckValid(const AidlTypenames& typenames) const { if (!CheckValidAnnotations()) { return false; } if (IsGeneric()) { const string& type_name = GetName(); auto& types = GetTypeParameters(); // TODO(b/136048684) Disallow to use primitive types only if it is List or Map. if (type_name == "List" || type_name == "Map") { if (std::any_of(types.begin(), types.end(), [](auto& type_ptr) { return AidlTypenames::IsPrimitiveTypename(type_ptr->GetName()); })) { AIDL_ERROR(this) << "A generic type cannot has any primitive type parameters."; return false; } } const auto defined_type = typenames.TryGetDefinedType(type_name); const auto parameterizable = defined_type != nullptr ? defined_type->AsParameterizable() : nullptr; const bool is_user_defined_generic_type = parameterizable != nullptr && parameterizable->IsGeneric(); const size_t num_params = GetTypeParameters().size(); if (type_name == "List") { if (num_params > 1) { AIDL_ERROR(this) << " List cannot have type parameters more than one, but got " << "'" << ToString() << "'"; return false; } } else if (type_name == "Map") { if (num_params != 0 && num_params != 2) { AIDL_ERROR(this) << "Map must have 0 or 2 type parameters, but got " << "'" << ToString() << "'"; return false; } if (num_params == 2) { const string& key_type = GetTypeParameters()[0]->GetName(); if (key_type != "String") { AIDL_ERROR(this) << "The type of key in map must be String, but it is " << "'" << key_type << "'"; return false; } } } else if (is_user_defined_generic_type) { const size_t allowed = parameterizable->GetTypeParameters().size(); if (num_params != allowed) { AIDL_ERROR(this) << type_name << " must have " << allowed << " type parameters, but got " << num_params; return false; } } else { AIDL_ERROR(this) << type_name << " is not a generic type."; return false; } } const bool is_generic_string_list = GetName() == "List" && IsGeneric() && GetTypeParameters().size() == 1 && GetTypeParameters()[0]->GetName() == "String"; if (IsUtf8InCpp() && (GetName() != "String" && !is_generic_string_list)) { AIDL_ERROR(this) << "@utf8InCpp can only be used on String, String[], and List."; return false; } if (GetName() == "void") { if (IsArray() || IsNullable() || IsUtf8InCpp()) { AIDL_ERROR(this) << "void type cannot be an array or nullable or utf8 string"; return false; } } if (IsArray()) { const auto defined_type = typenames.TryGetDefinedType(GetName()); if (defined_type != nullptr && defined_type->AsInterface() != nullptr) { AIDL_ERROR(this) << "Binder type cannot be an array"; return false; } } if (IsNullable()) { if (AidlTypenames::IsPrimitiveTypename(GetName()) && !IsArray()) { AIDL_ERROR(this) << "Primitive type cannot get nullable annotation"; return false; } const auto defined_type = typenames.TryGetDefinedType(GetName()); if (defined_type != nullptr && defined_type->AsEnumDeclaration() != nullptr && !IsArray()) { AIDL_ERROR(this) << "Enum type cannot get nullable annotation"; return false; } } return true; } std::string AidlConstantValueDecorator(const AidlTypeSpecifier& /*type*/, const std::string& raw_value) { return raw_value; } AidlVariableDeclaration::AidlVariableDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name) : AidlVariableDeclaration(location, type, name, nullptr /*default_value*/) {} AidlVariableDeclaration::AidlVariableDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name, AidlConstantValue* default_value) : AidlNode(location), type_(type), name_(name), default_value_(default_value) {} bool AidlVariableDeclaration::CheckValid(const AidlTypenames& typenames) const { bool valid = true; valid &= type_->CheckValid(typenames); if (type_->GetName() == "void") { AIDL_ERROR(this) << "Declaration " << name_ << " is void, but declarations cannot be of void type."; valid = false; } if (default_value_ == nullptr) return valid; valid &= default_value_->CheckValid(); if (!valid) return false; return !ValueString(AidlConstantValueDecorator).empty(); } string AidlVariableDeclaration::ToString() const { string ret = type_->Signature() + " " + name_; if (default_value_ != nullptr) { ret += " = " + ValueString(AidlConstantValueDecorator); } return ret; } string AidlVariableDeclaration::Signature() const { return type_->Signature() + " " + name_; } std::string AidlVariableDeclaration::ValueString(const ConstantValueDecorator& decorator) const { if (default_value_ != nullptr) { return default_value_->ValueString(GetType(), decorator); } else { return ""; } } AidlArgument::AidlArgument(const AidlLocation& location, AidlArgument::Direction direction, AidlTypeSpecifier* type, const std::string& name) : AidlVariableDeclaration(location, type, name), direction_(direction), direction_specified_(true) {} AidlArgument::AidlArgument(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name) : AidlVariableDeclaration(location, type, name), direction_(AidlArgument::IN_DIR), direction_specified_(false) {} string AidlArgument::GetDirectionSpecifier() const { string ret; if (direction_specified_) { switch(direction_) { case AidlArgument::IN_DIR: ret += "in "; break; case AidlArgument::OUT_DIR: ret += "out "; break; case AidlArgument::INOUT_DIR: ret += "inout "; break; } } return ret; } string AidlArgument::ToString() const { return GetDirectionSpecifier() + AidlVariableDeclaration::ToString(); } std::string AidlArgument::Signature() const { class AidlInterface; class AidlInterface; class AidlParcelable; class AidlStructuredParcelable; class AidlParcelable; class AidlStructuredParcelable; return GetDirectionSpecifier() + AidlVariableDeclaration::Signature(); } AidlMember::AidlMember(const AidlLocation& location) : AidlNode(location) {} AidlConstantDeclaration::AidlConstantDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name, AidlConstantValue* value) : AidlMember(location), type_(type), name_(name), value_(value) {} bool AidlConstantDeclaration::CheckValid(const AidlTypenames& typenames) const { bool valid = true; valid &= type_->CheckValid(typenames); valid &= value_->CheckValid(); if (!valid) return false; const static set kSupportedConstTypes = {"String", "int"}; if (kSupportedConstTypes.find(type_->ToString()) == kSupportedConstTypes.end()) { AIDL_ERROR(this) << "Constant of type " << type_->ToString() << " is not supported."; return false; } return true; } string AidlConstantDeclaration::ToString() const { return "const " + type_->ToString() + " " + name_ + " = " + ValueString(AidlConstantValueDecorator); } string AidlConstantDeclaration::Signature() const { return type_->Signature() + " " + name_; } AidlMethod::AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type, const std::string& name, std::vector>* args, const std::string& comments) : AidlMethod(location, oneway, type, name, args, comments, 0, true) { has_id_ = false; } AidlMethod::AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type, const std::string& name, std::vector>* args, const std::string& comments, int id, bool is_user_defined) : AidlMember(location), oneway_(oneway), comments_(comments), type_(type), name_(name), arguments_(std::move(*args)), id_(id), is_user_defined_(is_user_defined) { has_id_ = true; delete args; for (const unique_ptr& a : arguments_) { if (a->IsIn()) { in_arguments_.push_back(a.get()); } if (a->IsOut()) { out_arguments_.push_back(a.get()); } } } bool AidlMethod::IsHidden() const { return HasHideComment(GetComments()); } string AidlMethod::Signature() const { vector arg_signatures; for (const auto& arg : GetArguments()) { arg_signatures.emplace_back(arg->GetType().ToString()); } return GetName() + "(" + Join(arg_signatures, ", ") + ")"; } string AidlMethod::ToString() const { vector arg_strings; for (const auto& arg : GetArguments()) { arg_strings.emplace_back(arg->Signature()); } string ret = (IsOneway() ? "oneway " : "") + GetType().Signature() + " " + GetName() + "(" + Join(arg_strings, ", ") + ")"; if (HasId()) { ret += " = " + std::to_string(GetId()); } return ret; } AidlDefinedType::AidlDefinedType(const AidlLocation& location, const std::string& name, const std::string& comments, const std::vector& package) : AidlAnnotatable(location), name_(name), comments_(comments), package_(package) {} std::string AidlDefinedType::GetPackage() const { return Join(package_, '.'); } bool AidlDefinedType::IsHidden() const { return HasHideComment(GetComments()); } std::string AidlDefinedType::GetCanonicalName() const { if (package_.empty()) { return GetName(); } return GetPackage() + "." + GetName(); } void AidlDefinedType::DumpHeader(CodeWriter* writer) const { if (this->IsHidden()) { AddHideComment(writer); } DumpAnnotations(writer); } AidlParcelable::AidlParcelable(const AidlLocation& location, AidlQualifiedName* name, const std::vector& package, const std::string& comments, const std::string& cpp_header, std::vector* type_params) : AidlDefinedType(location, name->GetDotName(), comments, package), AidlParameterizable(type_params), name_(name), cpp_header_(cpp_header) { // Strip off quotation marks if we actually have a cpp header. if (cpp_header_.length() >= 2) { cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2); } } template AidlParameterizable::AidlParameterizable(const AidlParameterizable& other) { // Copying is not supported if it has type parameters. // It doesn't make a problem because only ArrayBase() makes a copy, // and it can be called only if a type is not generic. CHECK(!other.IsGeneric()); } template bool AidlParameterizable::CheckValid() const { return true; }; template <> bool AidlParameterizable::CheckValid() const { if (!IsGeneric()) { return true; } std::unordered_set set(GetTypeParameters().begin(), GetTypeParameters().end()); if (set.size() != GetTypeParameters().size()) { AIDL_ERROR(this->AsAidlNode()) << "Every type parameter should be unique."; return false; } return true; } bool AidlParcelable::CheckValid(const AidlTypenames&) const { static const std::set allowed{kJavaStableParcelable}; if (!CheckValidAnnotations()) { return false; } if (!AidlParameterizable::CheckValid()) { return false; } for (const auto& v : GetAnnotations()) { if (allowed.find(v.GetName()) == allowed.end()) { std::ostringstream stream; stream << "Unstructured parcelable can contain only"; for (const string& kv : allowed) { stream << " " << kv; } stream << "."; AIDL_ERROR(this) << stream.str(); return false; } } return true; } void AidlParcelable::Dump(CodeWriter* writer) const { DumpHeader(writer); writer->Write("parcelable %s ;\n", GetName().c_str()); } AidlStructuredParcelable::AidlStructuredParcelable( const AidlLocation& location, AidlQualifiedName* name, const std::vector& package, const std::string& comments, std::vector>* variables) : AidlParcelable(location, name, package, comments, "" /*cpp_header*/), variables_(std::move(*variables)) {} void AidlStructuredParcelable::Dump(CodeWriter* writer) const { DumpHeader(writer); writer->Write("parcelable %s {\n", GetName().c_str()); writer->Indent(); for (const auto& field : GetFields()) { if (field->GetType().IsHidden()) { AddHideComment(writer); } writer->Write("%s;\n", field->ToString().c_str()); } writer->Dedent(); writer->Write("}\n"); } bool AidlStructuredParcelable::CheckValid(const AidlTypenames& typenames) const { bool success = true; for (const auto& v : GetFields()) { success = success && v->CheckValid(typenames); } return success; } // TODO: we should treat every backend all the same in future. bool AidlTypeSpecifier::LanguageSpecificCheckValid(Options::Language lang) const { if (lang != Options::Language::JAVA) { if (this->GetName() == "List" && !this->IsGeneric()) { AIDL_ERROR(this) << "Currently, only the Java backend supports non-generic List."; return false; } } if (this->GetName() == "FileDescriptor" && lang == Options::Language::NDK) { AIDL_ERROR(this) << "FileDescriptor isn't supported with the NDK."; return false; } if (this->IsGeneric()) { if (this->GetName() == "List") { if (this->GetTypeParameters().size() != 1) { AIDL_ERROR(this) << "List must have only one type parameter."; return false; } if (lang == Options::Language::CPP) { auto& name = this->GetTypeParameters()[0]->GetName(); if (!(name == "String" || name == "IBinder")) { AIDL_ERROR(this) << "List in cpp supports only string and IBinder for now."; return false; } } else if (lang == Options::Language::JAVA) { const string& contained_type = this->GetTypeParameters()[0]->GetName(); if (AidlTypenames::IsBuiltinTypename(contained_type)) { if (contained_type != "String" && contained_type != "IBinder" && contained_type != "ParcelFileDescriptor") { AIDL_ERROR(this) << "List<" << contained_type << "> isn't supported in Java"; return false; } } } } } if (this->GetName() == "Map" || this->GetName() == "CharSequence") { if (lang != Options::Language::JAVA) { AIDL_ERROR(this) << "Currently, only Java backend supports " << this->GetName() << "."; return false; } } if (lang == Options::Language::JAVA) { const string name = this->GetName(); // List[], Map[], CharSequence[] are not supported. if (AidlTypenames::IsBuiltinTypename(name) && this->IsArray()) { if (name == "List" || name == "Map" || name == "CharSequence") { AIDL_ERROR(this) << "List[], Map[], CharSequence[] are not supported."; return false; } } } return true; } // TODO: we should treat every backend all the same in future. bool AidlParcelable::LanguageSpecificCheckValid(Options::Language lang) const { if (lang != Options::Language::JAVA) { const AidlParcelable* unstructured_parcelable = this->AsUnstructuredParcelable(); if (unstructured_parcelable != nullptr) { if (unstructured_parcelable->GetCppHeader().empty()) { AIDL_ERROR(unstructured_parcelable) << "Unstructured parcelable must have C++ header defined."; return false; } } } return true; } // TODO: we should treat every backend all the same in future. bool AidlStructuredParcelable::LanguageSpecificCheckValid(Options::Language lang) const { if (!AidlParcelable::LanguageSpecificCheckValid(lang)) { return false; } for (const auto& v : this->GetFields()) { if (!v->GetType().LanguageSpecificCheckValid(lang)) { return false; } } return true; } AidlEnumerator::AidlEnumerator(const AidlLocation& location, const std::string& name, AidlConstantValue* value, const std::string& comments) : AidlNode(location), name_(name), value_(value), comments_(comments) {} bool AidlEnumerator::CheckValid(const AidlTypeSpecifier& enum_backing_type) const { if (GetValue() == nullptr) { return false; } if (!GetValue()->CheckValid()) { return false; } if (GetValue()->ValueString(enum_backing_type, AidlConstantValueDecorator).empty()) { AIDL_ERROR(this) << "Enumerator type differs from enum backing type."; return false; } return true; } string AidlEnumerator::ValueString(const AidlTypeSpecifier& backing_type, const ConstantValueDecorator& decorator) const { return GetValue()->ValueString(backing_type, decorator); } AidlEnumDeclaration::AidlEnumDeclaration(const AidlLocation& location, const std::string& name, std::vector>* enumerators, const std::vector& package, const std::string& comments) : AidlDefinedType(location, name, comments, package), enumerators_(std::move(*enumerators)) {} void AidlEnumDeclaration::SetBackingType(std::unique_ptr type) { backing_type_ = std::move(type); } bool AidlEnumDeclaration::Autofill() { const AidlEnumerator* previous = nullptr; for (const auto& enumerator : enumerators_) { if (enumerator->GetValue() == nullptr) { if (previous == nullptr) { enumerator->SetValue(std::unique_ptr( AidlConstantValue::Integral(AIDL_LOCATION_HERE, "0"))); } else { auto prev_value = std::unique_ptr( AidlConstantValue::ShallowIntegralCopy(*previous->GetValue())); if (prev_value == nullptr) { return false; } enumerator->SetValue(std::make_unique( AIDL_LOCATION_HERE, std::move(prev_value), "+", std::unique_ptr( AidlConstantValue::Integral(AIDL_LOCATION_HERE, "1")))); } } previous = enumerator.get(); } return true; } bool AidlEnumDeclaration::CheckValid(const AidlTypenames&) const { if (backing_type_ == nullptr) { AIDL_ERROR(this) << "Enum declaration missing backing type."; return false; } bool success = true; for (const auto& enumerator : enumerators_) { success = success && enumerator->CheckValid(GetBackingType()); } return success; } void AidlEnumDeclaration::Dump(CodeWriter* writer) const { DumpHeader(writer); writer->Write("enum %s {\n", GetName().c_str()); writer->Indent(); for (const auto& enumerator : GetEnumerators()) { writer->Write("%s = %s,\n", enumerator->GetName().c_str(), enumerator->ValueString(GetBackingType(), AidlConstantValueDecorator).c_str()); } writer->Dedent(); writer->Write("}\n"); } // TODO: we should treat every backend all the same in future. bool AidlInterface::LanguageSpecificCheckValid(Options::Language lang) const { for (const auto& m : this->GetMethods()) { if (!m->GetType().LanguageSpecificCheckValid(lang)) { return false; } for (const auto& arg : m->GetArguments()) { if (!arg->GetType().LanguageSpecificCheckValid(lang)) { return false; } } } return true; } AidlInterface::AidlInterface(const AidlLocation& location, const std::string& name, const std::string& comments, bool oneway, std::vector>* members, const std::vector& package) : AidlDefinedType(location, name, comments, package) { for (auto& member : *members) { AidlMember* local = member.release(); AidlMethod* method = local->AsMethod(); AidlConstantDeclaration* constant = local->AsConstantDeclaration(); CHECK(method == nullptr || constant == nullptr); if (method) { method->ApplyInterfaceOneway(oneway); methods_.emplace_back(method); } else if (constant) { constants_.emplace_back(constant); } else { AIDL_FATAL(this) << "Member is neither method nor constant!"; } } delete members; } void AidlInterface::Dump(CodeWriter* writer) const { DumpHeader(writer); writer->Write("interface %s {\n", GetName().c_str()); writer->Indent(); for (const auto& method : GetMethods()) { if (method->IsHidden()) { AddHideComment(writer); } writer->Write("%s;\n", method->ToString().c_str()); } for (const auto& constdecl : GetConstantDeclarations()) { if (constdecl->GetType().IsHidden()) { AddHideComment(writer); } writer->Write("%s;\n", constdecl->ToString().c_str()); } writer->Dedent(); writer->Write("}\n"); } bool AidlInterface::CheckValid(const AidlTypenames& typenames) const { if (!CheckValidAnnotations()) { return false; } // Has to be a pointer due to deleting copy constructor. No idea why. map method_names; for (const auto& m : GetMethods()) { if (!m->GetType().CheckValid(typenames)) { return false; } if (m->IsOneway() && m->GetType().GetName() != "void") { AIDL_ERROR(m) << "oneway method '" << m->GetName() << "' cannot return a value"; return false; } set argument_names; for (const auto& arg : m->GetArguments()) { auto it = argument_names.find(arg->GetName()); if (it != argument_names.end()) { AIDL_ERROR(m) << "method '" << m->GetName() << "' has duplicate argument name '" << arg->GetName() << "'"; return false; } argument_names.insert(arg->GetName()); if (!arg->GetType().CheckValid(typenames)) { return false; } if (m->IsOneway() && arg->IsOut()) { AIDL_ERROR(m) << "oneway method '" << m->GetName() << "' cannot have out parameters"; return false; } const bool can_be_out = typenames.CanBeOutParameter(arg->GetType()); if (!arg->DirectionWasSpecified() && can_be_out) { AIDL_ERROR(arg) << "'" << arg->GetType().ToString() << "' can be an out type, so you must declare it as in, out, or inout."; return false; } if (arg->GetDirection() != AidlArgument::IN_DIR && !can_be_out) { AIDL_ERROR(arg) << "'" << arg->ToString() << "' can only be an in parameter."; return false; } // check that the name doesn't match a keyword if (IsJavaKeyword(arg->GetName().c_str())) { AIDL_ERROR(arg) << "Argument name is a Java or aidl keyword"; return false; } // Reserve a namespace for internal use if (android::base::StartsWith(arg->GetName(), "_aidl")) { AIDL_ERROR(arg) << "Argument name cannot begin with '_aidl'"; return false; } } auto it = method_names.find(m->GetName()); // prevent duplicate methods if (it == method_names.end()) { method_names[m->GetName()] = m.get(); } else { AIDL_ERROR(m) << "attempt to redefine method " << m->GetName() << ":"; AIDL_ERROR(it->second) << "previously defined here."; return false; } static set reserved_methods{"asBinder()", "getInterfaceHash()", "getInterfaceVersion()", "getTransactionName(int)"}; if (reserved_methods.find(m->Signature()) != reserved_methods.end()) { AIDL_ERROR(m) << " method " << m->Signature() << " is reserved for internal use." << endl; return false; } } bool success = true; set constant_names; for (const std::unique_ptr& constant : GetConstantDeclarations()) { if (constant_names.count(constant->GetName()) > 0) { LOG(ERROR) << "Found duplicate constant name '" << constant->GetName() << "'"; success = false; } constant_names.insert(constant->GetName()); success = success && constant->CheckValid(typenames); } return success; } AidlQualifiedName::AidlQualifiedName(const AidlLocation& location, const std::string& term, const std::string& comments) : AidlNode(location), terms_({term}), comments_(comments) { if (term.find('.') != string::npos) { terms_ = Split(term, "."); for (const auto& subterm : terms_) { if (subterm.empty()) { AIDL_FATAL(this) << "Malformed qualified identifier: '" << term << "'"; } } } } void AidlQualifiedName::AddTerm(const std::string& term) { terms_.push_back(term); } AidlImport::AidlImport(const AidlLocation& location, const std::string& needed_class) : AidlNode(location), needed_class_(needed_class) {} std::unique_ptr Parser::Parse(const std::string& filename, const android::aidl::IoDelegate& io_delegate, AidlTypenames& typenames) { // Make sure we can read the file first, before trashing previous state. unique_ptr raw_buffer = io_delegate.GetFileContents(filename); if (raw_buffer == nullptr) { AIDL_ERROR(filename) << "Error while opening file for parsing"; return nullptr; } // We're going to scan this buffer in place, and yacc demands we put two // nulls at the end. raw_buffer->append(2u, '\0'); std::unique_ptr parser(new Parser(filename, *raw_buffer, typenames)); if (yy::parser(parser.get()).parse() != 0 || parser->HasError()) return nullptr; return parser; } std::vector Parser::Package() const { if (!package_) { return {}; } return package_->GetTerms(); } void Parser::AddImport(std::unique_ptr&& import) { for (const auto& i : imports_) { if (i->GetNeededClass() == import->GetNeededClass()) { return; } } imports_.emplace_back(std::move(import)); } bool Parser::Resolve() { bool success = true; for (AidlTypeSpecifier* typespec : unresolved_typespecs_) { if (!typespec->Resolve(typenames_)) { AIDL_ERROR(typespec) << "Failed to resolve '" << typespec->GetUnresolvedName() << "'"; success = false; // don't stop to show more errors if any } } return success; } Parser::Parser(const std::string& filename, std::string& raw_buffer, android::aidl::AidlTypenames& typenames) : filename_(filename), typenames_(typenames) { yylex_init(&scanner_); buffer_ = yy_scan_buffer(&raw_buffer[0], raw_buffer.length(), scanner_); } Parser::~Parser() { yy_delete_buffer(buffer_, scanner_); yylex_destroy(scanner_); }