Allow duplicate types from preprocessed
When compiling for SDK stub sources, we need to load documents which are
also a part of preprocessed framework.aidl, which results in inevitable
type duplication.
We allow duplicate types only if one of them is from preprocessed
document.
Bug: 192211616
Test: aidl_unittests
Change-Id: I21fc66d7305df824d2cc84308b84b9c9e9213d13
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 83dfe74..7ea1bb8 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -906,7 +906,7 @@
AidlDefinedType::AidlDefinedType(const AidlLocation& location, const std::string& name,
const Comments& comments, const std::string& package,
std::vector<std::unique_ptr<AidlMember>>* members)
- : AidlAnnotatable(location, comments), name_(name), package_(package) {
+ : AidlAnnotatable(location, comments), AidlScope(this), name_(name), package_(package) {
// adjust name/package when name is fully qualified (for preprocessed files)
if (package_.empty() && name_.find('.') != std::string::npos) {
// Note that this logic is absolutely wrong. Given a parcelable
@@ -1030,6 +1030,25 @@
return GetEnclosingScope()->ResolveName(name);
}
+template <typename T>
+const T* AidlCast(const AidlNode& node) {
+ struct CastVisitor : AidlVisitor {
+ const T* cast = nullptr;
+ void Visit(const T& t) override { cast = &t; }
+ } visitor;
+ node.DispatchVisit(visitor);
+ return visitor.cast;
+}
+
+const AidlDocument& AidlDefinedType::GetDocument() const {
+ // TODO(b/182508839): resolve with nested types when we support nested types
+ auto scope = GetEnclosingScope();
+ AIDL_FATAL_IF(!scope, this) << "no scope defined.";
+ auto doc = AidlCast<AidlDocument>(scope->GetNode());
+ AIDL_FATAL_IF(!doc, this) << "scope is not a document.";
+ return *doc;
+}
+
AidlParcelable::AidlParcelable(const AidlLocation& location, const std::string& name,
const std::string& package, const Comments& comments,
const std::string& cpp_header, std::vector<std::string>* type_params,
@@ -1524,10 +1543,13 @@
AidlDocument::AidlDocument(const AidlLocation& location, const Comments& comments,
std::vector<std::unique_ptr<AidlImport>> imports,
- std::vector<std::unique_ptr<AidlDefinedType>> defined_types)
+ std::vector<std::unique_ptr<AidlDefinedType>> defined_types,
+ bool is_preprocessed)
: AidlCommentable(location, comments),
+ AidlScope(this),
imports_(std::move(imports)),
- defined_types_(std::move(defined_types)) {
+ defined_types_(std::move(defined_types)),
+ is_preprocessed_(is_preprocessed) {
for (const auto& t : defined_types_) {
t->SetEnclosingScope(this);
}
diff --git a/aidl_language.h b/aidl_language.h
index 4f19261..2dc1d91 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -123,6 +123,7 @@
class AidlScope {
public:
+ AidlScope(const AidlNode* self) : self_(self) {}
virtual ~AidlScope() = default;
virtual std::string ResolveName(const std::string& name) const = 0;
void SetEnclosingScope(const AidlScope* enclosing) {
@@ -130,8 +131,10 @@
enclosing_ = enclosing;
}
const AidlScope* GetEnclosingScope() const { return enclosing_; }
+ const AidlNode& GetNode() const { return *self_; }
private:
+ const AidlNode* self_;
const AidlScope* enclosing_ = nullptr;
};
@@ -928,6 +931,7 @@
if (package_.empty()) return std::vector<std::string>();
return android::base::Split(package_, ".");
}
+ const AidlDocument& GetDocument() const;
virtual std::string GetPreprocessDeclarationName() const = 0;
@@ -1222,7 +1226,7 @@
public:
AidlDocument(const AidlLocation& location, const Comments& comments,
std::vector<std::unique_ptr<AidlImport>> imports,
- std::vector<std::unique_ptr<AidlDefinedType>> defined_types);
+ std::vector<std::unique_ptr<AidlDefinedType>> defined_types, bool is_preprocessed);
~AidlDocument() = default;
// non-copyable, non-movable
@@ -1236,6 +1240,7 @@
const std::vector<std::unique_ptr<AidlDefinedType>>& DefinedTypes() const {
return defined_types_;
}
+ bool IsPreprocessed() const { return is_preprocessed_; }
void TraverseChildren(std::function<void(const AidlNode&)> traverse) const override {
for (const auto& i : Imports()) {
@@ -1250,6 +1255,7 @@
private:
const std::vector<std::unique_ptr<AidlImport>> imports_;
const std::vector<std::unique_ptr<AidlDefinedType>> defined_types_;
+ bool is_preprocessed_;
};
template <typename T>
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index 7dc1f94..aa82c4d 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -192,7 +192,7 @@
} else if (!$2->empty()) {
comments = $2->front()->GetComments();
}
- ps->SetDocument(std::make_unique<AidlDocument>(loc(@1), comments, std::move(*$2), std::move(*$3)));
+ ps->MakeDocument(loc(@1), comments, std::move(*$2), std::move(*$3));
delete $1;
delete $2;
delete $3;
diff --git a/aidl_typenames.cpp b/aidl_typenames.cpp
index 6c8c9a5..90a8393 100644
--- a/aidl_typenames.cpp
+++ b/aidl_typenames.cpp
@@ -117,53 +117,53 @@
return false;
}
-bool AidlTypenames::AddDocument(std::unique_ptr<AidlDocument> doc, bool is_preprocessed) {
+// Add a parsed document and populate type names in it.
+// Name conflict is an error unless one of them is from preprocessed.
+// For legacy, we populate unqualified names from preprocessed unstructured parcelable types
+// so that they can be referenced via a simple name.
+bool AidlTypenames::AddDocument(std::unique_ptr<AidlDocument> doc) {
+ bool is_preprocessed = doc->IsPreprocessed();
for (const auto& type : doc->DefinedTypes()) {
- // ParcelFileDescriptor is treated as a built-in type, but it's also in the framework.aidl.
- // So aidl should ignore built-in types in framework.aidl to prevent duplication.
- // (b/130899491)
- if (is_preprocessed && IsBuiltinTypename(type->GetName())) {
- continue;
+ if (IsBuiltinTypename(type->GetName())) {
+ // ParcelFileDescriptor is treated as a built-in type, but it's also in the framework.aidl.
+ // So aidl should ignore built-in types in framework.aidl to prevent duplication.
+ // (b/130899491)
+ if (is_preprocessed) {
+ continue;
+ }
+ // HasValidNameComponents handles name conflicts with built-in types
}
if (auto prev_definition = defined_types_.find(type->GetCanonicalName());
prev_definition != defined_types_.end()) {
- AIDL_ERROR(type) << "redefinition:" << type->GetCanonicalName() << " is defined "
- << prev_definition->second->GetLocation();
- return false;
+ // Skip duplicate type in preprocessed document
+ if (is_preprocessed) {
+ continue;
+ }
+ // Overwrite duplicate type which is already added via preprocessed with a new one
+ if (!prev_definition->second->GetDocument().IsPreprocessed()) {
+ AIDL_ERROR(type) << "redefinition: " << type->GetCanonicalName() << " is defined "
+ << prev_definition->second->GetLocation();
+ return false;
+ }
}
+
if (!HasValidNameComponents(*type)) {
return false;
}
+
+ // populate global 'type' namespace with fully-qualified names
+ defined_types_.emplace(type->GetCanonicalName(), type.get());
+ // preprocessed unstructured parcelable types can be referenced without qualification
+ if (is_preprocessed && type->AsUnstructuredParcelable()) {
+ defined_types_.emplace(type->GetName(), type.get());
+ }
}
// transfer ownership of document
documents_.push_back(std::move(doc));
- // populate global 'type' namespace with fully-qualified names
- for (const auto& type : documents_.back()->DefinedTypes()) {
- defined_types_.emplace(type->GetCanonicalName(), type.get());
- }
- if (is_preprocessed) {
- // preprocessed unstructured parcelable types can be referenced without qualification
- for (const auto& type : documents_.back()->DefinedTypes()) {
- if (type->AsUnstructuredParcelable()) {
- defined_types_.emplace(type->GetName(), type.get());
- }
- }
- }
return true;
}
-const AidlDocument* AidlTypenames::GetDocumentFor(const AidlDefinedType* type) const {
- for (const auto& doc : AllDocuments()) {
- for (const auto& defined_type : doc->DefinedTypes()) {
- if (defined_type.get() == type) {
- return doc.get();
- }
- }
- }
- return nullptr;
-}
-
const AidlDocument& AidlTypenames::MainDocument() const {
AIDL_FATAL_IF(documents_.size() == 0, AIDL_LOCATION_HERE) << "Main document doesn't exist";
return *(documents_[0]);
diff --git a/aidl_typenames.h b/aidl_typenames.h
index d33acb9..8956075 100644
--- a/aidl_typenames.h
+++ b/aidl_typenames.h
@@ -57,8 +57,7 @@
class AidlTypenames final {
public:
AidlTypenames() = default;
- bool AddDocument(std::unique_ptr<AidlDocument> doc, bool is_preprocessed);
- const AidlDocument* GetDocumentFor(const AidlDefinedType* type) const;
+ bool AddDocument(std::unique_ptr<AidlDocument> doc);
const std::vector<std::unique_ptr<AidlDocument>>& AllDocuments() const { return documents_; }
const AidlDocument& MainDocument() const;
static bool IsBuiltinTypename(const string& type_name);
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 27bf194..5e887e2 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -819,6 +819,58 @@
EXPECT_THAT(code, testing::HasSubstr("public static final int y = 43;"));
}
+TEST_F(AidlTest, AllowMultipleUnstructuredNestedParcelablesInASingleDocument) {
+ io_delegate_.SetFileContents("p/IFoo.aidl",
+ "package p;\n"
+ "import x.Outer;\n"
+ "interface IFoo {\n"
+ " void foo(in Outer.Inner1 in1, in Outer.Inner2 in2);\n"
+ "}");
+ io_delegate_.SetFileContents("imported/x/Outer.aidl",
+ "package x;\n"
+ "parcelable Outer.Inner1;\n"
+ "parcelable Outer.Inner2;\n");
+ auto opt = Options::From("aidl -Iimported --lang=java p/IFoo.aidl");
+ CaptureStderr();
+ EXPECT_EQ(0, ::android::aidl::compile_aidl(opt, io_delegate_));
+ EXPECT_EQ("", GetCapturedStderr());
+}
+
+TEST_F(AidlTest,
+ StubsSourceIsGeneratedFromDuplicateDefinitionWithFrameworkAidl_FrameworkAidlLater) {
+ // Main doc(Foo.aidl) is loaded
+ // And then framework.aidl is loaded as preprocessed. (conflict)
+ io_delegate_.SetFileContents("sdk/framework.aidl", "parcelable x.Foo.Inner;\n");
+ io_delegate_.SetFileContents("x/Foo.aidl",
+ "package x;\n"
+ "parcelable Foo.Inner;\n");
+ auto opt = Options::From("aidl -psdk/framework.aidl -I. x/Foo.aidl");
+ CaptureStderr();
+ EXPECT_EQ(0, ::android::aidl::compile_aidl(opt, io_delegate_));
+ EXPECT_EQ("", GetCapturedStderr());
+}
+
+TEST_F(AidlTest,
+ StubsSourceIsGeneratedFromDuplicateDefinitionWithFrameworkAidl_FrameworkAidlFirst) {
+ // Main doc(IBar.aidl) is loaded first.
+ // Framework.aidl is loaded as preprocessed.
+ // And then import(Foo.aidl) is loaded. (conflict)
+ io_delegate_.SetFileContents("sdk/framework.aidl", "parcelable x.Foo.Inner;\n");
+ io_delegate_.SetFileContents("x/IBar.aidl",
+ "package x;\n"
+ "import x.Foo;\n"
+ "interface IBar {\n"
+ " void bar(in Foo.Inner inner);\n"
+ "}");
+ io_delegate_.SetFileContents("x/Foo.aidl",
+ "package x;\n"
+ "parcelable Foo.Inner;\n");
+ auto opt = Options::From("aidl -psdk/framework.aidl -I. x/IBar.aidl");
+ CaptureStderr();
+ EXPECT_EQ(0, ::android::aidl::compile_aidl(opt, io_delegate_));
+ EXPECT_EQ("", GetCapturedStderr());
+}
+
TEST_F(AidlTest, PreprocessedFileCantDeclarePackage) {
string simple_content = "package xxx; parcelable a.Foo;";
io_delegate_.SetFileContents("path", simple_content);
diff --git a/parser.cpp b/parser.cpp
index d2fe362..8d73799 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -54,7 +54,7 @@
// transfer ownership to AidlTypenames and return the raw pointer
const AidlDocument* result = parser.document_.get();
- if (!typenames.AddDocument(std::move(parser.document_), is_preprocessed)) {
+ if (!typenames.AddDocument(std::move(parser.document_))) {
return nullptr;
}
return result;
@@ -192,3 +192,11 @@
yy_delete_buffer(buffer_, scanner_);
yylex_destroy(scanner_);
}
+
+void Parser::MakeDocument(const AidlLocation& location, const Comments& comments,
+ std::vector<std::unique_ptr<AidlImport>> imports,
+ std::vector<std::unique_ptr<AidlDefinedType>> defined_types) {
+ AIDL_FATAL_IF(document_.get(), location);
+ document_ = std::make_unique<AidlDocument>(location, comments, std::move(imports),
+ std::move(defined_types), is_preprocessed_);
+}
\ No newline at end of file
diff --git a/parser.h b/parser.h
index f286de2..20599cc 100644
--- a/parser.h
+++ b/parser.h
@@ -91,7 +91,9 @@
void SetPackage(const AidlPackage& package);
const std::string& Package() const { return package_; }
- void SetDocument(std::unique_ptr<AidlDocument> document) { document_ = std::move(document); }
+ void MakeDocument(const AidlLocation& location, const Comments& comments,
+ std::vector<std::unique_ptr<AidlImport>> imports,
+ std::vector<std::unique_ptr<AidlDefinedType>> defined_types);
private:
explicit Parser(const std::string& filename, std::string& raw_buffer, bool is_preprocessed);