Introduce integer constants
We can now declare a "const int" variable in an AIDL interface, in
addition to methods. These constants will become static members of the
interface/base class in the generated code.
Change-Id: I6b690ecbbe2acae37abb106510e42283f0753f26
Test: Unit and integration tests updated and pass
Bug: 23600061
Signed-off-by: Casey Dahlin <sadmac@google.com>
diff --git a/aidl.cpp b/aidl.cpp
index 6cfdee3..ffb9e14 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -441,7 +441,7 @@
lineno, package);
types->AddParcelableType(doc, filename);
} else if (decl == "interface") {
- auto temp = new std::vector<std::unique_ptr<AidlMethod>>();
+ auto temp = new std::vector<std::unique_ptr<AidlMember>>();
AidlInterface doc(class_name, lineno, "", false, temp, package);
types->AddBinderType(doc, filename);
} else {
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 02eb27d..ed05860 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -87,6 +87,10 @@
return ret;
}
+AidlConstant::AidlConstant(std::string name, int32_t value)
+ : name_(name),
+ value_(value) {}
+
AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
std::vector<std::unique_ptr<AidlArgument>>* args,
unsigned line, const std::string& comments, int id)
@@ -143,15 +147,28 @@
AidlInterface::AidlInterface(const std::string& name, unsigned line,
const std::string& comments, bool oneway,
- std::vector<std::unique_ptr<AidlMethod>>* methods,
+ std::vector<std::unique_ptr<AidlMember>>* members,
const std::vector<std::string>& package)
: name_(name),
comments_(comments),
line_(line),
oneway_(oneway),
- methods_(std::move(*methods)),
package_(package) {
- delete methods;
+ for (auto& member : *members) {
+ AidlMember* local = member.release();
+ AidlMethod* method = local->AsMethod();
+ AidlConstant* constant = local->AsConstant();
+
+ if (method) {
+ methods_.emplace_back(method);
+ } else if (constant) {
+ constants_.emplace_back(constant);
+ } else {
+ LOG(FATAL) << "Member is neither method nor constant!";
+ }
+ }
+
+ delete members;
}
std::string AidlInterface::GetPackage() const {
diff --git a/aidl_language.h b/aidl_language.h
index beaea83..4dcb5ff 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -87,7 +87,38 @@
DISALLOW_COPY_AND_ASSIGN(AidlArgument);
};
-class AidlMethod {
+class AidlMethod;
+class AidlConstant;
+class AidlMember : public AidlNode {
+ public:
+ AidlMember() = default;
+ virtual ~AidlMember() = default;
+
+ virtual AidlMethod* AsMethod() { return nullptr; }
+ virtual AidlConstant* AsConstant() { return nullptr; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AidlMember);
+};
+
+class AidlConstant : public AidlMember {
+ public:
+ AidlConstant(std::string name, int32_t value);
+ virtual ~AidlConstant() = default;
+
+ const std::string& GetName() const { return name_; }
+ int GetValue() const { return value_; }
+
+ AidlConstant* AsConstant() override { return this; }
+
+ private:
+ std::string name_;
+ int32_t value_;
+
+ DISALLOW_COPY_AND_ASSIGN(AidlConstant);
+};
+
+class AidlMethod : public AidlMember {
public:
AidlMethod(bool oneway, AidlType* type, std::string name,
std::vector<std::unique_ptr<AidlArgument>>* args,
@@ -97,6 +128,8 @@
unsigned line, const std::string& comments, int id);
virtual ~AidlMethod() = default;
+ AidlMethod* AsMethod() override { return this; }
+
const std::string& GetComments() const { return comments_; }
const AidlType& GetType() const { return *type_; }
bool IsOneway() const { return oneway_; }
@@ -205,7 +238,7 @@
public:
AidlInterface(const std::string& name, unsigned line,
const std::string& comments, bool oneway_,
- std::vector<std::unique_ptr<AidlMethod>>* methods,
+ std::vector<std::unique_ptr<AidlMember>>* members,
const std::vector<std::string>& package);
virtual ~AidlInterface() = default;
@@ -215,6 +248,8 @@
bool IsOneway() const { return oneway_; }
const std::vector<std::unique_ptr<AidlMethod>>& GetMethods() const
{ return methods_; }
+ const std::vector<std::unique_ptr<AidlConstant>>& GetConstants() const
+ { return constants_; }
std::string GetPackage() const;
std::string GetCanonicalName() const;
const std::vector<std::string>& GetSplitPackage() const { return package_; }
@@ -225,6 +260,7 @@
unsigned line_;
bool oneway_;
std::vector<std::unique_ptr<AidlMethod>> methods_;
+ std::vector<std::unique_ptr<AidlConstant>> constants_;
std::vector<std::string> package_;
DISALLOW_COPY_AND_ASSIGN(AidlInterface);
diff --git a/aidl_language_l.l b/aidl_language_l.l
index 78d4cc2..1bd587b 100644
--- a/aidl_language_l.l
+++ b/aidl_language_l.l
@@ -18,7 +18,7 @@
identifier [_a-zA-Z][_a-zA-Z0-9]*
whitespace ([ \t\r]+)
-idvalue (0|[1-9][0-9]*)
+intvalue (0|[1-9][0-9]*)
%%
%{
@@ -66,10 +66,12 @@
parcelable { return yy::parser::token::PARCELABLE; }
import { return yy::parser::token::IMPORT; }
package { return yy::parser::token::PACKAGE; }
+int { return yy::parser::token::INT; }
in { return yy::parser::token::IN; }
out { return yy::parser::token::OUT; }
inout { return yy::parser::token::INOUT; }
from { return yy::parser::token::FROM; }
+const { return yy::parser::token::CONST; }
interface { yylval->token = new AidlToken("interface", extra_text);
return yy::parser::token::INTERFACE;
@@ -82,8 +84,8 @@
{identifier} { yylval->token = new AidlToken(yytext, extra_text);
return yy::parser::token::IDENTIFIER;
}
-{idvalue} { yylval->integer = std::stoi(yytext);
- return yy::parser::token::IDVALUE; }
+{intvalue} { yylval->integer = std::stoi(yytext);
+ return yy::parser::token::INTVALUE; }
/* syntax error! */
. { printf("UNKNOWN(%s)", yytext);
diff --git a/aidl_language_y.y b/aidl_language_y.y
index 789edab..993f75b 100644
--- a/aidl_language_y.y
+++ b/aidl_language_y.y
@@ -26,7 +26,8 @@
AidlArgument::Direction direction;
std::vector<std::unique_ptr<AidlArgument>>* arg_list;
AidlMethod* method;
- std::vector<std::unique_ptr<AidlMethod>>* methods;
+ AidlConstant* constant;
+ std::vector<std::unique_ptr<AidlMember>>* members;
AidlQualifiedName* qname;
AidlInterface* interface_obj;
AidlParcelable* parcelable;
@@ -34,16 +35,17 @@
}
%token<token> IDENTIFIER INTERFACE ONEWAY C_STR
-%token<integer> IDVALUE
+%token<integer> INTVALUE
%token '(' ')' ',' '=' '[' ']' '<' '>' '.' '{' '}' ';'
-%token IN OUT INOUT PACKAGE IMPORT PARCELABLE FROM
+%token IN OUT INOUT PACKAGE IMPORT PARCELABLE FROM CONST INT
%type<parcelable_list> parcelable_decls
%type<parcelable> parcelable_decl
-%type<methods> methods
+%type<members> members
%type<interface_obj> interface_decl
%type<method> method_decl
+%type<constant> constant_decl
%type<type> type
%type<arg_list> arg_list
%type<arg> arg
@@ -68,7 +70,9 @@
: IDENTIFIER
{ $$ = $1; }
| FROM
- { $$ = new AidlToken("from", ""); };
+ { $$ = new AidlToken("from", ""); }
+ | INT
+ { $$ = new AidlToken("int", ""); };
package
: {}
@@ -126,20 +130,20 @@
};
interface_decl
- : INTERFACE identifier '{' methods '}' {
+ : INTERFACE identifier '{' members '}' {
$$ = new AidlInterface($2->GetText(), @2.begin.line, $1->GetComments(),
false, $4, ps->Package());
delete $1;
delete $2;
}
- | ONEWAY INTERFACE identifier '{' methods '}' {
+ | ONEWAY INTERFACE identifier '{' members '}' {
$$ = new AidlInterface($3->GetText(), @3.begin.line, $1->GetComments(),
true, $5, ps->Package());
delete $1;
delete $2;
delete $3;
}
- | INTERFACE error '{' methods '}' {
+ | INTERFACE error '{' members '}' {
fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected type name, saw \"%s\"\n",
ps->FileName().c_str(), @2.begin.line, $2->GetText().c_str());
$$ = NULL;
@@ -154,18 +158,25 @@
delete $2;
};
-methods
+members
:
- { $$ = new std::vector<std::unique_ptr<AidlMethod>>(); }
- | methods method_decl
- { $1->push_back(std::unique_ptr<AidlMethod>($2)); }
- | methods error ';' {
+ { $$ = new std::vector<std::unique_ptr<AidlMember>>(); }
+ | members method_decl
+ { $1->push_back(std::unique_ptr<AidlMember>($2)); }
+ | members constant_decl
+ { $1->push_back(std::unique_ptr<AidlMember>($2)); }
+ | members error ';' {
fprintf(stderr, "%s:%d: syntax error before ';' "
- "(expected method declaration)\n",
+ "(expected method or constant declaration)\n",
ps->FileName().c_str(), @3.begin.line);
$$ = $1;
};
+constant_decl
+ : CONST INT identifier '=' INTVALUE ';' {
+ $$ = new AidlConstant($3->GetText(), $5);
+ };
+
method_decl
: type identifier '(' arg_list ')' ';' {
$$ = new AidlMethod(false, $1, $2->GetText(), $4, @2.begin.line,
@@ -178,12 +189,12 @@
delete $1;
delete $3;
}
- | type identifier '(' arg_list ')' '=' IDVALUE ';' {
+ | type identifier '(' arg_list ')' '=' INTVALUE ';' {
$$ = new AidlMethod(false, $1, $2->GetText(), $4, @2.begin.line,
$1->GetComments(), $7);
delete $2;
}
- | ONEWAY type identifier '(' arg_list ')' '=' IDVALUE ';' {
+ | ONEWAY type identifier '(' arg_list ')' '=' INTVALUE ';' {
$$ = new AidlMethod(true, $2, $3->GetText(), $5, @3.begin.line,
$1->GetComments(), $8);
delete $1;
diff --git a/ast_cpp.cpp b/ast_cpp.cpp
index f67addb..b5eb69c 100644
--- a/ast_cpp.cpp
+++ b/ast_cpp.cpp
@@ -72,7 +72,15 @@
private_members_.push_back(std::move(member));
}
-Enum::EnumField::EnumField(const string& k, const string&v)
+ConstDecl::ConstDecl(const std::string& name, int value)
+ : name_(name),
+ value_(value) {}
+
+void ConstDecl::Write(CodeWriter* to) const {
+ to->Write("static constexpr int32_t %s = %d;\n", name_.c_str(), value_);
+}
+
+Enum::EnumField::EnumField(const string& k, const string& v)
: key(k),
value(v) {}
diff --git a/ast_cpp.h b/ast_cpp.h
index 1aacf9e..0d7bfc6 100644
--- a/ast_cpp.h
+++ b/ast_cpp.h
@@ -73,6 +73,20 @@
DISALLOW_COPY_AND_ASSIGN(ClassDecl);
}; // class ClassDecl
+class ConstDecl : public Declaration {
+ public:
+ ConstDecl(const std::string& name, int value);
+ virtual ~ConstDecl() = default;
+
+ void Write(CodeWriter* to) const override;
+
+ private:
+ std::string name_;
+ int value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConstDecl);
+}; // class ConstDecl
+
class Enum : public Declaration {
public:
explicit Enum(const std::string& name);
diff --git a/ast_java.cpp b/ast_java.cpp
index 6689111..c347d30 100644
--- a/ast_java.cpp
+++ b/ast_java.cpp
@@ -578,6 +578,13 @@
}
void
+Constant::Write(CodeWriter* to) const
+{
+ WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
+ to->Write("int %s = %d;\n", name.c_str(), value);
+}
+
+void
Class::Write(CodeWriter* to) const
{
size_t N, i;
diff --git a/ast_java.h b/ast_java.h
index 267faba..f852e88 100644
--- a/ast_java.h
+++ b/ast_java.h
@@ -356,6 +356,17 @@
void Write(CodeWriter* to) const override;
};
+struct Constant : public ClassElement
+{
+ string name;
+ int value;
+
+ Constant() = default;
+ virtual ~Constant() = default;
+
+ void Write(CodeWriter* to) const override;
+};
+
struct Class : public ClassElement
{
enum {
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index 9307c28..001ea44 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -697,6 +697,12 @@
"DECLARE_META_INTERFACE",
ArgList{vector<string>{ClassName(interface, ClassNames::BASE)}}}});
+ for (const auto& constant : interface.GetConstants()) {
+ unique_ptr<ConstDecl> declaration{
+ new ConstDecl(constant->GetName(), constant->GetValue())};
+ if_class->AddPublic(std::move(declaration));
+ }
+
unique_ptr<Enum> call_enum{new Enum{"Call"}};
for (const auto& method : interface.GetMethods()) {
// Each method gets an enum entry and pure virtual declaration.
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index 8949e22..0138150 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -43,6 +43,7 @@
R"(package android.os;
import foo.IFooType;
interface IComplexTypeInterface {
+ const int MY_CONSTANT = 3;
int[] Send(in int[] goes_in, inout double[] goes_in_and_out, out boolean[] goes_out);
oneway void Piff(int times);
IFooType TakesABinder(IFooType f);
@@ -606,6 +607,7 @@
class IComplexTypeInterface : public ::android::IInterface {
public:
DECLARE_META_INTERFACE(ComplexTypeInterface);
+static constexpr int32_t MY_CONSTANT = 3;
virtual ::android::binder::Status Send(const ::std::vector<int32_t>& goes_in, ::std::vector<double>* goes_in_and_out, ::std::vector<bool>* goes_out, ::std::vector<int32_t>* _aidl_return) = 0;
virtual ::android::binder::Status Piff(int32_t times) = 0;
virtual ::android::binder::Status TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) = 0;
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index b28d843..daff480 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -262,6 +262,16 @@
static void
+generate_constant(const AidlConstant& constant, Class* interface)
+{
+ Constant* decl = new Constant;
+ decl->name = constant.GetName();
+ decl->value = constant.GetValue();
+
+ interface->elements.push_back(decl);
+}
+
+static void
generate_method(const AidlMethod& method, Class* interface,
StubClass* stubClass, ProxyClass* proxyClass, int index,
JavaTypeNamespace* types)
@@ -543,12 +553,15 @@
// stub and proxy support for getInterfaceDescriptor()
generate_interface_descriptors(stub, proxy, types);
+ // all the declared constants of the interface
+ for (const auto& item : iface->GetConstants()) {
+ generate_constant(*item, interface);
+ }
+
// all the declared methods of the interface
- int index = 0;
for (const auto& item : iface->GetMethods()) {
generate_method(*item, interface, stub, proxy,
item->GetId(), types);
- index++;
}
return interface;
diff --git a/tests/aidl_test_client.cpp b/tests/aidl_test_client.cpp
index 976dc37..5ef3437 100644
--- a/tests/aidl_test_client.cpp
+++ b/tests/aidl_test_client.cpp
@@ -91,7 +91,8 @@
!RepeatPrimitive(s, &ITestService::RepeatInt, int32_t{1 << 30}) ||
!RepeatPrimitive(s, &ITestService::RepeatLong, int64_t{1ll << 60}) ||
!RepeatPrimitive(s, &ITestService::RepeatFloat, float{1.0f/3.0f}) ||
- !RepeatPrimitive(s, &ITestService::RepeatDouble, double{1.0/3.0})) {
+ !RepeatPrimitive(s, &ITestService::RepeatDouble, double{1.0/3.0}) ||
+ !RepeatPrimitive(s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT)) {
return false;
}
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index 3d750d7..db80a87 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -20,6 +20,9 @@
import android.aidl.tests.SimpleParcelable;
interface ITestService {
+ // Test that constants are accessible
+ const int TEST_CONSTANT = 42;
+
// Test that primitives work as parameters and return types.
boolean RepeatBoolean(boolean token);
byte RepeatByte(byte token);
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index e5b1947..42a60a9 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -144,6 +144,14 @@
}
}
{
+ int query = ITestService.TEST_CONSTANT;
+ int response = service.RepeatInt(query);
+ if (query != response) {
+ mLog.logAndThrow("Repeat with " + query +
+ " responded " + response);
+ }
+ }
+ {
long query = 1 << 60;
long response = service.RepeatLong(query);
if (query != response) {
diff --git a/tests/test_data_example_interface.cpp b/tests/test_data_example_interface.cpp
index 3fb299c..eea5e8e 100644
--- a/tests/test_data_example_interface.cpp
+++ b/tests/test_data_example_interface.cpp
@@ -45,6 +45,7 @@
import android.test.IAuxInterface2;
interface IExampleInterface {
+ const int EXAMPLE_CONSTANT = 3;
boolean isEnabled();
int getState();
String getAddress();
@@ -431,6 +432,7 @@
static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
}
+public static final int EXAMPLE_CONSTANT = 3;
public boolean isEnabled() throws android.os.RemoteException;
public int getState() throws android.os.RemoteException;
public java.lang.String getAddress() throws android.os.RemoteException;