Allow specifications for a function to be found in more than one spec file.

To enable the upcoming change that has rsClearOjbect, rsIsObject,
and rsSetObject in two spec files (core & graphics), we need to change
the generator.

Change-Id: I87925dcbe199f11c217907343455b2e8a7a76ed4
diff --git a/api/GenerateHeaderFiles.cpp b/api/GenerateHeaderFiles.cpp
index 7475d6b..eb4c9dd 100644
--- a/api/GenerateHeaderFiles.cpp
+++ b/api/GenerateHeaderFiles.cpp
@@ -95,21 +95,20 @@
     }
 }
 
-static void writeConstant(GeneratedFile* file, const Constant& constant) {
+static void writeConstantComment(GeneratedFile* file, const Constant& constant) {
     const string name = constant.getName();
     writeComment(file, name, constant.getSummary(), constant.getDescription(), true);
-
-    for (auto spec : constant.getSpecifications()) {
-        VersionInfo info = spec->getVersionInfo();
-        writeVersionGuardStart(file, info);
-        *file << "#define " << name << " " << spec->getValue() << "\n";
-        writeVersionGuardEnd(file, info);
-    }
-    *file << "\n";
 }
 
-static void writeTypeSpecification(GeneratedFile* file, const string& typeName,
-                                   const TypeSpecification& spec) {
+static void writeConstantSpecification(GeneratedFile* file, const ConstantSpecification& spec) {
+    VersionInfo info = spec.getVersionInfo();
+    writeVersionGuardStart(file, info);
+    *file << "#define " << spec.getConstant()->getName() << " " << spec.getValue() << "\n\n";
+    writeVersionGuardEnd(file, info);
+}
+
+static void writeTypeSpecification(GeneratedFile* file, const TypeSpecification& spec) {
+    const string& typeName = spec.getType()->getName();
     const VersionInfo info = spec.getVersionInfo();
     writeVersionGuardStart(file, info);
     switch (spec.getKind()) {
@@ -170,14 +169,9 @@
     *file << "\n";
 }
 
-static void writeType(GeneratedFile* file, const Type& type) {
+static void writeTypeComment(GeneratedFile* file, const Type& type) {
     const string name = type.getName();
     writeComment(file, name, type.getSummary(), type.getDescription(), true);
-
-    for (auto spec : type.getSpecifications()) {
-        writeTypeSpecification(file, name, *spec);
-    }
-    *file << "\n";
 }
 
 static void writeFunctionPermutation(GeneratedFile* file, const FunctionSpecification& spec,
@@ -272,7 +266,7 @@
     *file << "\n";
 }
 
-static void writeFunction(GeneratedFile* file, const Function& function) {
+static void writeFunctionComment(GeneratedFile* file, const Function& function) {
     // Write the generic documentation.
     writeComment(file, function.getName(), function.getSummary(), function.getDescription(), false);
 
@@ -295,12 +289,12 @@
     }
 
     *file << " */\n";
+}
 
+static void writeFunctionSpecification(GeneratedFile* file, const FunctionSpecification& spec) {
     // Write all the variants.
-    for (auto spec : function.getSpecifications()) {
-        for (auto permutation : spec->getPermutations()) {
-            writeFunctionPermutation(file, *spec, *permutation);
-        }
+    for (auto permutation : spec.getPermutations()) {
+        writeFunctionPermutation(file, spec, *permutation);
     }
 }
 
@@ -334,14 +328,33 @@
     /* Write the constants, types, and functions in the same order as
      * encountered in the spec file.
      */
-    for (auto iter : specFile.getConstantsList()) {
-        writeConstant(&file, *iter);
+    set<Constant*> documentedConstants;
+    for (auto spec : specFile.getConstantSpecifications()) {
+        Constant* constant = spec->getConstant();
+        if (documentedConstants.find(constant) == documentedConstants.end()) {
+            documentedConstants.insert(constant);
+            writeConstantComment(&file, *constant);
+        }
+        writeConstantSpecification(&file, *spec);
     }
-    for (auto iter : specFile.getTypesList()) {
-        writeType(&file, *iter);
+    set<Type*> documentedTypes;
+    for (auto spec : specFile.getTypeSpecifications()) {
+        Type* type = spec->getType();
+        if (documentedTypes.find(type) == documentedTypes.end()) {
+            documentedTypes.insert(type);
+            writeTypeComment(&file, *type);
+        }
+        writeTypeSpecification(&file, *spec);
     }
-    for (auto iter : specFile.getFunctionsList()) {
-        writeFunction(&file, *iter);
+
+    set<Function*> documentedFunctions;
+    for (auto spec : specFile.getFunctionSpecifications()) {
+        Function* function = spec->getFunction();
+        if (documentedFunctions.find(function) == documentedFunctions.end()) {
+            documentedFunctions.insert(function);
+            writeFunctionComment(&file, *function);
+        }
+        writeFunctionSpecification(&file, *spec);
     }
 
     file << "#endif // " << guard << "\n";
diff --git a/api/GenerateHtmlDocumentation.cpp b/api/GenerateHtmlDocumentation.cpp
index 359d785..a9e4d43 100644
--- a/api/GenerateHtmlDocumentation.cpp
+++ b/api/GenerateHtmlDocumentation.cpp
@@ -415,10 +415,8 @@
 
     // Write the summary tables.
     // file << "<h2>Summary</h2>\n";
-    const auto& constants = specFile.getConstantsMap();
-    const auto& types = specFile.getTypesMap();
-    const auto& functions = specFile.getFunctionsMap();
-    writeSummaryTables(file, constants, types, functions, false);
+    writeSummaryTables(file, specFile.getDocumentedConstants(), specFile.getDocumentedTypes(),
+                       specFile.getDocumentedFunctions(), false);
     return success;
 }
 
@@ -620,9 +618,9 @@
 
     // Write the summary tables.
     file << "<h2>Summary</h2>\n";
-    const auto& constants = specFile.getConstantsMap();
-    const auto& types = specFile.getTypesMap();
-    const auto& functions = specFile.getFunctionsMap();
+    const auto& constants = specFile.getDocumentedConstants();
+    const auto& types = specFile.getDocumentedTypes();
+    const auto& functions = specFile.getDocumentedFunctions();
     writeSummaryTables(&file, constants, types, functions, false);
 
     // Write the full details of each constant, type, and function.
diff --git a/api/GenerateTestFiles.cpp b/api/GenerateTestFiles.cpp
index f70c444..529bd2a 100644
--- a/api/GenerateTestFiles.cpp
+++ b/api/GenerateTestFiles.cpp
@@ -1030,11 +1030,9 @@
 
 bool GenerateTestFiles(const string& directory, int versionOfTestFiles) {
     bool success = true;
-    for (auto specFile : systemSpecification.getSpecFiles()) {
-        for (auto f : specFile->getFunctionsMap()) {
-            if (!writeTestFilesForFunction(*f.second, directory, versionOfTestFiles)) {
-                success = false;
-            }
+    for (auto f : systemSpecification.getFunctions()) {
+        if (!writeTestFilesForFunction(*f.second, directory, versionOfTestFiles)) {
+            success = false;
         }
     }
     return success;
diff --git a/api/Specification.cpp b/api/Specification.cpp
index a09495e..92d14d6 100644
--- a/api/Specification.cpp
+++ b/api/Specification.cpp
@@ -214,12 +214,11 @@
     }
 }
 
-Definition::Definition(const std::string& name, SpecFile* specFile) : mName(name), mHidden(false) {
-    mSpecFileName = specFile->getSpecFileName();
-    mUrl = specFile->getDetailedDocumentationUrl() + "#android_rs:" + name;
+Definition::Definition(const std::string& name) : mName(name), mHidden(false) {
 }
 
-void Definition::scanDocumentationTags(Scanner* scanner, bool firstOccurence) {
+void Definition::scanDocumentationTags(Scanner* scanner, bool firstOccurence,
+                                       const SpecFile* specFile) {
     if (scanner->findOptionalTag("hidden:")) {
         scanner->checkNoValue();
         mHidden = true;
@@ -234,6 +233,7 @@
                 mDescription.push_back(scanner->getValue());
             }
         }
+        mUrl = specFile->getDetailedDocumentationUrl() + "#android_rs:" + mName;
     } else if (scanner->findOptionalTag("summary:")) {
         scanner->error() << "Only the first specification should have a summary.\n";
     }
@@ -251,7 +251,7 @@
     }
 }
 
-Function::Function(const string& name, SpecFile* specFile) : Definition(name, specFile) {
+Function::Function(const string& name) : Definition(name) {
     mCapitalizedName = capitalize(mName);
 }
 
@@ -303,16 +303,16 @@
     string name = scanner->getValue();
 
     bool created = false;
-    Constant* constant = specFile->findOrCreateConstant(name, &created);
-
-    ConstantSpecification* spec = new ConstantSpecification();
+    Constant* constant = systemSpecification.findOrCreateConstant(name, &created);
+    ConstantSpecification* spec = new ConstantSpecification(constant);
     constant->addSpecification(spec);
+    specFile->addConstantSpecification(spec, created);
 
     spec->scanVersionInfo(scanner);
     if (scanner->findTag("value:")) {
         spec->mValue = scanner->getValue();
     }
-    constant->scanDocumentationTags(scanner, created);
+    constant->scanDocumentationTags(scanner, created, specFile);
 
     scanner->findTag("end:");
 }
@@ -321,10 +321,10 @@
     string name = scanner->getValue();
 
     bool created = false;
-    Type* type = specFile->findOrCreateType(name, &created);
-
-    TypeSpecification* spec = new TypeSpecification();
+    Type* type = systemSpecification.findOrCreateType(name, &created);
+    TypeSpecification* spec = new TypeSpecification(type);
     type->addSpecification(spec);
+    specFile->addTypeSpecification(spec, created);
 
     spec->scanVersionInfo(scanner);
     if (scanner->findOptionalTag("simple:")) {
@@ -356,7 +356,7 @@
             spec->mValueComments.push_back(comment);
         }
     }
-    type->scanDocumentationTags(scanner, created);
+    type->scanDocumentationTags(scanner, created, specFile);
 
     scanner->findTag("end:");
 }
@@ -497,10 +497,10 @@
     }
 
     bool created = false;
-    Function* function = specFile->findOrCreateFunction(name, &created);
-
-    FunctionSpecification* spec = new FunctionSpecification();
+    Function* function = systemSpecification.findOrCreateFunction(name, &created);
+    FunctionSpecification* spec = new FunctionSpecification(function);
     function->addSpecification(spec);
+    specFile->addFunctionSpecification(spec, created);
 
     spec->mUnexpandedName = scanner->getValue();
     spec->mTest = "scalar";  // default
@@ -542,7 +542,7 @@
         spec->mParameters.push_back(p);
     }
 
-    function->scanDocumentationTags(scanner, created);
+    function->scanDocumentationTags(scanner, created, specFile);
 
     if (scanner->findOptionalTag("inline:")) {
         scanner->checkNoValue();
@@ -633,15 +633,27 @@
     mDetailedDocumentationUrl += core + ".html";
 }
 
-SpecFile::~SpecFile() {
-    for (auto i : mConstantsList) {
-        delete i;
+void SpecFile::addConstantSpecification(ConstantSpecification* spec, bool hasDocumentation) {
+    mConstantSpecificationsList.push_back(spec);
+    if (hasDocumentation) {
+        Constant* constant = spec->getConstant();
+        mDocumentedConstants.insert(pair<string, Constant*>(constant->getName(), constant));
     }
-    for (auto i : mTypesList) {
-        delete i;
+}
+
+void SpecFile::addTypeSpecification(TypeSpecification* spec, bool hasDocumentation) {
+    mTypeSpecificationsList.push_back(spec);
+    if (hasDocumentation) {
+        Type* type = spec->getType();
+        mDocumentedTypes.insert(pair<string, Type*>(type->getName(), type));
     }
-    for (auto i : mFunctionsList) {
-        delete i;
+}
+
+void SpecFile::addFunctionSpecification(FunctionSpecification* spec, bool hasDocumentation) {
+    mFunctionSpecificationsList.push_back(spec);
+    if (hasDocumentation) {
+        Function* function = spec->getFunction();
+        mDocumentedFunctions.insert(pair<string, Function*>(function->getName(), function));
     }
 }
 
@@ -698,52 +710,45 @@
     return scanner.getErrorCount() == 0;
 }
 
+SystemSpecification::~SystemSpecification() {
+    for (auto i : mConstants) {
+        delete i.second;
+    }
+    for (auto i : mTypes) {
+        delete i.second;
+    }
+    for (auto i : mFunctions) {
+        delete i.second;
+    }
+    for (auto i : mSpecFiles) {
+        delete i;
+    }
+}
+
 // Returns the named entry in the map.  Creates it if it's not there.
 template <class T>
-T* findOrCreate(const string& name, list<T*>* list, map<string, T*>* map, bool* created,
-                SpecFile* specFile) {
+T* findOrCreate(const string& name, map<string, T*>* map, bool* created) {
     auto iter = map->find(name);
     if (iter != map->end()) {
         *created = false;
         return iter->second;
     }
     *created = true;
-    T* f = new T(name, specFile);
+    T* f = new T(name);
     map->insert(pair<string, T*>(name, f));
-    list->push_back(f);
     return f;
 }
 
-Constant* SpecFile::findOrCreateConstant(const string& name, bool* created) {
-    return findOrCreate<Constant>(name, &mConstantsList, &mConstantsMap, created, this);
+Constant* SystemSpecification::findOrCreateConstant(const string& name, bool* created) {
+    return findOrCreate<Constant>(name, &mConstants, created);
 }
 
-Type* SpecFile::findOrCreateType(const string& name, bool* created) {
-    return findOrCreate<Type>(name, &mTypesList, &mTypesMap, created, this);
+Type* SystemSpecification::findOrCreateType(const string& name, bool* created) {
+    return findOrCreate<Type>(name, &mTypes, created);
 }
 
-Function* SpecFile::findOrCreateFunction(const string& name, bool* created) {
-    return findOrCreate<Function>(name, &mFunctionsList, &mFunctionsMap, created, this);
-}
-
-SystemSpecification::~SystemSpecification() {
-    for (auto i : mSpecFiles) {
-        delete i;
-    }
-}
-
-template <class T>
-static bool addDefinitionToMap(map<string, T*>* map, T* object) {
-    const string& name = object->getName();
-    auto i = map->find(name);
-    if (i != map->end()) {
-        T* existing = i->second;
-        cerr << object->getSpecFileName() << ": Error. " << name << " has already been defined in "
-             << existing->getSpecFileName() << "\n";
-        return false;
-    }
-    (*map)[name] = object;
-    return true;
+Function* SystemSpecification::findOrCreateFunction(const string& name, bool* created) {
+    return findOrCreate<Function>(name, &mFunctions, created);
 }
 
 bool SystemSpecification::readSpecFile(const string& fileName) {
@@ -753,26 +758,7 @@
         return false;
     }
     mSpecFiles.push_back(spec);
-
-    // Store links to the definitions in a global table.
-    bool success = true;
-    for (auto i : spec->getConstantsMap()) {
-        if (!addDefinitionToMap(&mConstants, i.second)) {
-            success = false;
-        }
-    }
-    for (auto i : spec->getTypesMap()) {
-        if (!addDefinitionToMap(&mTypes, i.second)) {
-            success = false;
-        }
-    }
-    for (auto i : spec->getFunctionsMap()) {
-        if (!addDefinitionToMap(&mFunctions, i.second)) {
-            success = false;
-        }
-    }
-
-    return success;
+    return true;
 }
 
 bool SystemSpecification::generateFiles(int versionOfTestFiles) const {
diff --git a/api/Specification.h b/api/Specification.h
index 6146665..f5211f0 100644
--- a/api/Specification.h
+++ b/api/Specification.h
@@ -137,25 +137,21 @@
 class Definition {
 protected:
     std::string mName;
-    std::string mSpecFileName;
-
     bool mHidden;                           // True if it should not be documented
     std::string mSummary;                   // A one-line description
     std::vector<std::string> mDescription;  // The comments to be included in the header
     std::string mUrl;                       // The URL of the detailed documentation
 
 public:
-    Definition(const std::string& name, SpecFile* specFile);
+    Definition(const std::string& name);
 
     std::string getName() const { return mName; }
-    std::string getSpecFileName() const { return mSpecFileName; }
-
     bool hidden() const { return mHidden; }
     std::string getSummary() const { return mSummary; }
     const std::vector<std::string>& getDescription() const { return mDescription; }
     std::string getUrl() const { return mUrl; }
 
-    void scanDocumentationTags(Scanner* scanner, bool firstOccurence);
+    void scanDocumentationTags(Scanner* scanner, bool firstOccurence, const SpecFile* specFile);
 };
 
 /* Represents a constant, like M_PI.  This is a grouping of the version specific specifications.
@@ -166,7 +162,7 @@
     std::vector<ConstantSpecification*> mSpecifications;  // Owned
 
 public:
-    Constant(const std::string& name, SpecFile* specFile) : Definition(name, specFile) {}
+    Constant(const std::string& name) : Definition(name) {}
     ~Constant();
 
     const std::vector<ConstantSpecification*> getSpecifications() const { return mSpecifications; }
@@ -182,7 +178,7 @@
     std::vector<TypeSpecification*> mSpecifications;  // Owned
 
 public:
-    Type(const std::string& name, SpecFile* specFile) : Definition(name, specFile) {}
+    Type(const std::string& name) : Definition(name) {}
     ~Type();
 
     const std::vector<TypeSpecification*> getSpecifications() const { return mSpecifications; }
@@ -205,7 +201,7 @@
     std::vector<FunctionSpecification*> mSpecifications;  // Owned
 
 public:
-    Function(const std::string& name, SpecFile* specFile);
+    Function(const std::string& name);
     ~Function();
 
     std::string getCapitalizedName() const { return mCapitalizedName; }
@@ -239,8 +235,13 @@
  */
 class ConstantSpecification : public Specification {
 private:
+    Constant* mConstant;  // Not owned
+
     std::string mValue;  // E.g. "3.1415"
 public:
+    ConstantSpecification(Constant* constant) : mConstant(constant) {}
+
+    Constant* getConstant() const { return mConstant; }
     std::string getValue() const { return mValue; }
 
     // Parse a constant specification and add it to specFile.
@@ -258,6 +259,8 @@
  */
 class TypeSpecification : public Specification {
 private:
+    Type* mType;  // Not owned
+
     TypeKind mKind;  // The kind of type specification
 
     // If mKind is SIMPLE:
@@ -274,6 +277,9 @@
     std::vector<std::string> mValues;         // One entry per enum value
     std::vector<std::string> mValueComments;  // One entry per enum value
 public:
+    TypeSpecification(Type* type) : mType(type) {}
+
+    Type* getType() const { return mType; }
     TypeKind getKind() const { return mKind; }
     std::string getSimpleType() const { return mSimpleType; }
     std::string getStructName() const { return mStructName; }
@@ -298,6 +304,8 @@
  */
 class FunctionSpecification : public Specification {
 private:
+    Function* mFunction;  // Not owned
+
     /* How to test.  One of:
      * "scalar": Generate test code that checks entries of each vector indepently.  E.g. for
      *           sin(float3), the test code will call the CoreMathVerfier.computeSin 3 times.
@@ -349,9 +357,10 @@
     void createPermutations(Function* function, Scanner* scanner);
 
 public:
-    FunctionSpecification() : mReturn(nullptr) {}
+    FunctionSpecification(Function* function) : mFunction(function), mReturn(nullptr) {}
     ~FunctionSpecification();
 
+    Function* getFunction() { return mFunction; }
     std::string getAttribute() const { return mAttribute; }
     std::string getTest() const { return mTest; }
     std::string getPrecisionLimit() const { return mPrecisionLimit; }
@@ -437,25 +446,27 @@
     // Text to insert as-is in the generated header.
     std::vector<std::string> mVerbatimInclude;
 
-    /* The constants, types, and functions declared in this file,
-     * in the order they are found in the file.  This matters for
+    /* The constants, types, and functions specifications declared in this
+     *  file, in the order they are found in the file.  This matters for
      * header generation, as some types and inline functions depend
-     * on each other.
-     *
-     * Pointers are owned by this list.
+     * on each other.  Pointers not owned.
      */
-    std::list<Constant*> mConstantsList;
-    std::list<Type*> mTypesList;
-    std::list<Function*> mFunctionsList;
+    std::list<ConstantSpecification*> mConstantSpecificationsList;
+    std::list<TypeSpecification*> mTypeSpecificationsList;
+    std::list<FunctionSpecification*> mFunctionSpecificationsList;
 
-    // Quick way to find entries in the previous lists.  Pointers not owned.
-    std::map<std::string, Constant*> mConstantsMap;
-    std::map<std::string, Type*> mTypesMap;
-    std::map<std::string, Function*> mFunctionsMap;
+    /* The constants, types, and functions that are documented in this file.
+     * In very rare cases, specifications for an API are split across multiple
+     * files, e.g. currently for ClearObject().  The documentation for
+     * that function must be found in the first spec file encountered, so the
+     * order of the files on the command line matters.
+     */
+    std::map<std::string, Constant*> mDocumentedConstants;
+    std::map<std::string, Type*> mDocumentedTypes;
+    std::map<std::string, Function*> mDocumentedFunctions;
 
 public:
     explicit SpecFile(const std::string& specFileName);
-    ~SpecFile();
 
     std::string getSpecFileName() const { return mSpecFileName; }
     std::string getHeaderFileName() const { return mHeaderFileName; }
@@ -464,19 +475,31 @@
     const std::vector<std::string>& getFullDescription() const { return mFullDescription; }
     const std::vector<std::string>& getVerbatimInclude() const { return mVerbatimInclude; }
 
-    const std::list<Constant*>& getConstantsList() const { return mConstantsList; }
-    const std::list<Type*>& getTypesList() const { return mTypesList; }
-    const std::list<Function*>& getFunctionsList() const { return mFunctionsList; }
-
-    const std::map<std::string, Constant*>& getConstantsMap() const { return mConstantsMap; }
-    const std::map<std::string, Type*>& getTypesMap() const { return mTypesMap; }
-    const std::map<std::string, Function*>& getFunctionsMap() const { return mFunctionsMap; }
+    const std::list<ConstantSpecification*>& getConstantSpecifications() const {
+        return mConstantSpecificationsList;
+    }
+    const std::list<TypeSpecification*>& getTypeSpecifications() const {
+        return mTypeSpecificationsList;
+    }
+    const std::list<FunctionSpecification*>& getFunctionSpecifications() const {
+        return mFunctionSpecificationsList;
+    }
+    const std::map<std::string, Constant*>& getDocumentedConstants() const {
+        return mDocumentedConstants;
+    }
+    const std::map<std::string, Type*>& getDocumentedTypes() const { return mDocumentedTypes; }
+    const std::map<std::string, Function*>& getDocumentedFunctions() const {
+        return mDocumentedFunctions;
+    }
 
     bool readSpecFile();
 
-    Constant* findOrCreateConstant(const std::string& name, bool* created);
-    Type* findOrCreateType(const std::string& name, bool* created);
-    Function* findOrCreateFunction(const std::string& name, bool* created);
+    /* These are called by the parser to keep track of the specifications defined in this file.
+     * hasDocumentation is true if this specification containes the documentation.
+     */
+    void addConstantSpecification(ConstantSpecification* spec, bool hasDocumentation);
+    void addTypeSpecification(TypeSpecification* spec, bool hasDocumentation);
+    void addFunctionSpecification(FunctionSpecification* spec, bool hasDocumentation);
 };
 
 // The collection of all the spec files.
@@ -485,7 +508,7 @@
     std::vector<SpecFile*> mSpecFiles;
 
     /* Entries in the table of contents.  We accumulate them in a map to sort them.
-     * Pointers are not owned, they belong to the SpecFile object.
+     * Pointers are owned.
      */
     std::map<std::string, Constant*> mConstants;
     std::map<std::string, Type*> mTypes;
@@ -493,6 +516,14 @@
 
 public:
     ~SystemSpecification();
+
+    /* These are called the parser to create unique instances per name.  Set *created to true
+     * if the named specification did not already exist.
+     */
+    Constant* findOrCreateConstant(const std::string& name, bool* created);
+    Type* findOrCreateType(const std::string& name, bool* created);
+    Function* findOrCreateFunction(const std::string& name, bool* created);
+
     // Parse the spec file and create the object hierarchy, adding a pointer to mSpecFiles.
     bool readSpecFile(const std::string& fileName);
     // Generate all the files.