Check cpp_header for C++/NDK
Unstructured parcelables should have cpp_header for compilation.
Bug: 194846019
Test: atest aidl_unittests
Change-Id: I76c56d3976272f4b401ddc9d8d54fa0e37527400
diff --git a/aidl.cpp b/aidl.cpp
index 5703d3d..38b8220 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -354,6 +354,34 @@
return validator.success;
}
+bool ValidateCppHeader(const AidlDocument& doc) {
+ struct CppHeaderVisitor : AidlVisitor {
+ bool success = true;
+ void Visit(const AidlParcelable& p) override {
+ if (p.GetCppHeader().empty()) {
+ AIDL_ERROR(p) << "Unstructured parcelable \"" << p.GetName()
+ << "\" must have C++ header defined.";
+ success = false;
+ }
+ }
+ void Visit(const AidlTypeSpecifier& m) override {
+ auto type = m.GetDefinedType();
+ if (type) {
+ auto unstructured = type->AsUnstructuredParcelable();
+ if (unstructured && unstructured->GetCppHeader().empty()) {
+ AIDL_ERROR(m) << "Unstructured parcelable \"" << m.GetUnresolvedName()
+ << "\" must have C++ header defined.";
+ success = false;
+ }
+ }
+ }
+ };
+
+ CppHeaderVisitor validator;
+ VisitTopDown(validator, doc);
+ return validator.success;
+}
+
} // namespace
namespace internals {
@@ -505,8 +533,8 @@
bool isStable = unstructured_parcelable->IsStableApiParcelable(options.TargetLanguage());
if (options.IsStructured() && !isStable) {
AIDL_ERROR(unstructured_parcelable)
- << "Cannot declared parcelable in a --structured interface. Parcelable must be defined "
- "in AIDL directly.";
+ << "Cannot declare unstructured parcelable in a --structured interface. Parcelable "
+ "must be defined in AIDL directly.";
return AidlError::NOT_STRUCTURED;
}
if (options.FailOnParcelable()) {
@@ -579,6 +607,12 @@
return AidlError::BAD_TYPE;
}
+ if ((options.TargetLanguage() == Options::Language::CPP ||
+ options.TargetLanguage() == Options::Language::NDK) &&
+ !ValidateCppHeader(*document)) {
+ return AidlError::BAD_TYPE;
+ }
+
if (!Diagnose(*document, options.GetDiagnosticMapping())) {
return AidlError::BAD_TYPE;
}
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 7ea1bb8..76277fd 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -1215,27 +1215,8 @@
}
// TODO: we should treat every backend all the same in future.
-bool AidlParcelable::LanguageSpecificCheckValid(const AidlTypenames& /*typenames*/,
+bool AidlParcelable::LanguageSpecificCheckValid(const AidlTypenames& typenames,
Options::Language lang) const {
- if (lang == Options::Language::CPP || lang == Options::Language::NDK) {
- 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(const AidlTypenames& typenames,
- Options::Language lang) const {
- if (!AidlParcelable::LanguageSpecificCheckValid(typenames, lang)) {
- return false;
- }
for (const auto& v : this->GetFields()) {
if (!v->GetType().LanguageSpecificCheckValid(typenames, lang)) {
return false;
@@ -1400,20 +1381,6 @@
}
// TODO: we should treat every backend all the same in future.
-bool AidlUnionDecl::LanguageSpecificCheckValid(const AidlTypenames& typenames,
- Options::Language lang) const {
- if (!AidlParcelable::LanguageSpecificCheckValid(typenames, lang)) {
- return false;
- }
- for (const auto& v : this->GetFields()) {
- if (!v->GetType().LanguageSpecificCheckValid(typenames, lang)) {
- return false;
- }
- }
- return true;
-}
-
-// TODO: we should treat every backend all the same in future.
bool AidlInterface::LanguageSpecificCheckValid(const AidlTypenames& typenames,
Options::Language lang) const {
for (const auto& m : this->GetMethods()) {
diff --git a/aidl_language.h b/aidl_language.h
index 2dc1d91..c4a335e 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -1057,9 +1057,6 @@
std::string GetPreprocessDeclarationName() const override { return "structured_parcelable"; }
bool CheckValid(const AidlTypenames& typenames) const override;
- bool LanguageSpecificCheckValid(const AidlTypenames& typenames,
- Options::Language lang) const override;
-
void DispatchVisit(AidlVisitor& v) const override { v.Visit(*this); }
};
@@ -1154,8 +1151,6 @@
const AidlNode& AsAidlNode() const override { return *this; }
bool CheckValid(const AidlTypenames& typenames) const override;
- bool LanguageSpecificCheckValid(const AidlTypenames& typenames,
- Options::Language lang) const override;
std::string GetPreprocessDeclarationName() const override { return "union"; }
const AidlUnionDecl* AsUnionDeclaration() const override { return this; }
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index e63df71..b2e6eb4 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -435,16 +435,14 @@
EXPECT_EQ(0, ::android::aidl::compile_aidl(java_options, io_delegate_));
EXPECT_EQ(0, ::android::aidl::compile_aidl(cpp_options, io_delegate_));
- const string expected_stderr =
- "ERROR: a/Foo.aidl:1.48-52: Cannot declared parcelable in a --structured interface. "
- "Parcelable must be defined in AIDL directly.\n";
+
CaptureStderr();
EXPECT_NE(0, ::android::aidl::compile_aidl(cpp_structured_options, io_delegate_));
- EXPECT_EQ(expected_stderr, GetCapturedStderr());
+ EXPECT_THAT(GetCapturedStderr(), HasSubstr("Cannot declare unstructured"));
CaptureStderr();
EXPECT_NE(0, ::android::aidl::compile_aidl(rust_options, io_delegate_));
- EXPECT_EQ(expected_stderr, GetCapturedStderr());
+ EXPECT_THAT(GetCapturedStderr(), HasSubstr("Cannot declare unstructured"));
}
TEST_F(AidlTest, ParcelableSupportJavaDeriveToString) {
@@ -672,6 +670,23 @@
EXPECT_EQ((Comments{{"// get bar\n"}}), interface->GetMethods()[0]->GetComments());
}
+TEST_F(AidlTest, RejectsIfCppHeaderIsMissing) {
+ io_delegate_.SetFileContents("Foo.aidl", "parcelable Foo;");
+ Options options = Options::From("aidl --lang cpp -h h -o o Foo.aidl");
+ CaptureStderr();
+ EXPECT_EQ(1, ::android::aidl::compile_aidl(options, io_delegate_));
+ EXPECT_THAT(GetCapturedStderr(), HasSubstr("must have C++ header defined"));
+}
+
+TEST_F(AidlTest, RejectsIfTypeRefsCppHeaderIsMissing) {
+ io_delegate_.SetFileContents("Foo.aidl", "parcelable Foo;");
+ io_delegate_.SetFileContents("IBar.aidl", "interface IBar { void bar(in Foo foo); }");
+ Options options = Options::From("aidl -I . --lang cpp -h h -o o IBar.aidl");
+ CaptureStderr();
+ EXPECT_EQ(1, ::android::aidl::compile_aidl(options, io_delegate_));
+ EXPECT_THAT(GetCapturedStderr(), HasSubstr("must have C++ header defined"));
+}
+
TEST_F(AidlTest, ParsesPreprocessedFile) {
string simple_content = "parcelable a.Foo;\ninterface b.IBar;";
io_delegate_.SetFileContents("path", simple_content);