[fidlc] Declaration order test

Test: make -j 72 HOST_USE_ASAN=true tools && ./build-x64/host_tests/fidl-compiler-test
Change-Id: I87bf788bb78ffba4708b0c0e606da0a297f52c87
diff --git a/system/utest/fidl-compiler/declaration_order_tests.cpp b/system/utest/fidl-compiler/declaration_order_tests.cpp
new file mode 100644
index 0000000..f8d4a6c
--- /dev/null
+++ b/system/utest/fidl-compiler/declaration_order_tests.cpp
@@ -0,0 +1,106 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <unittest/unittest.h>
+
+#include <fidl/flat_ast.h>
+#include <fidl/lexer.h>
+#include <fidl/parser.h>
+#include <fidl/source_file.h>
+
+#include "test_library.h"
+
+#define ASSERT_DECL_NAME(D, N) \
+    ASSERT_STR_EQ(N, static_cast<const std::string>(D->name.name_part()).c_str());
+
+namespace {
+
+bool nonnullable_ref() {
+    BEGIN_TEST;
+
+    TestLibrary library(R"FIDL(
+library example;
+
+struct TheRequestStruct_02 {
+  array<TheElementStruct_03>:4 req;
+};
+
+struct TheElementStruct_03 {};
+
+interface TheInterface_01 {
+  SomeMethod(TheRequestStruct_02 req);
+};
+
+)FIDL");
+    ASSERT_TRUE(library.Compile());
+    auto decl_order = library.declaration_order();
+    ASSERT_EQ(4, decl_order.size());
+    ASSERT_DECL_NAME(decl_order[0], "TheElementStruct_03");
+    ASSERT_DECL_NAME(decl_order[1], "TheRequestStruct_02");
+    ASSERT_DECL_NAME(decl_order[2], "SomeLongAnonymousPrefix0");
+    ASSERT_DECL_NAME(decl_order[3], "TheInterface_01");
+
+    END_TEST;
+}
+
+bool nullable_ref_breaks_dependency() {
+    BEGIN_TEST;
+
+    TestLibrary library(R"FIDL(
+library example;
+
+struct TheRequestStruct_02 {
+  array<TheElementStruct_03?>:4 req;
+};
+
+struct TheElementStruct_03 {};
+
+interface TheInterface_01 {
+  SomeMethod(TheRequestStruct_02 req);
+};
+
+)FIDL");
+    ASSERT_TRUE(library.Compile());
+    auto decl_order = library.declaration_order();
+    ASSERT_EQ(4, decl_order.size());
+    ASSERT_DECL_NAME(decl_order[0], "TheRequestStruct_02");
+    ASSERT_DECL_NAME(decl_order[1], "SomeLongAnonymousPrefix0");
+    ASSERT_DECL_NAME(decl_order[2], "TheInterface_01");
+    ASSERT_DECL_NAME(decl_order[3], "TheElementStruct_03");
+
+    END_TEST;
+}
+
+bool request_type_breaks_dependency_graph() {
+    BEGIN_TEST;
+
+    TestLibrary library(R"FIDL(
+library example;
+
+struct TheRequestStruct_02 {
+  request<TheInterface_01> req;
+};
+
+interface TheInterface_01 {
+  SomeMethod(TheRequestStruct_02 req);
+};
+
+)FIDL");
+    ASSERT_TRUE(library.Compile());
+    auto decl_order = library.declaration_order();
+    ASSERT_EQ(3, decl_order.size());
+    ASSERT_DECL_NAME(decl_order[0], "TheRequestStruct_02");
+    ASSERT_DECL_NAME(decl_order[1], "SomeLongAnonymousPrefix0");
+    ASSERT_DECL_NAME(decl_order[2], "TheInterface_01");
+
+    END_TEST;
+}
+
+} // namespace
+
+BEGIN_TEST_CASE(declaration_order_test);
+RUN_TEST(nonnullable_ref);
+RUN_TEST(nullable_ref_breaks_dependency);
+RUN_TEST(request_type_breaks_dependency_graph);
+END_TEST_CASE(declaration_order_test);
diff --git a/system/utest/fidl-compiler/rules.mk b/system/utest/fidl-compiler/rules.mk
index e8c92d3..a5a162e 100644
--- a/system/utest/fidl-compiler/rules.mk
+++ b/system/utest/fidl-compiler/rules.mk
@@ -64,6 +64,7 @@
 MODULE_SRCS := \
     $(LOCAL_DIR)/attributes_tests.cpp \
     $(LOCAL_DIR)/consts_tests.cpp \
+    $(LOCAL_DIR)/declaration_order_tests.cpp \
     $(LOCAL_DIR)/enums_tests.cpp \
     $(LOCAL_DIR)/flat_ast_tests.cpp \
     $(LOCAL_DIR)/formatter_unittests.cpp \
diff --git a/system/utest/fidl-compiler/test_library.h b/system/utest/fidl-compiler/test_library.h
index 32fb8ff..3348cc4 100644
--- a/system/utest/fidl-compiler/test_library.h
+++ b/system/utest/fidl-compiler/test_library.h
@@ -126,6 +126,10 @@
         return error_reporter_.warnings();
     }
 
+    const std::vector<fidl::flat::Decl*> declaration_order() const {
+        return library_->declaration_order_;
+    }
+
 protected:
     fidl::SourceFile source_file_;
     fidl::ErrorReporter error_reporter_;