Use TypeNamespace instances in aidl.cpp
Refactor much of the logic around types into an instance of
TypeNamespace. This class defines an interface to type reasoning
logic that aidl.cpp can use to register binder and parcelable types
it loads during parsing. Code generation can use a language specific
subclass of the type namespace to reason about types more specifically.
For now, leave NAMES and the global type constants intact. We'll
refactor those in a separate change if necessary.
Bug: 24303749
Test: Compiles, unittests pass
Change-Id: Ie961dcef4f10bc23932ce45c39a1b190d272ab72
diff --git a/aidl.cpp b/aidl.cpp
index 01a1399..2964fc4 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -42,6 +42,7 @@
#include "parse_helpers.h"
#include "search_path.h"
#include "type_java.h"
+#include "type_namespace.h"
#ifndef O_BINARY
# define O_BINARY 0
@@ -52,6 +53,7 @@
using std::map;
using std::set;
using std::string;
+using std::unique_ptr;
using std::vector;
namespace android {
@@ -175,79 +177,34 @@
return NULL;
}
-int gather_types(const char* filename, document_item_type* items) {
- int err = 0;
- while (items) {
- Type* type;
- if (items->item_type == USER_DATA_TYPE) {
- user_data_type* p = (user_data_type*)items;
- type = new UserDataType(p->package ? p->package : "", p->name.data,
- false, p->parcelable, filename, p->name.lineno);
- }
- else if (items->item_type == INTERFACE_TYPE_BINDER) {
- interface_type* c = (interface_type*)items;
- type = new InterfaceType(c->package ? c->package : "",
- c->name.data, false, c->oneway,
- filename, c->name.lineno);
- }
- else {
- fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
- return 1;
- }
+bool gather_types(const char* raw_filename,
+ document_item_type* items,
+ TypeNamespace* types) {
+ bool success = true;
+ if (raw_filename == nullptr)
+ raw_filename = "";
+ const std::string filename{raw_filename};
- const Type* old = NAMES.Find(type->QualifiedName());
- if (old == NULL) {
- NAMES.Add(type);
-
- if (items->item_type == INTERFACE_TYPE_BINDER) {
- // for interfaces, also add the stub and proxy types, we don't
- // bother checking these for duplicates, because the parser
- // won't let us do it.
- interface_type* c = (interface_type*)items;
-
- string name = c->name.data;
- name += ".Stub";
- Type* stub = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
- filename, c->name.lineno);
- NAMES.Add(stub);
-
- name = c->name.data;
- name += ".Stub.Proxy";
- Type* proxy = new Type(c->package ? c->package : "",
- name, Type::GENERATED, false, false,
- filename, c->name.lineno);
- NAMES.Add(proxy);
- }
- } else {
- if (old->Kind() == Type::BUILT_IN) {
- fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
- filename, type->DeclLine(),
- type->QualifiedName().c_str());
- err = 1;
- }
- else if (type->Kind() != old->Kind()) {
- fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
- filename, type->DeclLine(),
- type->QualifiedName().c_str(),
- type->HumanReadableKind().c_str());
- fprintf(stderr, "%s:%d previously defined here as %s.\n",
- old->DeclFile().c_str(), old->DeclLine(),
- old->HumanReadableKind().c_str());
- err = 1;
- }
- }
-
- items = items->next;
+ for (document_item_type* item = items; item; item = item->next) {
+ if (items->item_type == USER_DATA_TYPE) {
+ user_data_type* p = (user_data_type*)items;
+ success &= types->AddParcelableType(p, filename);
}
- return err;
+ else if (items->item_type == INTERFACE_TYPE_BINDER) {
+ interface_type* c = (interface_type*)items;
+ success &= types->AddBinderType(c, filename);
+ } else {
+ LOG(FATAL) << "internal error";
+ }
+ }
+ return success;
}
-int check_method(const char* filename, method_type* m) {
+int check_method(const char* filename, method_type* m, TypeNamespace* types) {
int err = 0;
// return type
- const Type* returnType = NAMES.Search(m->type.type.data);
+ const Type* returnType = types->Search(m->type.type.data);
if (returnType == NULL) {
fprintf(stderr, "%s:%d unknown return type %s\n", filename,
m->type.type.lineno, m->type.type.data);
@@ -280,7 +237,7 @@
arg_type* arg = m->args;
while (arg) {
- const Type* t = NAMES.Search(arg->type.type.data);
+ const Type* t = types->Search(arg->type.type.data);
// check the arg type
if (t == NULL) {
@@ -353,7 +310,9 @@
return err;
}
-int check_types(const char* filename, document_item_type* items) {
+int check_types(const char* filename,
+ document_item_type* items,
+ TypeNamespace* types) {
int err = 0;
while (items) {
// (nothing to check for USER_DATA_TYPE)
@@ -366,7 +325,7 @@
if (member->item_type == METHOD_TYPE) {
method_type* m = (method_type*)member;
- err |= check_method(filename, m);
+ err |= check_method(filename, m, types);
// prevent duplicate methods
if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -516,7 +475,7 @@
}
-int parse_preprocessed_file(const string& filename) {
+int parse_preprocessed_file(const string& filename, TypeNamespace* types) {
int err;
FILE* f = fopen(filename.c_str(), "rb");
@@ -590,7 +549,9 @@
fclose(f);
return 1;
}
- err = gather_types(filename.c_str(), doc);
+ if (!gather_types(filename.c_str(), doc, types)) {
+ err = 1;
+ }
lineno++;
}
@@ -672,17 +633,16 @@
int load_and_validate_aidl(const std::vector<std::string> preprocessed_files,
const std::vector<std::string> import_paths,
const std::string& input_file_name,
+ TypeNamespace* types,
interface_type** returned_interface,
import_info** returned_imports) {
int err = 0;
set_import_paths(import_paths);
- register_base_types();
-
// import the preprocessed file
for (const string& s : preprocessed_files) {
- err |= parse_preprocessed_file(s);
+ err |= parse_preprocessed_file(s, types);
}
if (err != 0) {
return err;
@@ -712,7 +672,7 @@
// parse the imports of the input file
for (import_info* import = p.GetImports(); import; import = import->next) {
- if (NAMES.Find(import->neededClass) != NULL) {
+ if (types->Find(import->neededClass) != NULL) {
continue;
}
import->filename = find_import_file(import->neededClass);
@@ -738,13 +698,17 @@
}
// gather the types that have been declared
- err |= gather_types(input_file_name.c_str(), parsed_doc);
+ if (!gather_types(input_file_name.c_str(), parsed_doc, types)) {
+ err |= 1;
+ }
for (import_info* import = p.GetImports(); import; import = import->next) {
- err |= gather_types(import->filename, import->doc);
+ if (!gather_types(import->filename, import->doc, types)) {
+ err |= 1;
+ }
}
// check the referenced types in parsed_doc to make sure we've imported them
- err |= check_types(input_file_name.c_str(), parsed_doc);
+ err |= check_types(input_file_name.c_str(), parsed_doc, types);
// assign method ids and validate.
@@ -767,9 +731,12 @@
int compile_aidl_to_cpp(const CppOptions& options) {
interface_type* interface = nullptr;
import_info* imports = nullptr;
+ register_base_types();
+ JavaTypeNamespace* types = &NAMES;
int err = load_and_validate_aidl(std::vector<std::string>{},
options.ImportPaths(),
options.InputFileName(),
+ types,
&interface,
&imports);
if (err != 0) {
@@ -784,9 +751,12 @@
int compile_aidl_to_java(const JavaOptions& options) {
interface_type* interface = nullptr;
import_info* imports = nullptr;
+ register_base_types();
+ JavaTypeNamespace* types = &NAMES;
int err = load_and_validate_aidl(options.preprocessed_files_,
options.import_paths_,
options.input_file_name_,
+ types,
&interface,
&imports);
if (err != 0) {
@@ -813,7 +783,7 @@
check_outputFilePath(output_file_name);
err = generate_java(output_file_name, options.input_file_name_.c_str(),
- interface);
+ interface, types);
return err;
}
diff --git a/generate_java.cpp b/generate_java.cpp
index 09a4410..116b5c4 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -64,12 +64,12 @@
// =================================================
int
generate_java(const string& filename, const string& originalSrc,
- interface_type* iface)
+ interface_type* iface, JavaTypeNamespace* types)
{
Class* cl;
if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
- cl = generate_binder_interface_class(iface);
+ cl = generate_binder_interface_class(iface, types);
}
Document* document = new Document;
diff --git a/generate_java.h b/generate_java.h
index 12d9f57..b67a88c 100644
--- a/generate_java.h
+++ b/generate_java.h
@@ -12,11 +12,13 @@
using std::string;
using std::vector;
+class JavaTypeNamespace;
+
int generate_java(const string& filename, const string& originalSrc,
- interface_type* iface);
+ interface_type* iface, JavaTypeNamespace* types);
android::aidl::Class* generate_binder_interface_class(
- const interface_type* iface);
+ const interface_type* iface, JavaTypeNamespace* types);
string gather_comments(extra_text_type* extra);
string append(const char* a, const char* b);
diff --git a/generate_java_binder.cpp b/generate_java_binder.cpp
index f44254f..3127e8b 100644
--- a/generate_java_binder.cpp
+++ b/generate_java_binder.cpp
@@ -520,7 +520,8 @@
}
Class*
-generate_binder_interface_class(const interface_type* iface)
+generate_binder_interface_class(const interface_type* iface,
+ JavaTypeNamespace* types)
{
const InterfaceType* interfaceType = static_cast<const InterfaceType*>(
NAMES.Find(iface->package, iface->name.data));
diff --git a/type_java.cpp b/type_java.cpp
index 58e8c5e..379c783 100644
--- a/type_java.cpp
+++ b/type_java.cpp
@@ -18,10 +18,12 @@
#include <sys/types.h>
+#include "aidl_language.h"
+
namespace android {
namespace aidl {
-Namespace NAMES;
+JavaTypeNamespace NAMES;
Type* VOID_TYPE;
Type* BOOLEAN_TYPE;
@@ -885,24 +887,46 @@
// ================================================================
-Namespace::Namespace() {}
+JavaTypeNamespace::JavaTypeNamespace() {}
-Namespace::~Namespace() {
+JavaTypeNamespace::~JavaTypeNamespace() {
int N = m_types.size();
for (int i = 0; i < N; i++) {
delete m_types[i];
}
}
-void Namespace::Add(const Type* type) {
- const Type* t = Find(type->QualifiedName());
- if (t == NULL) {
+bool JavaTypeNamespace::Add(const Type* type) {
+ const Type* existing = Find(type->QualifiedName());
+ if (!existing) {
m_types.push_back(type);
+ return true;
}
+
+ if (existing->Kind() == Type::BUILT_IN) {
+ fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
+ type->DeclFile().c_str(), type->DeclLine(),
+ type->QualifiedName().c_str());
+ return false;
+ }
+
+ if (type->Kind() != existing->Kind()) {
+ fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
+ type->DeclFile().c_str(), type->DeclLine(),
+ type->QualifiedName().c_str(),
+ type->HumanReadableKind().c_str());
+ fprintf(stderr, "%s:%d previously defined here as %s.\n",
+ existing->DeclFile().c_str(), existing->DeclLine(),
+ existing->HumanReadableKind().c_str());
+ return false;
+ }
+
+ return true;
}
-void Namespace::AddGenericType(const string& package, const string& name,
- int args) {
+void JavaTypeNamespace::AddGenericType(const string& package,
+ const string& name,
+ int args) {
Generic g;
g.package = package;
g.name = name;
@@ -911,7 +935,7 @@
m_generics.push_back(g);
}
-const Type* Namespace::Find(const string& name) const {
+const Type* JavaTypeNamespace::Find(const string& name) const {
int N = m_types.size();
for (int i = 0; i < N; i++) {
if (m_types[i]->QualifiedName() == name) {
@@ -921,7 +945,8 @@
return NULL;
}
-const Type* Namespace::Find(const char* package, const char* name) const {
+const Type* JavaTypeNamespace::Find(const char* package,
+ const char* name) const {
string s;
if (package != nullptr && *package != '\0') {
s += package;
@@ -943,7 +968,36 @@
return r;
}
-const Type* Namespace::Search(const string& name) {
+bool JavaTypeNamespace::AddParcelableType(user_data_type* p,
+ const std::string& filename) {
+ Type* type = new UserDataType(p->package ? p->package : "", p->name.data,
+ false, p->parcelable, filename, p->name.lineno);
+ return Add(type);
+}
+
+bool JavaTypeNamespace::AddBinderType(interface_type* b,
+ const std::string& filename) {
+ Type* type = new InterfaceType(b->package ? b->package : "",
+ b->name.data, false, b->oneway,
+ filename, b->name.lineno);
+ // for interfaces, also add the stub and proxy types
+ Type* stub = new Type(b->package ? b->package : "",
+ string{b->name.data} + ".Stub",
+ Type::GENERATED, false, false,
+ filename, b->name.lineno);
+ Type* proxy = new Type(b->package ? b->package : "",
+ string{b->name.data} + ".Stub.Proxy",
+ Type::GENERATED, false, false,
+ filename, b->name.lineno);
+
+ bool success = true;
+ success &= Add(type);
+ success &= Add(stub);
+ success &= Add(proxy);
+ return success;
+}
+
+const Type* JavaTypeNamespace::Search(const string& name) {
// an exact match wins
const Type* result = Find(name);
if (result != NULL) {
@@ -1011,7 +1065,8 @@
return this->Find(result->QualifiedName());
}
-const Namespace::Generic* Namespace::search_generic(const string& name) const {
+const JavaTypeNamespace::Generic* JavaTypeNamespace::search_generic(
+ const string& name) const {
int N = m_generics.size();
// first exact match
@@ -1033,7 +1088,7 @@
return NULL;
}
-void Namespace::Dump() const {
+void JavaTypeNamespace::Dump() const {
int n = m_types.size();
for (int i = 0; i < n; i++) {
const Type* t = m_types[i];
diff --git a/type_java.h b/type_java.h
index 4006158..97d9823 100644
--- a/type_java.h
+++ b/type_java.h
@@ -21,6 +21,7 @@
#include <vector>
#include "ast_java.h"
+#include "type_namespace.h"
namespace android {
namespace aidl {
@@ -390,22 +391,24 @@
string m_creator;
};
-class Namespace {
+class JavaTypeNamespace : public TypeNamespace {
public:
- Namespace();
- ~Namespace();
- void Add(const Type* type);
+ JavaTypeNamespace();
+ virtual ~JavaTypeNamespace();
+
+ bool AddParcelableType(user_data_type* p, const string& filename) override;
+ bool AddBinderType(interface_type* b, const string& filename) override;
+ const Type* Search(const string& name) override;
+ const Type* Find(const string& name) const override;
+
+ bool Add(const Type* type);
// args is the number of template types (what is this called?)
void AddGenericType(const string& package, const string& name, int args);
- // lookup a specific class name
- const Type* Find(const string& name) const;
+ // helper alias for Find(name);
const Type* Find(const char* package, const char* name) const;
- // try to search by either a full name or a partial name
- const Type* Search(const string& name);
-
void Dump() const;
private:
@@ -420,9 +423,11 @@
vector<const Type*> m_types;
vector<Generic> m_generics;
+
+ DISALLOW_COPY_AND_ASSIGN(JavaTypeNamespace);
};
-extern Namespace NAMES;
+extern JavaTypeNamespace NAMES;
extern Type* VOID_TYPE;
extern Type* BOOLEAN_TYPE;
diff --git a/type_namespace.h b/type_namespace.h
new file mode 100644
index 0000000..0ab690a
--- /dev/null
+++ b/type_namespace.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015, 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.
+ */
+
+#ifndef AIDL_TYPE_NAMESPACE_H_
+#define AIDL_TYPE_NAMESPACE_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+
+struct user_data_type;
+struct interface_type;
+
+namespace android {
+namespace aidl {
+
+class TypeNamespace {
+ public:
+ // Load this TypeNamespace with user defined types.
+ virtual bool AddParcelableType(user_data_type* p,
+ const std::string& filename) = 0;
+ virtual bool AddBinderType(interface_type* b,
+ const std::string& filename) = 0;
+
+ // Search for a type by inexact match with |name|.
+ virtual const Type* Search(const std::string& name) = 0;
+ // Search for a type by exact match with |name|.
+ virtual const Type* Find(const string& name) const = 0;
+
+ protected:
+ TypeNamespace() = default;
+ virtual ~TypeNamespace() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
+};
+
+} // namespace aidl
+} // namespace android
+
+#endif // AIDL_TYPE_NAMESPACE_H_