migrate @JavaDebug to @JavaDerive(toString=true)
This will make it easier to add a new sythetic methods in the future.
Bug: 171271915
Test: aidl_unittests / aidl_integration_test
Merged-In: I043c1320821c1821faede60fa8608ff7cc79bd6c
Change-Id: I043c1320821c1821faede60fa8608ff7cc79bd6c
(cherry picked from commit 9034500d0796fd0ba4ab6598af3e477a642451c4)
diff --git a/aidl_checkapi.cpp b/aidl_checkapi.cpp
index cf9f59b..b2a884c 100644
--- a/aidl_checkapi.cpp
+++ b/aidl_checkapi.cpp
@@ -48,7 +48,7 @@
// - a new implementation might start accepting null values (add @nullable)
static const set<std::string> kIgnoreAnnotations{
"nullable",
- "JavaDebug",
+ "JavaDerive",
};
set<AidlAnnotation> annotations;
for (const AidlAnnotation& annotation : node.GetAnnotations()) {
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 0887a25..be1221d 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -131,7 +131,7 @@
static const string kJavaStableParcelable("JavaOnlyStableParcelable");
static const string kHide("Hide");
static const string kBacking("Backing");
-static const string kJavaDebug("JavaDebug");
+static const string kJavaDerive("JavaDerive");
static const std::map<string, std::map<std::string, std::string>> kAnnotationParameters{
{kNullable, {}},
@@ -146,7 +146,7 @@
{kJavaStableParcelable, {}},
{kHide, {}},
{kBacking, {{"type", "String"}}},
- {kJavaDebug, {}}};
+ {kJavaDerive, {{"toString", "boolean"}}}};
AidlAnnotation* AidlAnnotation::Parse(
const AidlLocation& location, const string& name,
@@ -310,8 +310,8 @@
return HasAnnotation(annotations_, kHide);
}
-bool AidlAnnotatable::IsJavaDebug() const {
- return GetAnnotation(annotations_, kJavaDebug);
+const AidlAnnotation* AidlAnnotatable::JavaDerive() const {
+ return GetAnnotation(annotations_, kJavaDerive);
}
void AidlAnnotatable::DumpAnnotations(CodeWriter* writer) const {
diff --git a/aidl_language.h b/aidl_language.h
index c2d6a1e..920970f 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -244,7 +244,7 @@
bool IsVintfStability() const;
bool IsStableApiParcelable(Options::Language lang) const;
bool IsHide() const;
- bool IsJavaDebug() const;
+ const AidlAnnotation* JavaDerive() const;
void DumpAnnotations(CodeWriter* writer) const;
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index a675628..fea3419 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -398,9 +398,9 @@
EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, typenames_, Options::Language::JAVA));
}
-TEST_F(AidlTest, ParsesJavaDebugAnnotation) {
+TEST_F(AidlTest, ParsesJavaDeriveAnnotation) {
io_delegate_.SetFileContents("a/IFoo.aidl", R"(package a;
- @JavaDebug parcelable IFoo { int a; float b; })");
+ @JavaDerive(toString=true) parcelable IFoo { int a; float b; })");
Options java_options = Options::From("aidl --lang=java -o out a/IFoo.aidl");
EXPECT_EQ(0, ::android::aidl::compile_aidl(java_options, io_delegate_));
diff --git a/code_writer.h b/code_writer.h
index d890d52..08516bf 100644
--- a/code_writer.h
+++ b/code_writer.h
@@ -39,6 +39,14 @@
// The buffer gets updated only after Close() is called or the CodeWriter
// is deleted -- much like a real file.
static CodeWriterPtr ForString(std::string* buf);
+ // Run a Code Generater (which accepts CodeWriter& as a first parameter)
+ // and return a result as a string.
+ template <typename... Args>
+ static std::string RunWith(void (*gen)(CodeWriter&, Args...), Args&&... args) {
+ std::string code;
+ (*gen)(*ForString(&code), std::forward<Args>(args)...);
+ return code;
+ }
// Write a formatted string to this writer in the usual printf sense.
// Returns false on error.
virtual bool Write(const char* format, ...) __attribute__((format(printf, 2, 3)));
diff --git a/generate_java.cpp b/generate_java.cpp
index 1065a55..f120ac5 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -33,6 +33,49 @@
using ::android::aidl::java::Variable;
using std::string;
+namespace {
+using android::aidl::java::CodeGeneratorContext;
+using android::aidl::java::ConstantValueDecorator;
+
+void GenerateToString(CodeWriter& out, const AidlStructuredParcelable& parcel,
+ const AidlTypenames& typenames) {
+ out << "@Override\n";
+ out << "public String toString() {\n";
+ out.Indent();
+ out << "java.util.StringJoiner _aidl_sj = new java.util.StringJoiner(";
+ out << "\", \", \"{\", \"}\");\n";
+ for (const auto& field : parcel.GetFields()) {
+ CodeGeneratorContext ctx{
+ .writer = out,
+ .typenames = typenames,
+ .type = field->GetType(),
+ .var = field->GetName(),
+ };
+ out << "_aidl_sj.add(\"" << field->GetName() << ": \" + (";
+ ToStringFor(ctx);
+ out << "));\n";
+ }
+ out << "return \"" << parcel.GetCanonicalName() << "\" + _aidl_sj.toString() ;\n";
+ out.Dedent();
+ out << "}\n";
+}
+
+template <typename ParcelableType>
+void GenerateDerivedMethods(CodeWriter& out, const ParcelableType& parcel,
+ const AidlTypenames& typenames) {
+ if (auto java_derive = parcel.JavaDerive(); java_derive) {
+ auto synthetic_methods = java_derive->AnnotationParams(ConstantValueDecorator);
+ for (const auto& [method_name, generate] : synthetic_methods) {
+ if (generate == "true") {
+ if (method_name == "toString") {
+ GenerateToString(out, parcel, typenames);
+ }
+ }
+ }
+ }
+}
+} // namespace
+
namespace android {
namespace aidl {
namespace java {
@@ -227,31 +270,8 @@
parcel_class->elements.push_back(read_method);
- if (parcel->IsJavaDebug()) {
- out.str("");
- out << "@Override\n";
- out << "public String toString() {\n";
- out << " java.util.StringJoiner _aidl_sj = new java.util.StringJoiner(";
- out << "\", \", \"{\", \"}\");\n";
- for (const auto& field : parcel->GetFields()) {
- std::string code;
- CodeWriterPtr writer = CodeWriter::ForString(&code);
- CodeGeneratorContext context{
- .writer = *(writer.get()),
- .typenames = typenames,
- .type = field->GetType(),
- .parcel = parcel_variable->name,
- .var = field->GetName(),
- .is_classloader_created = &is_classloader_created,
- };
- ToStringFor(context);
- writer->Close();
- out << " _aidl_sj.add(\"" << field->GetName() << ": \" + (" << code << "));\n";
- }
- out << " return \"" << parcel->GetCanonicalName() << "\" + _aidl_sj.toString() ;\n";
- out << "}\n";
- parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str()));
- }
+ auto method = CodeWriter::RunWith(GenerateDerivedMethods, *parcel, typenames);
+ parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(method));
auto describe_contents_method = std::make_shared<Method>();
describe_contents_method->modifiers = PUBLIC | OVERRIDE;
diff --git a/tests/android/aidl/tests/GenericStructuredParcelable.aidl b/tests/android/aidl/tests/GenericStructuredParcelable.aidl
new file mode 100644
index 0000000..af93692
--- /dev/null
+++ b/tests/android/aidl/tests/GenericStructuredParcelable.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.aidl.tests;
+
+@JavaDerive(toString=true)
+parcelable GenericStructuredParcelable<T, U, B> {
+ int a;
+ int b;
+}
diff --git a/tests/android/aidl/tests/OtherParcelableForToString.aidl b/tests/android/aidl/tests/OtherParcelableForToString.aidl
index 8bff893..f042ab5 100644
--- a/tests/android/aidl/tests/OtherParcelableForToString.aidl
+++ b/tests/android/aidl/tests/OtherParcelableForToString.aidl
@@ -16,7 +16,7 @@
package android.aidl.tests;
-@JavaDebug
+@JavaDerive(toString=true)
parcelable OtherParcelableForToString {
String field;
}
diff --git a/tests/android/aidl/tests/ParcelableForToString.aidl b/tests/android/aidl/tests/ParcelableForToString.aidl
index cdb8051..2ad414c 100644
--- a/tests/android/aidl/tests/ParcelableForToString.aidl
+++ b/tests/android/aidl/tests/ParcelableForToString.aidl
@@ -19,7 +19,7 @@
import android.aidl.tests.OtherParcelableForToString;
import android.aidl.tests.IntEnum;
-@JavaDebug
+@JavaDerive(toString=true)
parcelable ParcelableForToString {
int intValue;
int[] intArray;
diff --git a/tests/android/aidl/tests/StructuredParcelable.aidl b/tests/android/aidl/tests/StructuredParcelable.aidl
index 50a748f..5e316ee 100644
--- a/tests/android/aidl/tests/StructuredParcelable.aidl
+++ b/tests/android/aidl/tests/StructuredParcelable.aidl
@@ -21,7 +21,7 @@
import android.aidl.tests.LongEnum;
import android.aidl.tests.ConstantExpressionEnum;
-@JavaDebug
+@JavaDerive(toString=true)
parcelable StructuredParcelable {
int[] shouldContainThreeFs;
int f;