ProguardRules.cpp revision ca5638fd85098c3d0a699492751043545f75553a
1a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski/*
2a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * Copyright (C) 2015 The Android Open Source Project
3a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski *
4a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * you may not use this file except in compliance with the License.
6a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * You may obtain a copy of the License at
7a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski *
8a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski *
10a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * See the License for the specific language governing permissions and
14a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski * limitations under the License.
15a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski */
16a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
17a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski#include "XmlDom.h"
18a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
19ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include "java/ProguardRules.h"
201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h"
211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
22a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski#include <memory>
23a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski#include <string>
24a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
25a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskinamespace aapt {
26a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskinamespace proguard {
27a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
28a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskiconstexpr const char16_t* kSchemaAndroid = u"http://schemas.android.com/apk/res/android";
29a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
30a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskiclass BaseVisitor : public xml::Visitor {
31a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskipublic:
32a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    BaseVisitor(const Source& source, KeepSet* keepSet) : mSource(source), mKeepSet(keepSet) {
33a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
34a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
35a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Text*) override {};
36a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
37a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Namespace* node) override {
38a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        for (const auto& child : node->children) {
39a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            child->accept(this);
40a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
41a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
42a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
43a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Element* node) override {
44a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (!node->namespaceUri.empty()) {
45a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            Maybe<std::u16string> maybePackage = util::extractPackageFromNamespace(
46a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    node->namespaceUri);
47a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            if (maybePackage) {
48a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                // This is a custom view, let's figure out the class name from this.
49a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                std::u16string package = maybePackage.value() + u"." + node->name;
50a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                if (util::isJavaClassName(package)) {
51a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    addClass(node->lineNumber, package);
52a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                }
53a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            }
54a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        } else if (util::isJavaClassName(node->name)) {
55a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            addClass(node->lineNumber, node->name);
56a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
57a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
58a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        for (const auto& child: node->children) {
59a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            child->accept(this);
60a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
61a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
62a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
63a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskiprotected:
64a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    void addClass(size_t lineNumber, const std::u16string& className) {
651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        mKeepSet->addClass(Source(mSource.path, lineNumber), className);
66a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
67a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
68a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    void addMethod(size_t lineNumber, const std::u16string& methodName) {
691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        mKeepSet->addMethod(Source(mSource.path, lineNumber), methodName);
70a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
71a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
72a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskiprivate:
73a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    Source mSource;
74a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    KeepSet* mKeepSet;
75a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski};
76a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
77a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskistruct LayoutVisitor : public BaseVisitor {
78a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    LayoutVisitor(const Source& source, KeepSet* keepSet) : BaseVisitor(source, keepSet) {
79a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
80a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
81a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Element* node) override {
82a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        bool checkClass = false;
83a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        bool checkName = false;
84a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (node->namespaceUri.empty()) {
85a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            checkClass = node->name == u"view" || node->name == u"fragment";
86a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        } else if (node->namespaceUri == kSchemaAndroid) {
87a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            checkName = node->name == u"fragment";
88a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
89a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
90a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        for (const auto& attr : node->attributes) {
91a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            if (checkClass && attr.namespaceUri.empty() && attr.name == u"class" &&
92a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    util::isJavaClassName(attr.value)) {
93a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                addClass(node->lineNumber, attr.value);
94a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            } else if (checkName && attr.namespaceUri == kSchemaAndroid && attr.name == u"name" &&
95a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    util::isJavaClassName(attr.value)) {
96a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                addClass(node->lineNumber, attr.value);
97a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            } else if (attr.namespaceUri == kSchemaAndroid && attr.name == u"onClick") {
98a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                addMethod(node->lineNumber, attr.value);
99a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            }
100a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
101a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
102a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        BaseVisitor::visit(node);
103a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
104a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski};
105a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
106a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskistruct XmlResourceVisitor : public BaseVisitor {
107a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    XmlResourceVisitor(const Source& source, KeepSet* keepSet) : BaseVisitor(source, keepSet) {
108a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
109a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
110a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Element* node) override {
111a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        bool checkFragment = false;
112a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (node->namespaceUri.empty()) {
113a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            checkFragment = node->name == u"PreferenceScreen" || node->name == u"header";
114a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
115a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
116a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (checkFragment) {
117a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            xml::Attribute* attr = node->findAttribute(kSchemaAndroid, u"fragment");
118a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            if (attr && util::isJavaClassName(attr->value)) {
119a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                addClass(node->lineNumber, attr->value);
120a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            }
121a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
122a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
123a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        BaseVisitor::visit(node);
124a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
125a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski};
126a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
127a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskistruct TransitionVisitor : public BaseVisitor {
128a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    TransitionVisitor(const Source& source, KeepSet* keepSet) : BaseVisitor(source, keepSet) {
129a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
130a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
131a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Element* node) override {
132a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        bool checkClass = node->namespaceUri.empty() &&
133a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                (node->name == u"transition" || node->name == u"pathMotion");
134a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (checkClass) {
135a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            xml::Attribute* attr = node->findAttribute({}, u"class");
136a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            if (attr && util::isJavaClassName(attr->value)) {
137a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                addClass(node->lineNumber, attr->value);
138a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            }
139a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
140a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
141a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        BaseVisitor::visit(node);
142a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
143a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski};
144a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
145a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskistruct ManifestVisitor : public BaseVisitor {
146a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    ManifestVisitor(const Source& source, KeepSet* keepSet) : BaseVisitor(source, keepSet) {
147a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
148a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
149a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    virtual void visit(xml::Element* node) override {
150a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        if (node->namespaceUri.empty()) {
151a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            bool getName = false;
152a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            if (node->name == u"manifest") {
153a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                xml::Attribute* attr = node->findAttribute({}, u"package");
154a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                if (attr) {
155a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    mPackage = attr->value;
156a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                }
157a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            } else if (node->name == u"application") {
158a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                getName = true;
159a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                xml::Attribute* attr = node->findAttribute(kSchemaAndroid, u"backupAgent");
160a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                if (attr) {
161a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    Maybe<std::u16string> result = util::getFullyQualifiedClassName(mPackage,
162a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                                                                                    attr->value);
163a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    if (result) {
164a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                        addClass(node->lineNumber, result.value());
165a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    }
166a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                }
167a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            } else if (node->name == u"activity" || node->name == u"service" ||
168a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    node->name == u"receiver" || node->name == u"provider" ||
169a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    node->name == u"instrumentation") {
170a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                getName = true;
171a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            }
172a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
173a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            if (getName) {
174a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                xml::Attribute* attr = node->findAttribute(kSchemaAndroid, u"name");
175a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                if (attr) {
176a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    Maybe<std::u16string> result = util::getFullyQualifiedClassName(mPackage,
177a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                                                                                    attr->value);
178a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    if (result) {
179a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                        addClass(node->lineNumber, result.value());
180a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                    }
181a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski                }
182a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            }
183a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
184a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        BaseVisitor::visit(node);
185a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
186a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
187a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    std::u16string mPackage;
188a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski};
189a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
1901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool collectProguardRulesForManifest(const Source& source, XmlResource* res, KeepSet* keepSet) {
191a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    ManifestVisitor visitor(source, keepSet);
1921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (res->root) {
1931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        res->root->accept(&visitor);
1941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return true;
1951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return false;
197a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski}
198a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
1991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool collectProguardRules(const Source& source, XmlResource* res, KeepSet* keepSet) {
2001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    if (!res->root) {
2011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return false;
2021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
2041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    switch (res->file.name.type) {
205a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        case ResourceType::kLayout: {
206a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            LayoutVisitor visitor(source, keepSet);
2071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            res->root->accept(&visitor);
208a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            break;
209a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
210a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
211a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        case ResourceType::kXml: {
212a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            XmlResourceVisitor visitor(source, keepSet);
2131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            res->root->accept(&visitor);
214a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            break;
215a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
216a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
217a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        case ResourceType::kTransition: {
218a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            TransitionVisitor visitor(source, keepSet);
2191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            res->root->accept(&visitor);
220a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            break;
221a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
222a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
223a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        default:
224a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            break;
225a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
226a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    return true;
227a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski}
228a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
229a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinskibool writeKeepSet(std::ostream* out, const KeepSet& keepSet) {
230a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    for (const auto& entry : keepSet.mKeepSet) {
2311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        for (const Source& source : entry.second) {
232a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            *out << "// Referenced at " << source << "\n";
233a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
234a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
235a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
236a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
237a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    for (const auto& entry : keepSet.mKeepMethodSet) {
2381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        for (const Source& source : entry.second) {
239a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski            *out << "// Referenced at " << source << "\n";
240a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        }
241a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski        *out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
242a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    }
243a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski    return true;
244a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski}
245a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski
246a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski} // namespace proguard
247a1ad4a812a87642ad259ff4478159e8cc8194680Adam Lesinski} // namespace aapt
248