[fidlc] Allow type aliases anywhere in file

... after library imports of course.

FIDL-582 #comment

Change-Id: I1a75dcc54c46de170c016e3c898bcd65fd136c75
diff --git a/zircon/system/host/fidl/lib/parser.cpp b/zircon/system/host/fidl/lib/parser.cpp
index 66f8d17..c7eacde 100644
--- a/zircon/system/host/fidl/lib/parser.cpp
+++ b/zircon/system/host/fidl/lib/parser.cpp
@@ -1067,6 +1067,7 @@
 
 std::unique_ptr<raw::File> Parser::ParseFile() {
     ASTScope scope(this);
+    bool done_with_library_imports = false;
     std::vector<std::unique_ptr<raw::Using>> using_list;
     std::vector<std::unique_ptr<raw::BitsDeclaration>> bits_declaration_list;
     std::vector<std::unique_ptr<raw::ConstDeclaration>> const_declaration_list;
@@ -1090,27 +1091,9 @@
     if (!Ok())
         return Fail();
 
-    auto parse_using = [&using_list, this]() {
-        switch (Peek().combined()) {
-        default:
-            return Done;
-
-        case CASE_IDENTIFIER(Token::Subkind::kUsing):
-            using_list.emplace_back(ParseUsing());
-            return More;
-        }
-    };
-
-    while (parse_using() == More) {
-        if (!Ok())
-            return Fail();
-        ConsumeToken(OfKind(Token::Kind::kSemicolon));
-        if (!Ok())
-            return Fail();
-    }
-
     auto parse_declaration = [&bits_declaration_list, &const_declaration_list, &enum_declaration_list,
                               &interface_declaration_list, &struct_declaration_list,
+                              &done_with_library_imports, &using_list,
                               &table_declaration_list, &union_declaration_list, &xunion_declaration_list, this]() {
         ASTScope scope(this);
         std::unique_ptr<raw::AttributeList> attributes = MaybeParseAttributeList();
@@ -1122,30 +1105,51 @@
             return Done;
 
         case CASE_IDENTIFIER(Token::Subkind::kBits):
+            done_with_library_imports = true;
             bits_declaration_list.emplace_back(ParseBitsDeclaration(std::move(attributes), scope));
             return More;
 
         case CASE_IDENTIFIER(Token::Subkind::kConst):
+            done_with_library_imports = true;
             const_declaration_list.emplace_back(ParseConstDeclaration(std::move(attributes), scope));
             return More;
 
         case CASE_IDENTIFIER(Token::Subkind::kEnum):
+            done_with_library_imports = true;
             enum_declaration_list.emplace_back(ParseEnumDeclaration(std::move(attributes), scope));
             return More;
 
         case CASE_IDENTIFIER(Token::Subkind::kProtocol):
+            done_with_library_imports = true;
             interface_declaration_list.emplace_back(
                 ParseProtocolDeclaration(std::move(attributes), scope));
             return More;
 
         case CASE_IDENTIFIER(Token::Subkind::kStruct):
+            done_with_library_imports = true;
             struct_declaration_list.emplace_back(ParseStructDeclaration(std::move(attributes), scope));
             return More;
 
         case CASE_IDENTIFIER(Token::Subkind::kTable):
+            done_with_library_imports = true;
             table_declaration_list.emplace_back(ParseTableDeclaration(std::move(attributes), scope));
             return More;
 
+        case CASE_IDENTIFIER(Token::Subkind::kUsing): {
+            auto using_decl = ParseUsing();
+            if (using_decl->maybe_type_ctor) {
+                done_with_library_imports = true;
+            } else if (done_with_library_imports) {
+                // TODO(FIDL-582): Give one week warning, then turn this into
+                // an error.
+                error_reporter_->ReportWarning(
+                    using_decl->location(),
+                    "library imports must be grouped at top-of-file");
+            }
+            using_list.emplace_back(std::move(using_decl));
+            return More;
+        }
+
         case CASE_IDENTIFIER(Token::Subkind::kUnion):
             union_declaration_list.emplace_back(ParseUnionDeclaration(std::move(attributes), scope));
             return More;
diff --git a/zircon/system/utest/fidl-compiler/parsing_tests.cpp b/zircon/system/utest/fidl-compiler/parsing_tests.cpp
index 7863b98..308b58f 100644
--- a/zircon/system/utest/fidl-compiler/parsing_tests.cpp
+++ b/zircon/system/utest/fidl-compiler/parsing_tests.cpp
@@ -289,6 +289,31 @@
     END_TEST;
 }
 
+bool warn_on_type_alias_before_imports() {
+    BEGIN_TEST;
+
+    SharedAmongstLibraries shared;
+    TestLibrary dependency("dependent.fidl", R"FIDL(
+library dependent;
+)FIDL", &shared);
+    ASSERT_TRUE(dependency.Compile());
+
+    TestLibrary library(R"FIDL(
+library example;
+
+using foo = int16;
+using dependent;
+)FIDL");
+    ASSERT_TRUE(library.AddDependentLibrary(std::move(dependency)));
+    ASSERT_TRUE(library.Compile());
+
+    const auto& warnings = library.warnings();
+    ASSERT_EQ(warnings.size(), 1);
+    ASSERT_STR_STR(warnings[0].data(), "library imports must be grouped at top-of-file");
+
+    END_TEST;
+}
+
 } // namespace
 
 BEGIN_TEST_CASE(parsing_tests)
