warning: import should introduce unique simple name

Importing two different types with the same simple name is not allowed.

- collision with other imports

  import q.Bar;
  import r.Bar; // error

- collision with top-level type decl's name

  import q.Bar; // error
  parcelable Bar { .. }

Bug: 190782365
Test: aidl_unittests
Test: m
Change-Id: I13c0bde3f710d8230c61c1f0bb9680ea32f980eb
diff --git a/aidl_language.h b/aidl_language.h
index deb530a..77c8d0a 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -1193,6 +1193,7 @@
   AidlImport& operator=(AidlImport&&) = delete;
 
   const std::string& GetNeededClass() const { return needed_class_; }
+  std::string SimpleName() const { return needed_class_.substr(needed_class_.rfind('.') + 1); }
   void TraverseChildren(std::function<void(const AidlNode&)>) const {}
   void DispatchVisit(AidlVisitor& v) const { v.Visit(*this); }
 
diff --git a/diagnostics.cpp b/diagnostics.cpp
index 694e96a..ce30db5 100644
--- a/diagnostics.cpp
+++ b/diagnostics.cpp
@@ -248,6 +248,34 @@
   }
 };
 
+struct DiagnoseImports : DiagnosticsVisitor {
+  DiagnoseImports(DiagnosticsContext& diag) : DiagnosticsVisitor(diag) {}
+  void Visit(const AidlDocument& doc) override {
+    auto collide_with_decls = [&](const auto& import) {
+      for (const auto& type : doc.DefinedTypes()) {
+        if (type->GetCanonicalName() != import->GetNeededClass() &&
+            type->GetName() == import->SimpleName()) {
+          return true;
+        }
+      }
+      return false;
+    };
+
+    std::set<std::string> imported_names;
+    for (const auto& import : doc.Imports()) {
+      if (collide_with_decls(import)) {
+        diag.Report(import->GetLocation(), DiagnosticID::unique_import)
+            << import->SimpleName() << " is already defined in this file.";
+      }
+      auto [_, inserted] = imported_names.insert(import->SimpleName());
+      if (!inserted) {
+        diag.Report(import->GetLocation(), DiagnosticID::unique_import)
+            << import->SimpleName() << " is already imported.";
+      }
+    }
+  }
+};
+
 bool Diagnose(const AidlDocument& doc, const DiagnosticMapping& mapping) {
   DiagnosticsContext diag(mapping);
 
@@ -259,6 +287,7 @@
   DiagnoseOutArray{diag}.Check(doc);
   DiagnoseFileDescriptor{diag}.Check(doc);
   DiagnoseOutNullable{diag}.Check(doc);
+  DiagnoseImports{diag}.Check(doc);
 
   return diag.ErrorCount() == 0;
 }
diff --git a/diagnostics.inc b/diagnostics.inc
index 59ea7c8..c7dd4e5 100644
--- a/diagnostics.inc
+++ b/diagnostics.inc
@@ -7,4 +7,5 @@
 DIAG(mixed_oneway, "mixed-oneway", false)
 DIAG(out_array, "out-array", false)
 DIAG(out_nullable, "out-nullable", false)
+DIAG(unique_import, "unique-import", false)
 DIAG(unknown_warning, "unknown-warning", false)
diff --git a/diagnostics_unittest.cpp b/diagnostics_unittest.cpp
index 0ea3141..eed824c 100644
--- a/diagnostics_unittest.cpp
+++ b/diagnostics_unittest.cpp
@@ -178,3 +178,41 @@
                "}"},
               {"Bar.aidl", "parcelable Bar {}"}});
 }
+
+TEST_F(DiagnosticsTest, RejectImportsCollisionWithTopLevelDecl) {
+  expect_diagnostics = {DiagnosticID::unique_import};
+  ParseFiles({{"p/IFoo.aidl",
+               "package p;\n"
+               "import q.IFoo;\n"  // should collide with previous import
+               "interface IFoo{}"},
+              {"q/IFoo.aidl", "package q; interface IFoo{}"}});
+}
+
+TEST_F(DiagnosticsTest, RejectImportsCollision) {
+  expect_diagnostics = {DiagnosticID::unique_import};
+  ParseFiles({{"p/IFoo.aidl",
+               "package p;\n"
+               "import q.IBar;\n"
+               "import r.IBar;\n"  // should collide with previous import
+               "interface IFoo{}"},
+              {"q/IBar.aidl", "package q; interface IBar{}"},
+              {"r/IBar.aidl", "package r; interface IBar{}"}});
+}
+
+TEST_F(DiagnosticsTest, AllowImportingSelf) {
+  expect_diagnostics = {};
+  ParseFiles({{"p/IFoo.aidl",
+               "package p;\n"
+               "import p.IFoo;\n"
+               "interface IFoo{}"}});
+}
+
+TEST_F(DiagnosticsTest, AllowRedundantImports) {
+  expect_diagnostics = {};
+  ParseFiles({{"p/IFoo.aidl",
+               "package p;\n"
+               "import q.IBar;\n"
+               "import q.IBar;\n"  // ugly, but okay
+               "interface IFoo{}"},
+              {"q/IBar.aidl", "package q; interface IBar{}"}});
+}
\ No newline at end of file