List<T> supported types
Added a parameterized test to reflect the current status:
This revealed some weird cases like "List<IBinder>" is not supported
in the NDK backends.
Note that added checks in aidl_language.cpp are to avoid crashes. We
need to fix if the current status is not what we intended.
Bug: 174779997
Bug: 171932530
Test: aidl_unittests
Change-Id: Id5fa4c55b9c36206b25d6408d16ddfc224704f95
diff --git a/aidl.cpp b/aidl.cpp
index 0f894c2..344649d 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -522,6 +522,7 @@
return true;
};
const bool is_check_api = options.GetTask() == Options::Task::CHECK_API;
+ const bool is_dump_api = options.GetTask() == Options::Task::DUMP_API;
// Resolve the unresolved type references found from the input file
if (!is_check_api && !main_parser->Resolve(resolver)) {
@@ -592,8 +593,10 @@
}
}
- if (!defined_type->LanguageSpecificCheckValid(*typenames, options.TargetLanguage())) {
- valid_type = false;
+ if (!is_dump_api && !is_check_api) {
+ if (!defined_type->LanguageSpecificCheckValid(*typenames, options.TargetLanguage())) {
+ valid_type = false;
+ }
}
if (!valid_type) {
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 4ab9fad..ad6aa8b 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -522,8 +522,9 @@
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());
+ if (std::any_of(types.begin(), types.end(), [&](auto& type_ptr) {
+ return (typenames.GetEnumDeclaration(*type_ptr)) ||
+ AidlTypenames::IsPrimitiveTypename(type_ptr->GetName());
})) {
AIDL_ERROR(this) << "A generic type cannot have any primitive type parameters.";
return false;
@@ -1069,23 +1070,41 @@
}
if (this->IsGeneric()) {
if (this->GetName() == "List") {
+ const AidlTypeSpecifier& contained_type = *GetTypeParameters()[0];
+ const string& contained_type_name = contained_type.GetName();
if (lang == Options::Language::CPP) {
- const string& contained_type = this->GetTypeParameters()[0]->GetName();
- if (!(contained_type == "String" || contained_type == "IBinder")) {
- AIDL_ERROR(this) << "List<" << contained_type
+ if (!(contained_type_name == "String" || contained_type_name == "IBinder")) {
+ AIDL_ERROR(this) << "List<" << contained_type_name
<< "> is not supported. List in cpp supports only String and IBinder.";
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
+ if (AidlTypenames::IsBuiltinTypename(contained_type_name)) {
+ if (contained_type_name != "String" && contained_type_name != "IBinder" &&
+ contained_type_name != "ParcelFileDescriptor") {
+ AIDL_ERROR(this) << "List<" << contained_type_name
<< "> is not supported. List in Java supports only String, IBinder, "
"and ParcelFileDescriptor.";
return false;
}
+ } else { // Defined types
+ if (typenames.GetInterface(contained_type)) {
+ AIDL_ERROR(this) << "List<" << contained_type_name
+ << "> is not supported. List in Java supports only String, IBinder, "
+ "and ParcelFileDescriptor.";
+ return false;
+ }
+ }
+ } else if (lang == Options::Language::NDK) {
+ if (typenames.GetInterface(contained_type)) {
+ AIDL_ERROR(this) << "List<" << contained_type_name
+ << "> is not supported. List in NDK doesn't support interface.";
+ return false;
+ }
+ if (contained_type_name == "IBinder") {
+ AIDL_ERROR(this) << "List<" << contained_type_name
+ << "> is not supported. List in NDK doesn't support IBinder.";
+ return false;
}
}
}
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index c4651c8..4d6ee2e 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -16,6 +16,7 @@
#include "aidl.h"
+#include <android-base/format.h>
#include <android-base/stringprintf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -4274,5 +4275,103 @@
EXPECT_NE(nullptr, Parse("IFoo.aidl", contents, typenames_, GetLanguage()));
}
+struct ListTypeParam {
+ string kind;
+ string literal;
+};
+
+const ListTypeParam kListTypeParams[] = {
+ {"primitive", "int"}, {"String", "String"},
+ {"IBinder", "IBinder"}, {"ParcelFileDescriptor", "ParcelFileDescriptor"},
+ {"parcelable", "Foo"}, {"enum", "a.Enum"},
+ {"union", "a.Union"}, {"interface", "a.IBar"},
+};
+
+const std::map<std::string, std::string> kListSupportExpectations = {
+ {"cpp_primitive", "A generic type cannot have any primitive type parameters."},
+ {"java_primitive", "A generic type cannot have any primitive type parameters."},
+ {"ndk_primitive", "A generic type cannot have any primitive type parameters."},
+ {"rust_primitive", "A generic type cannot have any primitive type parameters."},
+ {"cpp_String", ""},
+ {"java_String", ""},
+ {"ndk_String", ""},
+ {"rust_String", ""},
+ {"cpp_IBinder", ""},
+ {"java_IBinder", ""},
+ {"ndk_IBinder", "List<IBinder> is not supported. List in NDK doesn't support IBinder."},
+ {"rust_IBinder", ""},
+ {"cpp_ParcelFileDescriptor", "List<ParcelFileDescriptor> is not supported."},
+ {"java_ParcelFileDescriptor", ""},
+ {"ndk_ParcelFileDescriptor", ""},
+ {"rust_ParcelFileDescriptor", ""},
+ {"cpp_interface",
+ "List<a.IBar> is not supported. List in cpp supports only String and IBinder."},
+ {"java_interface",
+ "List<a.IBar> is not supported. List in Java supports only String, IBinder, and "
+ "ParcelFileDescriptor."},
+ {"ndk_interface", "List<a.IBar> is not supported. List in NDK doesn't support interface."},
+ {"rust_interface", ""},
+ {"cpp_parcelable",
+ "List<a.Foo> is not supported. List in cpp supports only String and IBinder."},
+ {"java_parcelable", ""},
+ {"ndk_parcelable", ""},
+ {"rust_parcelable", ""},
+ {"cpp_enum", "A generic type cannot have any primitive type parameters."},
+ {"java_enum", "A generic type cannot have any primitive type parameters."},
+ {"ndk_enum", "A generic type cannot have any primitive type parameters."},
+ {"rust_enum", "A generic type cannot have any primitive type parameters."},
+ {"cpp_union", "List<a.Union> is not supported. List in cpp supports only String and IBinder."},
+ {"java_union", ""},
+ {"ndk_union", ""},
+ {"rust_union", ""},
+};
+
+using AidlListTestParam = std::tuple<Options::Language, ListTypeParam>;
+
+class AidlListTest : public testing::TestWithParam<AidlListTestParam> {
+ public:
+ void SetUp() override {
+ const auto& param = GetParam();
+ const auto& lang = Options::LanguageToString(std::get<0>(param));
+ const auto& kind = std::get<1>(param).kind;
+
+ FakeIoDelegate io;
+ io.SetFileContents("a/IBar.aidl", "package a; interface IBar { }");
+ io.SetFileContents("a/Enum.aidl", "package a; enum Enum { A }");
+ io.SetFileContents("a/Union.aidl", "package a; union Union { int a; }");
+ io.SetFileContents("a/Foo.aidl", fmt::format(R"(
+ package a;
+ parcelable Foo {{
+ List<{}> list;
+ }})",
+ std::get<1>(param).literal));
+
+ const auto options =
+ Options::From(fmt::format("aidl -I . --lang={} a/Foo.aidl -o out -h out", lang));
+ CaptureStderr();
+ compile_aidl(options, io);
+ auto it = kListSupportExpectations.find(lang + "_" + kind);
+ EXPECT_TRUE(it != kListSupportExpectations.end());
+ const string err = GetCapturedStderr();
+ if (it->second.empty()) {
+ EXPECT_EQ("", err);
+ } else {
+ EXPECT_THAT(err, testing::HasSubstr(it->second));
+ }
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ AidlTestSuite, AidlListTest,
+ testing::Combine(testing::Values(Options::Language::CPP, Options::Language::JAVA,
+ Options::Language::NDK, Options::Language::RUST),
+ testing::ValuesIn(kListTypeParams)),
+ [](const testing::TestParamInfo<AidlListTestParam>& info) {
+ return Options::LanguageToString(std::get<0>(info.param)) + "_" +
+ std::get<1>(info.param).kind;
+ });
+
+TEST_P(AidlListTest, SupportedTypes) {}
+
} // namespace aidl
} // namespace android