@@ -301,4 +326,5 @@
 RUN_TEST(bad_identifier_test)
 RUN_TEST(invalid_character_test)
 RUN_TEST(empty_struct_test)
+RUN_TEST(warn_on_type_alias_before_imports)
 END_TEST_CASE(parsing_tests)
diff --git a/zircon/system/utest/fidl-compiler/type_alias_tests.cpp b/zircon/system/utest/fidl-compiler/type_alias_tests.cpp
index 74a1ab9..eb2281b 100644
--- a/zircon/system/utest/fidl-compiler/type_alias_tests.cpp
+++ b/zircon/system/utest/fidl-compiler/type_alias_tests.cpp
@@ -14,6 +14,33 @@
     TestLibrary library(R"FIDL(
 library example;
 
+struct Message {
+    alias_of_int16 f;
+};
+
+using alias_of_int16 = int16;
+)FIDL");
+    ASSERT_TRUE(library.Compile());
+    auto msg = library.LookupStruct("Message");
+    ASSERT_NONNULL(msg);
+    ASSERT_EQ(msg->members.size(), 1);
+
+    auto type = msg->members[0].type_ctor->type;
+    ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kPrimitive);
+    ASSERT_EQ(type->nullability, fidl::types::Nullability::kNonnullable);
+
+    auto primitive_type = static_cast<const fidl::flat::PrimitiveType*>(type);
+    ASSERT_EQ(primitive_type->subtype, fidl::types::PrimitiveSubtype::kInt16);
+
+    END_TEST;
+}
+
+bool primitive_type_alias_before_use() {
+    BEGIN_TEST;
+
+    TestLibrary library(R"FIDL(
+library example;
+
 using alias_of_int16 = int16;
 
 struct Message {
@@ -41,11 +68,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_of_string = vector<string>;
-
 struct Message {
     alias_of_vector_of_string f;
 };
+
+using alias_of_vector_of_string = vector<string>;
 )FIDL");
     ASSERT_TRUE(library.Compile());
     auto msg = library.LookupStruct("Message");
@@ -70,11 +97,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector = vector;
-
 struct Message {
     alias_of_vector<uint8> f;
 };
+
+using alias_of_vector = vector;
 )FIDL");
     ASSERT_TRUE(library.Compile());
     auto msg = library.LookupStruct("Message");
@@ -102,11 +129,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_max_8 = vector:8;
-
 struct Message {
     alias_of_vector_max_8<string> f;
 };
+
+using alias_of_vector_max_8 = vector:8;
 )FIDL");
     ASSERT_TRUE(library.Compile());
     auto msg = library.LookupStruct("Message");
@@ -131,11 +158,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_of_string = vector<string>;
-
 struct Message {
     alias_of_vector_of_string:8 f;
 };
+
+using alias_of_vector_of_string = vector<string>;
 )FIDL");
     ASSERT_TRUE(library.Compile());
     auto msg = library.LookupStruct("Message");
@@ -160,11 +187,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_of_string_nullable = vector<string>?;
-
 struct Message {
     alias_of_vector_of_string_nullable f;
 };
+
+using alias_of_vector_of_string_nullable = vector<string>?;
 )FIDL");
     ASSERT_TRUE(library.Compile());
     auto msg = library.LookupStruct("Message");
@@ -189,11 +216,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_of_string = vector<string>;
-
 struct Message {
     alias_of_vector_of_string? f;
 };
+
+using alias_of_vector_of_string = vector<string>;
 )FIDL");
     ASSERT_TRUE(library.Compile());
     auto msg = library.LookupStruct("Message");
@@ -218,11 +245,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_of_string = vector<string>;
-
 struct Message {
     alias_of_vector_of_string<string> f;
 };
+
+using alias_of_vector_of_string = vector<string>;
 )FIDL");
     ASSERT_FALSE(library.Compile());
     auto errors = library.errors();
@@ -238,11 +265,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_of_string_max_5 = vector<string>:5;
-
 struct Message {
     alias_of_vector_of_string_max_5:9 f;
 };
+
+using alias_of_vector_of_string_max_5 = vector<string>:5;
 )FIDL");
     ASSERT_FALSE(library.Compile());
     auto errors = library.errors();
@@ -258,11 +285,11 @@
     TestLibrary library(R"FIDL(
 library example;
 
-using alias_of_vector_nullable = vector?;
-
 struct Message {
     alias_of_vector_nullable<string>? f;
 };
+
+using alias_of_vector_nullable = vector?;
 )FIDL");
     ASSERT_FALSE(library.Compile());
     auto errors = library.errors();
@@ -276,6 +303,7 @@
 
 BEGIN_TEST_CASE(type_alias_tests)
 RUN_TEST(primitive)
+RUN_TEST(primitive_type_alias_before_use)
 RUN_TEST(vector_parametrized_on_decl)
 RUN_TEST(vector_parametrized_on_use)
 RUN_TEST(vector_bounded_on_decl)