Add @UnsupportedAppUsage annotation
AIDL annotation @UnsupportedAppUsage is addd. When an interface, a
parcelable, a method, or a field is annotated with it, the generated
Java code will be annotated with a Java annotation
android.annotation.UnsupportedAppUsage.
This CL also fixes the problem that comments are not emitted when it is
before an annotation, i.e.,
AIDL:
/* some comment */
@annotation
parcelable IData {...}
This is happening because comments are attached to the very next token,
but annotation doesn't support it. Fixing the issue by allowing
AidlAnnotation to have comments and copying the comments from the
annotation to the type.
Bug: 113581267
Test: aidl_unittests successful
Change-Id: I0c421560c0c277ce8a57cdba3f6bdb64b149caec
diff --git a/aidl.cpp b/aidl.cpp
index c79d627..e0e4c58 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -396,14 +396,15 @@
AidlLocation location = AidlLocation(filename, point, point);
if (decl == "parcelable") {
- AidlParcelable* doc =
- new AidlParcelable(location, new AidlQualifiedName(location, class_name, ""), package);
+ AidlParcelable* doc = new AidlParcelable(
+ location, new AidlQualifiedName(location, class_name, ""), package, "" /* comments */);
types->AddParcelableType(*doc, filename);
typenames.AddPreprocessedType(unique_ptr<AidlParcelable>(doc));
} else if (decl == "structured_parcelable") {
auto temp = new std::vector<std::unique_ptr<AidlVariableDeclaration>>();
- AidlStructuredParcelable* doc = new AidlStructuredParcelable(
- location, new AidlQualifiedName(location, class_name, ""), package, temp);
+ AidlStructuredParcelable* doc =
+ new AidlStructuredParcelable(location, new AidlQualifiedName(location, class_name, ""),
+ package, "" /* comments */, temp);
types->AddParcelableType(*doc, filename);
typenames.AddPreprocessedType(unique_ptr<AidlStructuredParcelable>(doc));
} else if (decl == "interface") {
diff --git a/aidl_language.cpp b/aidl_language.cpp
index ec97053..0cc11ac 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -70,8 +70,9 @@
static const string kNullable("nullable");
static const string kUtf8InCpp("utf8InCpp");
+static const string kUnsupportedAppUsage("UnsupportedAppUsage");
-static const set<string> kAnnotationNames{kNullable, kUtf8InCpp};
+static const set<string> kAnnotationNames{kNullable, kUtf8InCpp, kUnsupportedAppUsage};
AidlAnnotation* AidlAnnotation::Parse(const AidlLocation& location, const string& name) {
if (kAnnotationNames.find(name) == kAnnotationNames.end()) {
@@ -91,7 +92,7 @@
AidlAnnotation::AidlAnnotation(const AidlLocation& location, const string& name)
: AidlNode(location), name_(name) {}
-static bool HasAnnotation(const set<AidlAnnotation>& annotations, const string& name) {
+static bool HasAnnotation(const vector<AidlAnnotation>& annotations, const string& name) {
for (const auto& a : annotations) {
if (a.GetName() == name) {
return true;
@@ -110,6 +111,10 @@
return HasAnnotation(annotations_, kUtf8InCpp);
}
+bool AidlAnnotatable::IsUnsupportedAppUsage() const {
+ return HasAnnotation(annotations_, kUnsupportedAppUsage);
+}
+
string AidlAnnotatable::ToString() const {
vector<string> ret;
for (const auto& a : annotations_) {
@@ -599,9 +604,9 @@
}
AidlParcelable::AidlParcelable(const AidlLocation& location, AidlQualifiedName* name,
- const std::vector<std::string>& package,
+ const std::vector<std::string>& package, const std::string& comments,
const std::string& cpp_header)
- : AidlDefinedType(location, name->GetDotName(), "" /*comments*/, package),
+ : AidlDefinedType(location, name->GetDotName(), comments, package),
name_(name),
cpp_header_(cpp_header) {
// Strip off quotation marks if we actually have a cpp header.
@@ -616,8 +621,8 @@
AidlStructuredParcelable::AidlStructuredParcelable(
const AidlLocation& location, AidlQualifiedName* name, const std::vector<std::string>& package,
- std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables)
- : AidlParcelable(location, name, package, "" /*cpp_header*/),
+ const std::string& comments, std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables)
+ : AidlParcelable(location, name, package, comments, "" /*cpp_header*/),
variables_(std::move(*variables)) {}
void AidlStructuredParcelable::Write(CodeWriter* writer) const {
diff --git a/aidl_language.h b/aidl_language.h
index 75f3579..7dfc597 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -131,10 +131,13 @@
const string& GetName() const { return name_; }
string ToString() const { return "@" + name_; }
+ const string& GetComments() const { return comments_; }
+ void SetComments(const string& comments) { comments_ = comments; }
private:
AidlAnnotation(const AidlLocation& location, const string& name);
const string name_;
+ string comments_;
};
static inline bool operator<(const AidlAnnotation& lhs, const AidlAnnotation& rhs) {
@@ -152,15 +155,16 @@
AidlAnnotatable(AidlAnnotatable&&) = default;
virtual ~AidlAnnotatable() = default;
- void Annotate(set<AidlAnnotation>&& annotations) { annotations_ = std::move(annotations); }
+ void Annotate(vector<AidlAnnotation>&& annotations) { annotations_ = std::move(annotations); }
bool IsNullable() const;
bool IsUtf8InCpp() const;
+ bool IsUnsupportedAppUsage() const;
std::string ToString() const;
- const set<AidlAnnotation>& GetAnnotations() const { return annotations_; }
+ const vector<AidlAnnotation>& GetAnnotations() const { return annotations_; }
private:
- set<AidlAnnotation> annotations_;
+ vector<AidlAnnotation> annotations_;
};
class AidlQualifiedName;
@@ -199,6 +203,8 @@
const string& GetComments() const { return comments_; }
+ void SetComments(const string& comment) { comments_ = comment; }
+
bool IsResolved() const { return fully_qualified_name_ != ""; }
bool IsArray() const { return is_array_; }
@@ -228,7 +234,7 @@
string fully_qualified_name_;
bool is_array_;
const shared_ptr<vector<unique_ptr<AidlTypeSpecifier>>> type_params_;
- const string comments_;
+ string comments_;
const android::aidl::ValidatableType* language_type_ = nullptr;
};
@@ -471,6 +477,7 @@
const std::string& GetName() const { return name_; };
const std::string& GetComments() const { return comments_; }
+ void SetComments(const std::string comments) { comments_ = comments; }
/* dot joined package, example: "android.package.foo" */
std::string GetPackage() const;
@@ -528,7 +535,8 @@
class AidlParcelable : public AidlDefinedType {
public:
AidlParcelable(const AidlLocation& location, AidlQualifiedName* name,
- const std::vector<std::string>& package, const std::string& cpp_header = "");
+ const std::vector<std::string>& package, const std::string& comments,
+ const std::string& cpp_header = "");
virtual ~AidlParcelable() = default;
// C++ uses "::" instead of "." to refer to a inner class.
@@ -550,7 +558,7 @@
class AidlStructuredParcelable : public AidlParcelable {
public:
AidlStructuredParcelable(const AidlLocation& location, AidlQualifiedName* name,
- const std::vector<std::string>& package,
+ const std::vector<std::string>& package, const std::string& comments,
std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables);
const std::vector<std::unique_ptr<AidlVariableDeclaration>>& GetFields() const {
diff --git a/aidl_language_l.ll b/aidl_language_l.ll
index 9ca8f16..862332c 100644
--- a/aidl_language_l.ll
+++ b/aidl_language_l.ll
@@ -67,12 +67,14 @@
\> { return '>'; }
/* annotations */
-@{identifier} { yylval->token = new AidlToken(yytext + 1, "");
+@{identifier} { yylval->token = new AidlToken(yytext + 1, extra_text);
return yy::parser::token::ANNOTATION;
}
/* keywords */
-parcelable { return yy::parser::token::PARCELABLE; }
+parcelable { yylval->token = new AidlToken("parcelable", extra_text);
+ return yy::parser::token::PARCELABLE;
+ }
import { return yy::parser::token::IMPORT; }
package { return yy::parser::token::PACKAGE; }
in { return yy::parser::token::IN; }
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index e07f905..442ffe5 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -47,7 +47,7 @@
char character;
std::string *str;
AidlAnnotation* annotation;
- std::set<AidlAnnotation>* annotation_list;
+ std::vector<AidlAnnotation>* annotation_list;
AidlTypeSpecifier* type;
AidlArgument* arg;
AidlArgument::Direction direction;
@@ -70,6 +70,7 @@
%token<token> C_STR "string literal"
%token<token> IDENTIFIER "identifier"
%token<token> INTERFACE "interface"
+%token<token> PARCELABLE "parcelable"
%token<token> ONEWAY "oneway"
%token<character> CHARVALUE "char literal"
@@ -86,7 +87,6 @@
%token INOUT "inout"
%token OUT "out"
%token PACKAGE "package"
-%token PARCELABLE "parcelable"
%token TRUE_LITERAL "true"
%token FALSE_LITERAL "false"
@@ -173,6 +173,11 @@
ps->AddError();
}
+ if ($1->size() > 0) {
+ // copy comments from annotation to decl
+ $2->SetComments($1->begin()->GetComments());
+ }
+
$$->Annotate(std::move(*$1));
delete $1;
}
@@ -187,14 +192,14 @@
parcelable_decl
: PARCELABLE qualified_name ';' {
- $$ = new AidlParcelable(loc(@2), $2, ps->Package());
+ $$ = new AidlParcelable(loc(@2), $2, ps->Package(), $1->GetComments());
}
| PARCELABLE qualified_name CPP_HEADER C_STR ';' {
- $$ = new AidlParcelable(loc(@2), $2, ps->Package(), $4->GetText());
+ $$ = new AidlParcelable(loc(@2), $2, ps->Package(), $1->GetComments(), $4->GetText());
}
| PARCELABLE identifier '{' variable_decls '}' {
AidlQualifiedName* name = new AidlQualifiedName(loc(@2), $2->GetText(), $2->GetComments());
- $$ = new AidlStructuredParcelable(loc(@2), name, ps->Package(), $4);
+ $$ = new AidlStructuredParcelable(loc(@2), name, ps->Package(), $1->GetComments(), $4);
}
| PARCELABLE error ';' {
ps->AddError();
@@ -374,6 +379,10 @@
type
: annotation_list unannotated_type {
$$ = $2;
+ if ($1->size() > 0) {
+ // copy comments from annotation to type
+ $2->SetComments($1->begin()->GetComments());
+ }
$2->Annotate(std::move(*$1));
delete $1;
};
@@ -389,11 +398,11 @@
annotation_list
:
- { $$ = new std::set<AidlAnnotation>(); }
+ { $$ = new std::vector<AidlAnnotation>(); }
| annotation_list annotation
{
if ($2 != nullptr) {
- $1->insert(std::move(*$2));
+ $1->emplace_back(std::move(*$2));
delete $2;
}
};
@@ -405,6 +414,7 @@
if ($$ == nullptr) {
ps->AddError();
}
+ $$->SetComments($1->GetComments());
};
direction
diff --git a/ast_java.cpp b/ast_java.cpp
index 7b8b36a..b69452c 100644
--- a/ast_java.cpp
+++ b/ast_java.cpp
@@ -76,6 +76,9 @@
if (this->comment.length() != 0) {
to->Write("%s\n", this->comment.c_str());
}
+ for (const auto& a : this->annotations) {
+ to->Write("%s\n", a.c_str());
+ }
WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
this->variable->WriteDeclaration(to);
@@ -392,6 +395,10 @@
to->Write("%s\n", this->comment.c_str());
}
+ for (const auto& a : this->annotations) {
+ to->Write("%s\n", a.c_str());
+ }
+
WriteModifiers(to, this->modifiers,
SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
@@ -453,6 +460,9 @@
if (this->comment.length() != 0) {
to->Write("%s\n", this->comment.c_str());
}
+ for (const auto& a : this->annotations) {
+ to->Write("%s\n", a.c_str());
+ }
WriteModifiers(to, this->modifiers, ALL_MODIFIERS);
diff --git a/ast_java.h b/ast_java.h
index a516c81..c8c4063 100644
--- a/ast_java.h
+++ b/ast_java.h
@@ -114,6 +114,7 @@
struct Field : public ClassElement {
std::string comment;
+ std::vector<std::string> annotations;
int modifiers = 0;
Variable* variable = nullptr;
std::string value;
@@ -324,6 +325,7 @@
struct Method : public ClassElement {
std::string comment;
+ std::vector<std::string> annotations;
int modifiers = 0;
const Type* returnType = nullptr; // nullptr means constructor
size_t returnTypeDimension = 0;
@@ -372,6 +374,7 @@
enum { CLASS, INTERFACE };
std::string comment;
+ std::vector<std::string> annotations;
int modifiers = 0;
int what = CLASS; // CLASS or INTERFACE
const Type* type = nullptr;
diff --git a/generate_java.cpp b/generate_java.cpp
index 4e021ee..1bf26c3 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -93,11 +93,16 @@
parcel_class->what = Class::CLASS;
parcel_class->type = parcelType;
parcel_class->interfaces.push_back(types->ParcelableInterfaceType());
+ parcel_class->annotations = generate_java_annotations(*parcel);
for (const auto& variable : parcel->GetFields()) {
const Type* type = variable->GetType().GetLanguageType<Type>();
std::ostringstream out;
+ out << variable->GetType().GetComments() << "\n";
+ for (const auto& a : generate_java_annotations(variable->GetType())) {
+ out << a << "\n";
+ }
out << "public " << type->JavaType() << (variable->GetType().IsArray() ? "[]" : "") << " "
<< variable->GetName();
if (variable->GetDefaultValue()) {
@@ -190,6 +195,14 @@
return parcel_class;
}
+std::vector<std::string> generate_java_annotations(const AidlAnnotatable& a) {
+ std::vector<std::string> result;
+ if (a.IsUnsupportedAppUsage()) {
+ result.emplace_back("@android.annotation.UnsupportedAppUsage");
+ }
+ return result;
+}
+
} // namespace java
} // namespace android
} // namespace aidl
diff --git a/generate_java.h b/generate_java.h
index efe48f3..7408ee7 100644
--- a/generate_java.h
+++ b/generate_java.h
@@ -40,6 +40,8 @@
java::JavaTypeNamespace* types,
const Options& options);
+std::vector<std::string> generate_java_annotations(const AidlAnnotatable& a);
+
} // namespace java
} // namespace android
} // namespace aidl
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index 69f2df3..198b8c1 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -411,6 +411,7 @@
decl->returnType = method.GetType().GetLanguageType<Type>();
decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
decl->name = method.GetName();
+ decl->annotations = generate_java_annotations(method.GetType());
for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
decl->parameters.push_back(
@@ -989,6 +990,7 @@
interface->what = Class::INTERFACE;
interface->type = interfaceType;
interface->interfaces.push_back(types->IInterfaceType());
+ interface->annotations = generate_java_annotations(*iface);
if (options.Version()) {
std::ostringstream code;
diff --git a/tests/test_data_example_interface.cpp b/tests/test_data_example_interface.cpp
index adb0c3f..57d267d 100644
--- a/tests/test_data_example_interface.cpp
+++ b/tests/test_data_example_interface.cpp
@@ -44,6 +44,7 @@
import android.bar.IAuxInterface;
import android.test.IAuxInterface2;
+@UnsupportedAppUsage
interface IExampleInterface {
const int EXAMPLE_CONSTANT = 3;
boolean isEnabled();
@@ -51,6 +52,7 @@
String getAddress();
/* Test long comment */
+ @UnsupportedAppUsage
ExampleParcelable[] getParcelables();
// Test short comment
@@ -119,6 +121,7 @@
* Original file: android/test/IExampleInterface.aidl
*/
package android.test;
+@android.annotation.UnsupportedAppUsage
public interface IExampleInterface extends android.os.IInterface
{
/** Default implementation for IExampleInterface. */
@@ -559,6 +562,7 @@
public int getState() throws android.os.RemoteException;
public java.lang.String getAddress() throws android.os.RemoteException;
/* Test long comment */
+ @android.annotation.UnsupportedAppUsage
public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
// Test short comment
@@ -578,6 +582,7 @@
* Original file: android/test/IExampleInterface.aidl
*/
package android.test;
+@android.annotation.UnsupportedAppUsage
public interface IExampleInterface extends android.os.IInterface
{
/** Default implementation for IExampleInterface. */
@@ -1068,6 +1073,7 @@
public int getState() throws android.os.RemoteException;
public java.lang.String getAddress() throws android.os.RemoteException;
/* Test long comment */
+ @android.annotation.UnsupportedAppUsage
public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
// Test short comment
@@ -1087,6 +1093,7 @@
* Original file: android/test/IExampleInterface.aidl
*/
package android.test;
+@android.annotation.UnsupportedAppUsage
public interface IExampleInterface extends android.os.IInterface
{
/** Default implementation for IExampleInterface. */
@@ -1607,6 +1614,7 @@
public int getState() throws android.os.RemoteException;
public java.lang.String getAddress() throws android.os.RemoteException;
/* Test long comment */
+ @android.annotation.UnsupportedAppUsage
public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
// Test short comment
diff --git a/type_cpp_unittest.cpp b/type_cpp_unittest.cpp
index d27efca..79b47a9 100644
--- a/type_cpp_unittest.cpp
+++ b/type_cpp_unittest.cpp
@@ -62,7 +62,7 @@
TEST_F(CppTypeNamespaceTest, SupportsNestedParcelableClass) {
unique_ptr<AidlParcelable> parcelable(new AidlParcelable(
AIDL_LOCATION_HERE, new AidlQualifiedName(AIDL_LOCATION_HERE, kParcelableDotName, ""),
- {"a", "goog"}));
+ {"a", "goog"}, ""));
EXPECT_EQ(parcelable->GetCppName(), kParcelableColonName);
}
diff --git a/type_java_unittest.cpp b/type_java_unittest.cpp
index 12d3f74..098a7a5 100644
--- a/type_java_unittest.cpp
+++ b/type_java_unittest.cpp
@@ -46,7 +46,7 @@
EXPECT_FALSE(types_.HasTypeByCanonicalName("Foo"));
EXPECT_FALSE(types_.HasTypeByCanonicalName("java.util.List<a.goog.Foo>"));
unique_ptr<AidlParcelable> parcelable(new AidlParcelable(
- AIDL_LOCATION_HERE, new AidlQualifiedName(AIDL_LOCATION_HERE, "Foo", ""), {"a", "goog"}));
+ AIDL_LOCATION_HERE, new AidlQualifiedName(AIDL_LOCATION_HERE, "Foo", ""), {"a", "goog"}, ""));
// Add the parcelable type we care about.
EXPECT_TRUE(types_.AddParcelableType(*parcelable.get(), __FILE__));
// Now we can find the parcelable type, but not the List of them.