Merge "Use static_libs for java."
diff --git a/AST.cpp b/AST.cpp
index 6d26349..17c8e26 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -342,15 +342,17 @@
 
     addToImportedNamesGranular(fqName);
 
-    AST *importAST;
-
     // cases like android.hardware.foo@1.0::IFoo.Internal
     //            android.hardware.foo@1.0::Abc.Internal
 
     // assume it is an interface, and try to import it.
     const FQName interfaceName = fqName.getTopLevelType();
     // Do not enforce restrictions on imports.
-    importAST = mCoordinator->parse(interfaceName, &mImportedASTs, Coordinator::Enforce::NONE);
+    AST* importAST;
+    status_t err = mCoordinator->parseOptional(interfaceName, &importAST, &mImportedASTs,
+                                               Coordinator::Enforce::NONE);
+    if (err != OK) return false;
+    // importAST nullptr == file doesn't exist
 
     if (importAST != nullptr) {
         // cases like android.hardware.foo@1.0::IFoo.Internal
diff --git a/Android.bp b/Android.bp
index d3acd41..d1e9c5a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,7 @@
 
 cc_defaults {
     name: "hidl-gen-defaults",
+    cpp_std: "experimental",
     cflags: [
         "-O0",
         "-g",
diff --git a/Coordinator.cpp b/Coordinator.cpp
index 6110c23..198505b 100644
--- a/Coordinator.cpp
+++ b/Coordinator.cpp
@@ -29,8 +29,7 @@
 
 #include "AST.h"
 #include "Interface.h"
-
-extern android::status_t parseFile(android::AST *ast);
+#include "hidl-gen_l.h"
 
 static bool existdir(const char *name) {
     DIR *dir = opendir(name);
@@ -192,17 +191,34 @@
 
 AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
                         Enforce enforcement) const {
+    AST* ret;
+    status_t err = parseOptional(fqName, &ret, parsedASTs, enforcement);
+    if (err != OK) CHECK(ret == nullptr);  // internal consistency
+
+    // only in a handful of places do we want to distinguish between
+    // a missing file and a bad AST. Everywhere else, we just want to
+    // throw an error if we expect an AST to be present but it is not.
+    return ret;
+}
+
+status_t Coordinator::parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs,
+                                    Enforce enforcement) const {
     CHECK(fqName.isFullyQualified());
 
     auto it = mCache.find(fqName);
     if (it != mCache.end()) {
-        AST *ast = (*it).second;
+        *ast = (*it).second;
 
-        if (ast != nullptr && parsedASTs != nullptr) {
-            parsedASTs->insert(ast);
+        if (*ast != nullptr && parsedASTs != nullptr) {
+            parsedASTs->insert(*ast);
         }
 
-        return ast;
+        if (*ast == nullptr) {
+            // circular import OR that AST has errors in it
+            return UNKNOWN_ERROR;
+        }
+
+        return OK;
     }
 
     // Add this to the cache immediately, so we can discover circular imports.
@@ -214,7 +230,8 @@
         // Any interface file implicitly imports its package's types.hal.
         FQName typesName = fqName.getTypesForPackage();
         // Do not enforce on imports. Do not add imports' imports to this AST.
-        typesAST = parse(typesName, nullptr, Enforce::NONE);
+        status_t err = parseOptional(typesName, &typesAST, nullptr, Enforce::NONE);
+        if (err != OK) return err;
 
         // fall through.
     }
@@ -224,26 +241,35 @@
     path.append(fqName.name());
     path.append(".hal");
 
-    AST* ast = new AST(this, &Hash::getHash(path));
+    *ast = new AST(this, &Hash::getHash(path));
 
     if (typesAST != NULL) {
         // If types.hal for this AST's package existed, make it's defined
         // types available to the (about to be parsed) AST right away.
-        ast->addImportedAST(typesAST);
+        (*ast)->addImportedAST(typesAST);
     }
 
-    if (parseFile(ast) != OK || ast->postParse() != OK) {
-        delete ast;
-        ast = nullptr;
+    FILE* file = fopen(path.c_str(), "rb");
 
-        return nullptr;
+    if (file == nullptr) {
+        mCache.erase(fqName);  // nullptr in cache is used to find circular imports
+        delete *ast;
+        *ast = nullptr;
+        return OK;  // File does not exist, nullptr AST* == file doesn't exist.
     }
 
     onFileAccess(path, "r");
 
+    // parse file takes ownership of file
+    if (parseFile(*ast, file) != OK || (*ast)->postParse() != OK) {
+        delete *ast;
+        *ast = nullptr;
+        return UNKNOWN_ERROR;
+    }
+
     status_t err = OK;
-    if (ast->package().package() != fqName.package()
-            || ast->package().version() != fqName.version()) {
+    if ((*ast)->package().package() != fqName.package() ||
+        (*ast)->package().version() != fqName.version()) {
         fprintf(stderr,
                 "ERROR: File at '%s' does not match expected package and/or "
                 "version.\n",
@@ -251,16 +277,15 @@
 
         err = UNKNOWN_ERROR;
     } else {
-        if (ast->isInterface()) {
+        if ((*ast)->isInterface()) {
             if (fqName.name() == "types") {
                 fprintf(stderr,
                         "ERROR: File at '%s' declares an interface '%s' "
                         "instead of the expected types common to the package.\n",
-                        path.c_str(),
-                        ast->getInterface()->localName().c_str());
+                        path.c_str(), (*ast)->getInterface()->localName().c_str());
 
                 err = UNKNOWN_ERROR;
-            } else if (ast->getInterface()->localName() != fqName.name()) {
+            } else if ((*ast)->getInterface()->localName() != fqName.name()) {
                 fprintf(stderr,
                         "ERROR: File at '%s' does not declare interface type "
                         "'%s'.\n",
@@ -277,7 +302,7 @@
                     fqName.name().c_str());
 
             err = UNKNOWN_ERROR;
-        } else if (ast->containsInterfaces()) {
+        } else if ((*ast)->containsInterfaces()) {
             fprintf(stderr,
                     "ERROR: types.hal file at '%s' declares at least one "
                     "interface type.\n",
@@ -288,28 +313,29 @@
     }
 
     if (err != OK) {
-        delete ast;
-        ast = nullptr;
-
-        return nullptr;
+        delete *ast;
+        *ast = nullptr;
+        return err;
     }
 
-    if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
+    if (parsedASTs != nullptr) {
+        parsedASTs->insert(*ast);
+    }
 
     // put it into the cache now, so that enforceRestrictionsOnPackage can
     // parse fqName.
-    mCache[fqName] = ast;
+    mCache[fqName] = *ast;
 
     // For each .hal file that hidl-gen parses, the whole package will be checked.
     err = enforceRestrictionsOnPackage(fqName, enforcement);
     if (err != OK) {
         mCache[fqName] = nullptr;
-        delete ast;
-        ast = nullptr;
-        return nullptr;
+        delete *ast;
+        *ast = nullptr;
+        return err;
     }
 
-    return ast;
+    return OK;
 }
 
 const Coordinator::PackageRoot &Coordinator::findPackageRoot(const FQName &fqName) const {
@@ -357,10 +383,6 @@
     return findPackageRoot(fqName).path;
 }
 
-std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
-    return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
-}
-
 std::string Coordinator::getPackagePath(
         const FQName& fqName, bool relative, bool sanitized) const {
 
@@ -736,8 +758,10 @@
 
     std::string hashPath = makeAbsolute(getPackageRootPath(fqName)) + "/current.txt";
     std::string error;
-    onFileAccess(hashPath, "r");
-    std::vector<std::string> frozen = Hash::lookupHash(hashPath, fqName.string(), &error);
+    bool fileExists;
+    std::vector<std::string> frozen =
+        Hash::lookupHash(hashPath, fqName.string(), &error, &fileExists);
+    if (fileExists) onFileAccess(hashPath, "r");
 
     if (error.size() > 0) {
         std::cerr << "ERROR: " << error << std::endl;
diff --git a/Coordinator.h b/Coordinator.h
index 10d05ac..60a9a4f 100644
--- a/Coordinator.h
+++ b/Coordinator.h
@@ -86,6 +86,15 @@
     AST* parse(const FQName& fqName, std::set<AST*>* parsedASTs = nullptr,
                Enforce enforcement = Enforce::FULL) const;
 
+    // Same as parse, but it distinguishes between "missing file" and "could not parse AST"
+    // return OK, out *ast:
+    //    0xdeadbeef -> successfully parsed
+    //    nullptr    -> file not present
+    // return !OK
+    //    could not parse AST and file exists
+    status_t parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs = nullptr,
+                           Enforce enforcement = Enforce::FULL) const;
+
     // Given package-root paths of ["hardware/interfaces",
     // "vendor/<something>/interfaces"], package roots of
     // ["android.hardware", "vendor.<something>.hardware"], and a
@@ -102,9 +111,6 @@
     // return "android.hardware".
     std::string getPackageRoot(const FQName &fqName) const;
 
-    // return getPackageRoot + ":" + getPackageRootPath
-    std::string getPackageRootOption(const FQName &fqName) const;
-
     status_t getPackageInterfaceFiles(
             const FQName &package,
             std::vector<std::string> *fileNames) const;
diff --git a/Hash.cpp b/Hash.cpp
index e269a2c..7eb315b 100644
--- a/Hash.cpp
+++ b/Hash.cpp
@@ -167,16 +167,18 @@
     std::map<std::string,std::vector<std::string>> hashes;
 };
 
-std::vector<std::string> Hash::lookupHash(const std::string &path,
-                                          const std::string &interfaceName,
-                                          std::string *err) {
+std::vector<std::string> Hash::lookupHash(const std::string& path, const std::string& interfaceName,
+                                          std::string* err, bool* fileExists) {
     *err = "";
     const HashFile *file = HashFile::parse(path, err);
 
     if (file == nullptr || err->size() > 0) {
+        if (fileExists != nullptr) *fileExists = false;
         return {};
     }
 
+    if (fileExists != nullptr) *fileExists = true;
+
     return file->lookup(interfaceName);
 }
 
diff --git a/NamedType.cpp b/NamedType.cpp
index a57c8cd..645c63d 100644
--- a/NamedType.cpp
+++ b/NamedType.cpp
@@ -38,10 +38,6 @@
     return mFullName.cppName();
 }
 
-std::string NamedType::partialCppName() const {
-    return mFullName.cppLocalName();
-}
-
 std::string NamedType::fullJavaName() const {
     return mFullName.javaName();
 }
diff --git a/NamedType.h b/NamedType.h
index a0ef302..857f3a3 100644
--- a/NamedType.h
+++ b/NamedType.h
@@ -38,8 +38,6 @@
 
     /* short for fqName().cppName() */
     std::string fullName() const;
-    /* short for fqName().cppLocalName() */
-    std::string partialCppName() const;
     /* short for fqName().fullJavaName() */
     std::string fullJavaName() const;
 
diff --git a/c2hal/c2hal_l.ll b/c2hal/c2hal_l.ll
index 42f7464..f613adc 100644
--- a/c2hal/c2hal_l.ll
+++ b/c2hal/c2hal_l.ll
@@ -78,6 +78,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
 #pragma clang diagnostic ignored "-Wdeprecated-register"
+#pragma clang diagnostic ignored "-Wregister"
 
 %}
 
diff --git a/hidl-gen_l.h b/hidl-gen_l.h
new file mode 100644
index 0000000..0642c2d
--- /dev/null
+++ b/hidl-gen_l.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <AST.h>
+
+#include <utils/Errors.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// entry-point for file parsing
+// - contents of file are added to the AST
+// - expects file to already be open
+status_t parseFile(AST* ast, FILE* file);
+
+}  // namespace android
\ No newline at end of file
diff --git a/hidl-gen_l.ll b/hidl-gen_l.ll
index 71d3067..3be556b 100644
--- a/hidl-gen_l.ll
+++ b/hidl-gen_l.ll
@@ -68,6 +68,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
 #pragma clang diagnostic ignored "-Wdeprecated-register"
+#pragma clang diagnostic ignored "-Wregister"
 
 %}
 
@@ -180,13 +181,9 @@
 
 #pragma clang diagnostic pop
 
-status_t parseFile(AST *ast) {
-    FILE *file = fopen(ast->getFilename().c_str(), "rb");
+namespace android {
 
-    if (file == nullptr) {
-        return -errno;
-    }
-
+status_t parseFile(AST* ast, FILE* file) {
     yyscan_t scanner;
     yylex_init(&scanner);
 
@@ -206,3 +203,5 @@
 
     return OK;
 }
+
+}  // namespace android
diff --git a/include_hash/hidl-hash/Hash.h b/include_hash/hidl-hash/Hash.h
index 40cc5bf..e443ef5 100644
--- a/include_hash/hidl-hash/Hash.h
+++ b/include_hash/hidl-hash/Hash.h
@@ -32,9 +32,9 @@
     // returns matching hashes of interfaceName in path
     // path is something like hardware/interfaces/current.txt
     // interfaceName is something like android.hardware.foo@1.0::IFoo
-    static std::vector<std::string> lookupHash(const std::string &path,
-                                               const std::string &interfaceName,
-                                               std::string *err);
+    static std::vector<std::string> lookupHash(const std::string& path,
+                                               const std::string& interfaceName, std::string* err,
+                                               bool* fileExists = nullptr);
 
     static std::string hexString(const std::vector<uint8_t> &hash);
     std::string hexString() const;
diff --git a/main.cpp b/main.cpp
index 3d10854..ac6f638 100644
--- a/main.cpp
+++ b/main.cpp
@@ -785,7 +785,7 @@
 
         out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
             << "// Source: " << packageFQName.string() << "\n"
-            << "// Root: " << coordinator->getPackageRootOption(packageFQName) << "\n\n";
+            << "// Location: " << coordinator->getPackagePath(packageFQName) << "\n\n";
 
         std::string guard;
         if (forJava) {
@@ -1135,9 +1135,12 @@
 static void usage(const char *me) {
     fprintf(stderr,
             "usage: %s [-p <root path>] -o <output path> -L <language> [-O <owner>] (-r <interface "
-            "root>)+ [-v] [-d <depfile>] fqname+\n",
+            "root>)+ [-v] [-d <depfile>] FQNAME...\n\n",
             me);
 
+    fprintf(stderr,
+            "Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.\n\n");
+
     fprintf(stderr, "         -h: Prints this menu.\n");
     fprintf(stderr, "         -L <language>: The following options are available:\n");
     for (auto& e : kFormats) {
@@ -1325,15 +1328,14 @@
     for (int i = 0; i < argc; ++i) {
         FQName fqName(argv[i]);
 
-        // TODO(b/65200821): remove
-        gCurrentCompileName = "_" + StringHelper::Uppercase(fqName.tokenName());
-
         if (!fqName.isValid()) {
-            fprintf(stderr,
-                    "ERROR: Invalid fully-qualified name.\n");
+            fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", argv[i]);
             exit(1);
         }
 
+        // TODO(b/65200821): remove
+        gCurrentCompileName = "_" + StringHelper::Uppercase(fqName.tokenName());
+
         // Dump extra verbose output
         if (coordinator.isVerbose()) {
             status_t err =
diff --git a/test/error_test/references_broken_package/1.0/IBar.hal b/test/error_test/references_broken_package/1.0/IBar.hal
new file mode 100644
index 0000000..27dbdeb
--- /dev/null
+++ b/test/error_test/references_broken_package/1.0/IBar.hal
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package test.references_broken_package@1.0;
+
+import test.references_broken_package.bad_package@1.0::IFoo;
+
+interface IBar {
+};
diff --git a/test/error_test/references_broken_package/1.0/required_error b/test/error_test/references_broken_package/1.0/required_error
new file mode 100644
index 0000000..4301bae
--- /dev/null
+++ b/test/error_test/references_broken_package/1.0/required_error
@@ -0,0 +1 @@
+missing ; at
\ No newline at end of file
diff --git a/test/error_test/references_broken_package/bad_package/1.0/IFoo.hal b/test/error_test/references_broken_package/bad_package/1.0/IFoo.hal
new file mode 100644
index 0000000..14d4189
--- /dev/null
+++ b/test/error_test/references_broken_package/bad_package/1.0/IFoo.hal
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package test.references_broken_package.bad_package@1.0;
+
+interface IFoo {
+} // no semicolon -> error
diff --git a/test/error_test/references_broken_package/bad_package/1.0/types.hal b/test/error_test/references_broken_package/bad_package/1.0/types.hal
new file mode 100644
index 0000000..ea7ed6e
--- /dev/null
+++ b/test/error_test/references_broken_package/bad_package/1.0/types.hal
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package test.references_broken_package.bad_package@1.0;
+
+struct IFoo {};
\ No newline at end of file
diff --git a/test/hidl_test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
index aa8859a..5fed44f 100644
--- a/test/hidl_test/hidl_test_client.cpp
+++ b/test/hidl_test/hidl_test_client.cpp
@@ -1779,7 +1779,6 @@
                 for (size_t i = 0; i != REQUEST_NUM; ++i) {
                     strings.push_back(stringGenerator.next());
                 }
-                std::random_shuffle(strings.begin(), strings.end());
 
                 std::vector<bool> trueResponse(strings.size());
                 std::transform(strings.begin(), strings.end(), trueResponse.begin(),