blob: 5173b8541943b9729e6bd838ee889ecd228345cb [file] [log] [blame]
Adam Lesinski34a16872018-02-23 16:18:10 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "link/NoDefaultResourceRemover.h"
18
19#include <algorithm>
20
21#include "ResourceTable.h"
22
23namespace aapt {
24
Ryan Mitchella5936052018-05-23 13:31:28 -070025static bool KeepResource(const std::unique_ptr<ResourceEntry>& entry, int minSdk) {
Adam Lesinski34a16872018-02-23 16:18:10 -080026 if (entry->visibility.level == Visibility::Level::kPublic) {
27 // Removing a public API without the developer knowing is bad, so just leave this here for now.
28 return true;
29 }
30
31 if (entry->HasDefaultValue()) {
32 // There is a default value, no removal needed.
33 return true;
34 }
35
36 // There is no default value defined, check if removal is required.
Ryan Mitchella5936052018-05-23 13:31:28 -070037 bool defaultRequired = false;
Adam Lesinski34a16872018-02-23 16:18:10 -080038 for (const auto& config_value : entry->values) {
Ryan Mitchella5936052018-05-23 13:31:28 -070039 const int config = ConfigDescription::DefaultConfig().diff(config_value->config);
40 // If a resource defines a value for a locale-only configuration, the default configuration is
41 // required.
42 if (config == ConfigDescription::CONFIG_LOCALE) {
43 defaultRequired = true;
44 }
45 // If a resource defines a version-only config, the config value can be used as a default if
46 // the version is at most the minimum sdk version
47 else if (config == ConfigDescription::CONFIG_VERSION
48 && config_value->config.sdkVersion <= minSdk) {
49 return true;
50 }
51 // If a resource defines a value for a density only configuration, then that value could be used
52 // as a default and the entry should not be removed
53 else if (config == ConfigDescription::CONFIG_DENSITY
54 || (config == (ConfigDescription::CONFIG_DENSITY | ConfigDescription::CONFIG_VERSION)
55 && config_value->config.sdkVersion <= minSdk)) {
56 return true;
Adam Lesinski34a16872018-02-23 16:18:10 -080057 }
58 }
Ryan Mitchella5936052018-05-23 13:31:28 -070059
60 return !defaultRequired;
Adam Lesinski34a16872018-02-23 16:18:10 -080061}
62
63bool NoDefaultResourceRemover::Consume(IAaptContext* context, ResourceTable* table) {
Adam Lesinski34a16872018-02-23 16:18:10 -080064 for (auto& pkg : table->packages) {
65 for (auto& type : pkg->types) {
Ryan Mitchella5936052018-05-23 13:31:28 -070066 // Gather the entries without defaults that must be removed
67 const int minSdk = context->GetMinSdkVersion();
Adam Lesinski34a16872018-02-23 16:18:10 -080068 const auto end_iter = type->entries.end();
Ryan Mitchella5936052018-05-23 13:31:28 -070069 const auto remove_iter = std::stable_partition(type->entries.begin(), end_iter,
70 [&minSdk](const std::unique_ptr<ResourceEntry>& entry) -> bool {
71 return KeepResource(entry, minSdk);
72 });
73
74 for (auto iter = remove_iter; iter != end_iter; ++iter) {
Adam Lesinski34a16872018-02-23 16:18:10 -080075 const ResourceName name(pkg->name, type->type, (*iter)->name);
76 IDiagnostics* diag = context->GetDiagnostics();
77 diag->Warn(DiagMessage() << "removing resource " << name
78 << " without required default value");
79 if (context->IsVerbose()) {
80 diag->Note(DiagMessage() << " did you forget to remove all definitions?");
81 for (const auto& config_value : (*iter)->values) {
82 if (config_value->value != nullptr) {
83 diag->Note(DiagMessage(config_value->value->GetSource()) << "defined here");
84 }
85 }
86 }
87 }
88
Ryan Mitchella5936052018-05-23 13:31:28 -070089 type->entries.erase(remove_iter, end_iter);
Adam Lesinski34a16872018-02-23 16:18:10 -080090 }
91 }
92 return true;
93}
94
95} // namespace aapt