AAPT2: inferred style parent processing

Change-Id: I8fbc4feef16b6039cf4c526fcfb767dc75a9c131
diff --git a/tools/aapt2/BinaryResourceParser.cpp b/tools/aapt2/BinaryResourceParser.cpp
index bbd21fb..620f0fe 100644
--- a/tools/aapt2/BinaryResourceParser.cpp
+++ b/tools/aapt2/BinaryResourceParser.cpp
@@ -735,8 +735,7 @@
 std::unique_ptr<Style> BinaryResourceParser::parseStyle(const ResourceNameRef& name,
                                                         const ConfigDescription& config,
                                                         const ResTable_map_entry* map) {
-    const bool isWeak = (map->flags & ResTable_entry::FLAG_WEAK) != 0;
-    std::unique_ptr<Style> style = util::make_unique<Style>(isWeak);
+    std::unique_ptr<Style> style = util::make_unique<Style>();
     if (map->parent.ident == 0) {
         // The parent is either not set or it is an unresolved symbol.
         // Check to see if it is a symbol.
diff --git a/tools/aapt2/Linker_test.cpp b/tools/aapt2/Linker_test.cpp
index 66c6717..d897f98 100644
--- a/tools/aapt2/Linker_test.cpp
+++ b/tools/aapt2/Linker_test.cpp
@@ -77,7 +77,7 @@
 }
 
 TEST_F(LinkerTest, EscapeAndConvertRawString) {
-    std::unique_ptr<Style> style = util::make_unique<Style>(false);
+    std::unique_ptr<Style> style = util::make_unique<Style>();
     style->entries.push_back(Style::Entry{
             ResourceNameRef{ u"android", ResourceType::kAttr, u"integer" },
             util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"  123"))
@@ -93,7 +93,7 @@
 }
 
 TEST_F(LinkerTest, FailToConvertRawString) {
-    std::unique_ptr<Style> style = util::make_unique<Style>(false);
+    std::unique_ptr<Style> style = util::make_unique<Style>();
     style->entries.push_back(Style::Entry{
             ResourceNameRef{ u"android", ResourceType::kAttr, u"integer" },
             util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"yo what is up?"))
@@ -105,7 +105,7 @@
 }
 
 TEST_F(LinkerTest, ConvertRawStringToString) {
-    std::unique_ptr<Style> style = util::make_unique<Style>(false);
+    std::unique_ptr<Style> style = util::make_unique<Style>();
     style->entries.push_back(Style::Entry{
             ResourceNameRef{ u"android", ResourceType::kAttr, u"string" },
             util::make_unique<RawString>(
@@ -124,7 +124,7 @@
 }
 
 TEST_F(LinkerTest, ConvertRawStringToFlags) {
-    std::unique_ptr<Style> style = util::make_unique<Style>(false);
+    std::unique_ptr<Style> style = util::make_unique<Style>();
     style->entries.push_back(Style::Entry{
             ResourceNameRef{ u"android", ResourceType::kAttr, u"flags" },
             util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"banana | apple"))
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index f1b7777..e0977b8 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -158,7 +158,6 @@
                         };
 
                         Style& newStyle = static_cast<Style&>(*value.value);
-                        newStyle.weak = true;
 
                         // Move the recorded stripped attributes into this new style.
                         std::move(stripped.begin(), stripped.end(),
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index e7e824c..59915a2 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1163,7 +1163,7 @@
 
 bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& resourceName) {
     const SourceLine source = mSource.line(parser->getLineNumber());
-    std::unique_ptr<Style> style = util::make_unique<Style>(false);
+    std::unique_ptr<Style> style = util::make_unique<Style>();
 
     const auto endAttrIter = parser->endAttributes();
     const auto parentAttrIter = parser->findAttribute(u"", u"parent");
@@ -1181,6 +1181,16 @@
             // If no package is specified, this can not be an alias and is the local package.
             style->parent.name.package = mTable->getPackage();
         }
+    } else {
+        // No parent was specified, so try inferring it from the style name.
+        std::u16string styleName = resourceName.entry.toString();
+        size_t pos = styleName.find_last_of(u'.');
+        if (pos != std::string::npos) {
+            style->parentInferred = true;
+            style->parent.name.package = mTable->getPackage();
+            style->parent.name.type = ResourceType::kStyle;
+            style->parent.name.entry = styleName.substr(0, pos);
+        }
     }
 
     bool success = true;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 00be3bd..3d8a2f0 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -355,6 +355,28 @@
               style->entries[0].key.name);
 }
 
+TEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
+    std::string input = "<style name=\"foo.bar\"/>";
+    ASSERT_TRUE(testParse(input));
+
+    const Style* style = findResource<Style>(ResourceName{
+            u"android", ResourceType::kStyle, u"foo.bar" });
+    ASSERT_NE(style, nullptr);
+    EXPECT_EQ(style->parent.name, (ResourceName{ u"android", ResourceType::kStyle, u"foo" }));
+    EXPECT_TRUE(style->parentInferred);
+}
+
+TEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
+    std::string input = "<style name=\"foo.bar\" parent=\"\"/>";
+    ASSERT_TRUE(testParse(input));
+
+    const Style* style = findResource<Style>(ResourceName{
+            u"android", ResourceType::kStyle, u"foo.bar" });
+    ASSERT_NE(style, nullptr);
+    EXPECT_FALSE(style->parent.name.isValid());
+    EXPECT_FALSE(style->parentInferred);
+}
+
 TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
     std::string input = "<string name=\"foo\">@+id/bar</string>";
     ASSERT_TRUE(testParse(input));
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index be0c3f3..aabb375 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -342,16 +342,10 @@
     }
 }
 
-Style::Style(bool weak) : weak(weak) {
-}
-
-bool Style::isWeak() const {
-    return weak;
-}
-
 Style* Style::clone(StringPool* newPool) const {
-    Style* style = new Style(weak);
+    Style* style = new Style();
     style->parent = parent;
+    style->parentInferred = parentInferred;
     for (auto& entry : entries) {
         style->entries.push_back(Entry{
                 entry.key,
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index b448bd8..ef6594e 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -232,12 +232,16 @@
         std::unique_ptr<Item> value;
     };
 
-    bool weak;
     Reference parent;
+
+    /**
+     * If set to true, the parent was auto inferred from the
+     * style's name.
+     */
+    bool parentInferred = false;
+
     std::vector<Entry> entries;
 
-    Style(bool weak);
-    bool isWeak() const override;
     Style* clone(StringPool* newPool) const override;
     void print(std::ostream& out) const override;
 };
diff --git a/tools/aapt2/XmlFlattener.cpp b/tools/aapt2/XmlFlattener.cpp
index 97e4f68..f78e38d 100644
--- a/tools/aapt2/XmlFlattener.cpp
+++ b/tools/aapt2/XmlFlattener.cpp
@@ -332,6 +332,7 @@
                             elem->styleIndex = attributeIndex;
                         }
                     }
+                    attributeIndex++;
 
                     std::unique_ptr<Item> value;
                     if (entry.attr) {