Build RS API doc generator with Android.bp

The RS API header/document generator should be compiled with a proper
Android.bp rather than relying on a hardcoded clang version. This CL
updates both the generate.sh and provides an Android.bp for the generator.

Also fixed a segfault caused by an old bug from advancing an invalidated
list iterator. The segfault was caught by switching toolchain and C++
library versions.

In addition, fixed warnings caught by -Werror.

Test: m
Test: run generate.sh and inspect the generated documents
Bug: 66509928
Change-Id: Ibbbaaf65a0d1fc8ca37d357d077530d351d112f5
diff --git a/script_api/Android.bp b/script_api/Android.bp
new file mode 100644
index 0000000..8f42e47
--- /dev/null
+++ b/script_api/Android.bp
@@ -0,0 +1,26 @@
+// Build API doc generator ====================
+
+cc_binary_host {
+    name: "rs-api-doc-generator",
+    cpp_std: "c++17",
+    srcs: [
+        "Generator.cpp",
+        "Specification.cpp",
+        "GenerateDocumentation.cpp",
+        "GenerateHeaderFiles.cpp",
+        "GenerateTestFiles.cpp",
+        "Scanner.cpp",
+        "Utilities.cpp",
+        "GenerateStubsWhiteList.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    sanitize: {
+        never: true,
+    },
+}
+
diff --git a/script_api/GenerateDocumentation.cpp b/script_api/GenerateDocumentation.cpp
index fde096b..94af311 100644
--- a/script_api/GenerateDocumentation.cpp
+++ b/script_api/GenerateDocumentation.cpp
@@ -50,7 +50,7 @@
         // Output only the first two lines. Assuming there's no other HTML
         // markups there
         // TODO: escape/remove markups
