AAPT2: Debug: Dump only targetted style

Change-Id: Id7c5a4b5d0880520e1fea05e5a31d398946c5f05
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index a7b9bba..cf222c6 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -23,6 +23,7 @@
 #include <iostream>
 #include <map>
 #include <memory>
+#include <queue>
 #include <set>
 #include <vector>
 
@@ -135,43 +136,53 @@
     return std::distance(names.begin(), iter);
 }
 
-void Debug::printStyleGraph(const std::shared_ptr<ResourceTable>& table) {
-    std::vector<ResourceName> names;
+void Debug::printStyleGraph(const std::shared_ptr<ResourceTable>& table,
+                            const ResourceName& targetStyle) {
     std::map<ResourceName, std::set<ResourceName>> graph;
 
-    for (const auto& type : *table) {
-        for (const auto& entry : type->entries) {
-            ResourceName name = { table->getPackage(), type->type, entry->name };
+    std::queue<ResourceName> stylesToVisit;
+    stylesToVisit.push(targetStyle);
+    for (; !stylesToVisit.empty(); stylesToVisit.pop()) {
+        const ResourceName& styleName = stylesToVisit.front();
+        std::set<ResourceName>& parents = graph[styleName];
+        if (!parents.empty()) {
+            // We've already visited this style.
+            continue;
+        }
+
+        const ResourceTableType* type;
+        const ResourceEntry* entry;
+        std::tie(type, entry) = table->findResource(styleName);
+        if (entry) {
             for (const auto& value : entry->values) {
                 visitFunc<Style>(*value.value, [&](const Style& style) {
                     if (style.parent.name.isValid()) {
-                        names.push_back(style.parent.name);
-                        names.push_back(name);
-                        graph[style.parent.name].insert(name);
+                        parents.insert(style.parent.name);
+                        stylesToVisit.push(style.parent.name);
                     }
                 });
             }
         }
     }
 
-    std::sort(names.begin(), names.end());
-    auto it1 = std::unique(names.begin(), names.end());
-    names.resize(std::distance(names.begin(), it1));
+    std::vector<ResourceName> names;
+    for (const auto& entry : graph) {
+        names.push_back(entry.first);
+    }
 
     std::cout << "digraph styles {\n";
-
     for (const auto& name : names) {
         std::cout << "  node_" << getNodeIndex(names, name)
-                  << " [label=\"" << name.entry << "\"];\n";
+                  << " [label=\"" << name << "\"];\n";
     }
 
     for (const auto& entry : graph) {
-        const ResourceName& parent = entry.first;
-        size_t parentNodeIndex = getNodeIndex(names, parent);
+        const ResourceName& styleName = entry.first;
+        size_t styleNodeIndex = getNodeIndex(names, styleName);
 
-        for (const auto& childName : entry.second) {
-            std::cout << "node_" << getNodeIndex(names, childName) << " -> "
-                      << "node_" << parentNodeIndex << ";\n";
+        for (const auto& parentName : entry.second) {
+            std::cout << "  node_" << styleNodeIndex << " -> "
+                      << "node_" << getNodeIndex(names, parentName) << ";\n";
         }
     }
 
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 84ae40f..cdb3dcb 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -17,6 +17,7 @@
 #ifndef AAPT_DEBUG_H
 #define AAPT_DEBUG_H
 
+#include "Resource.h"
 #include "ResourceTable.h"
 
 #include <memory>
@@ -25,7 +26,8 @@
 
 struct Debug {
     static void printTable(const std::shared_ptr<ResourceTable>& table);
-    static void printStyleGraph(const std::shared_ptr<ResourceTable>& table);
+    static void printStyleGraph(const std::shared_ptr<ResourceTable>& table,
+                                const ResourceName& targetStyle);
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/Flag.cpp b/tools/aapt2/Flag.cpp
index 0f63c2c..76985da 100644
--- a/tools/aapt2/Flag.cpp
+++ b/tools/aapt2/Flag.cpp
@@ -13,7 +13,7 @@
 struct Flag {
     std::string name;
     std::string description;
-    std::function<void(const StringPiece&)> action;
+    std::function<bool(const StringPiece&, std::string*)> action;
     bool required;
     bool* flagResult;
     bool flagValueWhenSet;
@@ -23,22 +23,38 @@
 static std::vector<Flag> sFlags;
 static std::vector<std::string> sArgs;
 
+static std::function<bool(const StringPiece&, std::string*)> wrap(
+        const std::function<void(const StringPiece&)>& action) {
+    return [action](const StringPiece& arg, std::string*) -> bool {
+        action(arg);
+        return true;
+    };
+}
+
 void optionalFlag(const StringPiece& name, const StringPiece& description,
                   std::function<void(const StringPiece&)> action) {
-    sFlags.push_back(
-            Flag{ name.toString(), description.toString(), action, false, nullptr, false, false });
+    sFlags.push_back(Flag{
+            name.toString(), description.toString(), wrap(action),
+            false, nullptr, false, false });
 }
 
 void requiredFlag(const StringPiece& name, const StringPiece& description,
                   std::function<void(const StringPiece&)> action) {
-    sFlags.push_back(
-            Flag{ name.toString(), description.toString(), action, true, nullptr, false, false });
+    sFlags.push_back(Flag{ name.toString(), description.toString(), wrap(action),
+            true, nullptr, false, false });
+}
+
+void requiredFlag(const StringPiece& name, const StringPiece& description,
+                  std::function<bool(const StringPiece&, std::string*)> action) {
+    sFlags.push_back(Flag{ name.toString(), description.toString(), action,
+            true, nullptr, false, false });
 }
 
 void optionalSwitch(const StringPiece& name, const StringPiece& description, bool resultWhenSet,
                     bool* result) {
     sFlags.push_back(Flag{
-            name.toString(), description.toString(), {}, false, result, resultWhenSet, false });
+            name.toString(), description.toString(), {},
+            false, result, resultWhenSet, false });
 }
 
 void usageAndDie(const StringPiece& command) {
@@ -62,6 +78,7 @@
 }
 
 void parse(int argc, char** argv, const StringPiece& command) {
+    std::string errorStr;
     for (int i = 0; i < argc; i++) {
         const StringPiece arg(argv[i]);
         if (*arg.data() != '-') {
@@ -83,7 +100,11 @@
                                   << std::endl;
                         usageAndDie(command);
                     }
-                    flag.action(argv[i]);
+
+                    if (!flag.action(argv[i], &errorStr)) {
+                        std::cerr << errorStr << "." << std::endl << std::endl;
+                        usageAndDie(command);
+                    }
                 }
                 break;
             }
diff --git a/tools/aapt2/Flag.h b/tools/aapt2/Flag.h
index 4745c35..e863742 100644
--- a/tools/aapt2/Flag.h
+++ b/tools/aapt2/Flag.h
@@ -13,6 +13,9 @@
 void requiredFlag(const StringPiece& name, const StringPiece& description,
                   std::function<void(const StringPiece&)> action);
 
+void requiredFlag(const StringPiece& name, const StringPiece& description,
+                  std::function<bool(const StringPiece&, std::string*)> action);
+
 void optionalFlag(const StringPiece& name, const StringPiece& description,
                   std::function<void(const StringPiece&)> action);
 
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index e0977b8..025ede5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -293,6 +293,10 @@
     // referencing attributes defined in a newer SDK
     // level than the style or layout is defined for.
     bool versionStylesAndLayouts = true;
+
+    // The target style that will have it's style hierarchy dumped
+    // when the phase is DumpStyleGraph.
+    ResourceName dumpStyleTarget;
 };
 
 bool compileXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table,
@@ -1001,6 +1005,17 @@
         flag::requiredFlag("-o", "Output path", [&options](const StringPiece& arg) {
             options.output = Source{ arg.toString() };
         });
+    } else if (options.phase == AaptOptions::Phase::DumpStyleGraph) {
+        flag::requiredFlag("--style", "Name of the style to dump",
+                [&options](const StringPiece& arg, std::string* outError) -> bool {
+                    Reference styleReference;
+                    if (!ResourceParser::parseStyleParentReference(util::utf8ToUtf16(arg),
+                                &styleReference, outError)) {
+                        return false;
+                    }
+                    options.dumpStyleTarget = styleReference.name;
+                    return true;
+                });
     }
 
     bool help = false;
@@ -1062,7 +1077,7 @@
         if (options.phase == AaptOptions::Phase::Dump) {
             Debug::printTable(table);
         } else if (options.phase == AaptOptions::Phase::DumpStyleGraph) {
-            Debug::printStyleGraph(table);
+            Debug::printStyleGraph(table, options.dumpStyleTarget);
         }
     }
     return true;