-        for (int i = 0; i < std::min(desc.size(), 2UL); ++i) {
+        for (unsigned int i = 0; i < std::min(desc.size(), 2UL); ++i) {
             if (i) *file << " ";
             *file << desc[i];
         }
diff --git a/script_api/GenerateStubsWhiteList.cpp b/script_api/GenerateStubsWhiteList.cpp
index ed03a09..5caecd5 100644
--- a/script_api/GenerateStubsWhiteList.cpp
+++ b/script_api/GenerateStubsWhiteList.cpp
@@ -105,7 +105,6 @@
             i++;
         } else {
             // Split the replacement string in tokens.
-            istringstream stream(substitute);
 
             /* Get the new vector size. This is for the case of the type being for example
              * rs_quaternion* == float4*, where we need the vector size to be 4 for the
@@ -126,14 +125,16 @@
             if (newVectorSizeVal > vectorSizeVal)
                 vectorSize = newVectorSize;
 
+            istringstream stream(substitute);
             list<string> newTokens{istream_iterator<string>{stream}, istream_iterator<string>{}};
             // Replace the token with the substitution. Don't advance, as the new substitution
             // might itself be replaced.
+            // hold previous node
             auto prev = i;
-            --prev;
-            tokens.insert(i, newTokens.begin(), newTokens.end());
-            tokens.erase(i);
-            advance(i, -newTokens.size());
+            // insert new nodes after node i
+            tokens.splice(++i, std::move(newTokens));
+            // remove previous node and set i to beginning of inserted nodes
+            i = tokens.erase(prev);
         }
     }
     return tokens;
@@ -322,9 +323,9 @@
 /* Add the mangling for this permutation of the function.  apiLevel and intSize is used
  * to select the correct type when expanding complex type.
  */
-static bool addFunctionManglingToSet(const Function& function,
-                                     const FunctionPermutation& permutation, bool overloadable,
-                                     unsigned int apiLevel, int intSize, set<string>* allManglings) {
+static bool addFunctionManglingToSet(const FunctionPermutation& permutation,
+                                     bool overloadable, unsigned int apiLevel,
+                                     int intSize, set<string>* allManglings) {
     const string& functionName = permutation.getName();
     string mangling;
     if (overloadable) {
@@ -347,8 +348,8 @@
  * for each API level because the implementation of a type may have changed in the range
  * of API levels covered.
  */
-static bool addManglingsForSpecification(const Function& function,
-                                         const FunctionSpecification& spec, unsigned int lastApiLevel,
+static bool addManglingsForSpecification(const FunctionSpecification& spec,
+                                         unsigned int lastApiLevel,
                                          set<string>* allManglings) {
     // If the function is inlined, we won't generate an unresolved external for that.
     if (spec.hasInline()) {
@@ -369,14 +370,14 @@
     for (int64_t apiLevel = minApiLevel; apiLevel <= maxApiLevel; ++apiLevel) {
         for (auto permutation : spec.getPermutations()) {
             if (info.intSize == 0 || info.intSize == 32) {
-                if (!addFunctionManglingToSet(function, *permutation, overloadable, apiLevel, 32,
-                                              allManglings)) {
+                if (!addFunctionManglingToSet(*permutation, overloadable,
+                                              apiLevel, 32, allManglings)) {
                     success = false;
                 }
             }
             if (apiLevel >= kApiLevelWithFirst64Bit && (info.intSize == 0 || info.intSize == 64)) {
-                if (!addFunctionManglingToSet(function, *permutation, overloadable, apiLevel, 64,
-                                              allManglings)) {
+                if (!addFunctionManglingToSet(*permutation, overloadable,
+                                              apiLevel, 64, allManglings)) {
                     success = false;
                 }
             }
@@ -400,7 +401,8 @@
             if (spec->isIntrinsic()) {
                 continue;
             }
-            if (!addManglingsForSpecification(*function, *spec, lastApiLevel, &allManglings)) {
+            if (!addManglingsForSpecification(*spec, lastApiLevel,
+                                              &allManglings)) {
                 success = false;  // We continue so we can generate all errors.
             }
         }
@@ -438,7 +440,7 @@
  * before the function definition.
  */
 static void generateTestCall(GeneratedFile* file, ostringstream* calls,
-                             unsigned int* variableNumber, const Function& function,
+                             unsigned int* variableNumber,
                              const FunctionPermutation& permutation) {
     *calls << "    ";
 
@@ -523,7 +525,7 @@
                 // http://b/27358969 Do not test rsForEach in the all-api test.
                 if (apiLevel >= 24 && permutation->getName().compare(0, 9, "rsForEach") == 0)
                   continue;
-                generateTestCall(&file, &calls, &variableNumber, *function, *permutation);
+                generateTestCall(&file, &calls, &variableNumber, *permutation);
             }
             if (info.intSize != 0) {
                 calls << "#endif\n";
diff --git a/script_api/GenerateTestFiles.cpp b/script_api/GenerateTestFiles.cpp
index d907d37..5a649a5 100644
--- a/script_api/GenerateTestFiles.cpp
+++ b/script_api/GenerateTestFiles.cpp
@@ -1010,8 +1010,9 @@
 }
 
 // Open the mJavaFile and writes the header.
-static bool startJavaFile(GeneratedFile* file, const Function& function, const string& directory,
-                          const string& testName, const string& relaxedTestName) {
+static bool startJavaFile(GeneratedFile* file, const string& directory,
+                          const string& testName,
+                          const string& relaxedTestName) {
     const string fileName = testName + ".java";
     if (!file->start(directory, fileName)) {
         return false;
@@ -1072,7 +1073,7 @@
 }
 
 // Open the script file and write its header.
-static bool startRsFile(GeneratedFile* file, const Function& function, const string& directory,
+static bool startRsFile(GeneratedFile* file, const string& directory,
                         const string& testName) {
     string fileName = testName + ".rs";
     if (!file->start(directory, fileName)) {
@@ -1086,8 +1087,8 @@
 }
 
 // Write the entire *Relaxed.rs test file, as it only depends on the name.
-static bool writeRelaxedRsFile(const Function& function, const string& directory,
-                               const string& testName, const string& relaxedTestName) {
+static bool writeRelaxedRsFile(const string& directory, const string& testName,
+                               const string& relaxedTestName) {
     string name = relaxedTestName + ".rs";
 
     GeneratedFile file;
@@ -1115,17 +1116,17 @@
     const string testName = "Test" + function.getCapitalizedName();
     const string relaxedTestName = testName + "Relaxed";
 
-    if (!writeRelaxedRsFile(function, directory, testName, relaxedTestName)) {
+    if (!writeRelaxedRsFile(directory, testName, relaxedTestName)) {
         return false;
     }
 
     GeneratedFile rsFile;    // The Renderscript test file we're generating.
     GeneratedFile javaFile;  // The Jave test file we're generating.
-    if (!startRsFile(&rsFile, function, directory, testName)) {
+    if (!startRsFile(&rsFile, directory, testName)) {
         return false;
     }
 
-    if (!startJavaFile(&javaFile, function, directory, testName, relaxedTestName)) {
+    if (!startJavaFile(&javaFile, directory, testName, relaxedTestName)) {
         return false;
     }
 
diff --git a/script_api/Specification.cpp b/script_api/Specification.cpp
index 4082a04..5056b08 100644
--- a/script_api/Specification.cpp
+++ b/script_api/Specification.cpp
@@ -266,7 +266,8 @@
      * - We have a max that's later than what we currently have.
      */
     if (mFinalVersion < 0 || info.maxVersion == 0 ||
-        (mFinalVersion > 0 && info.maxVersion > mFinalVersion)) {
+        (mFinalVersion > 0 &&
+         static_cast<int>(info.maxVersion) > mFinalVersion)) {
         mFinalVersion = info.maxVersion;
     }
 }
diff --git a/script_api/Specification.h b/script_api/Specification.h
index 8bb99ed..9d6764e 100644
--- a/script_api/Specification.h
+++ b/script_api/Specification.h
@@ -141,7 +141,7 @@
      */
     bool scan(Scanner* scanner, unsigned int maxApiLevel);
     /* Return true if the target can be found whitin the range. */
-    bool includesVersion(int target) const {
+    bool includesVersion(unsigned int target) const {
         return (minVersion == 0 || target >= minVersion) &&
                (maxVersion == 0 || target <= maxVersion);
     }
diff --git a/script_api/generate.sh b/script_api/generate.sh
index 894edc8..9adc751 100755
--- a/script_api/generate.sh
+++ b/script_api/generate.sh
@@ -18,7 +18,6 @@
 # TODO: $ANDROID_BUILD_TOP/prebuilts/clang/host/linux-x86/clang-stable/bin
 # no longer contains clang on AOSP master. Need a stable way to reach clang
 # binaries here.
-CLANG=$ANDROID_BUILD_TOP/prebuilts/clang/host/linux-x86/clang-4393122/bin/clang++
 
 if [ x"$1" == "x" ]; then
   echo "Please specify the top-level Piper client directory."
@@ -34,7 +33,6 @@
 cd `dirname $0`
 
 set -e
-$CLANG Generator.cpp Specification.cpp GenerateDocumentation.cpp GenerateHeaderFiles.cpp GenerateTestFiles.cpp Scanner.cpp Utilities.cpp GenerateStubsWhiteList.cpp -g -std=c++11 -Wall -o generator
 
 mkdir -p test
 mkdir -p include
@@ -47,9 +45,7 @@
 #    This can be manually changed when cut&pasting the snippet into guide_toc.cs.
 # 3. rsIs/Clear/SetObject is documented in rs_object_info but also found in rs_graphics.
 #    The latter must appear after the former.
-./generator rs_core.spec rs_value_types.spec rs_object_types.spec rs_convert.spec rs_math.spec rs_vector_math.spec rs_matrix.spec rs_quaternion.spec rs_atomic.spec rs_time.spec rs_allocation_create.spec rs_allocation_data.spec rs_object_info.spec rs_for_each.spec rs_io.spec rs_debug.spec rs_graphics.spec
-
-rm generator
+$ANDROID_HOST_OUT/bin/rs-api-doc-generator rs_core.spec rs_value_types.spec rs_object_types.spec rs_convert.spec rs_math.spec rs_vector_math.spec rs_matrix.spec rs_quaternion.spec rs_atomic.spec rs_time.spec rs_allocation_create.spec rs_allocation_data.spec rs_object_info.spec rs_for_each.spec rs_io.spec rs_debug.spec rs_graphics.spec
 
 rm -f ../../../cts/tests/tests/renderscript/src/android/renderscript/cts/generated/*
 mv test/* ../../../cts/tests/tests/renderscript/src/android/renderscript/cts/generated/