• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 namespace aapt {
24 
IsDefaultConfigRequired(const ConfigDescription & config)25 static bool IsDefaultConfigRequired(const ConfigDescription& config) {
26   // We don't want to be overzealous with resource removal, so have strict requirements.
27   // If a resource defines a value for a locale-only configuration, the default configuration is
28   // required.
29   if (ConfigDescription::DefaultConfig().diff(config) == ConfigDescription::CONFIG_LOCALE) {
30     return true;
31   }
32   return false;
33 }
34 
KeepResource(const std::unique_ptr<ResourceEntry> & entry)35 static bool KeepResource(const std::unique_ptr<ResourceEntry>& entry) {
36   if (entry->visibility.level == Visibility::Level::kPublic) {
37     // Removing a public API without the developer knowing is bad, so just leave this here for now.
38     return true;
39   }
40 
41   if (entry->HasDefaultValue()) {
42     // There is a default value, no removal needed.
43     return true;
44   }
45 
46   // There is no default value defined, check if removal is required.
47   for (const auto& config_value : entry->values) {
48     if (IsDefaultConfigRequired(config_value->config)) {
49       return false;
50     }
51   }
52   return true;
53 }
54 
Consume(IAaptContext * context,ResourceTable * table)55 bool NoDefaultResourceRemover::Consume(IAaptContext* context, ResourceTable* table) {
56   const ConfigDescription default_config = ConfigDescription::DefaultConfig();
57   for (auto& pkg : table->packages) {
58     for (auto& type : pkg->types) {
59       const auto end_iter = type->entries.end();
60       const auto new_end_iter =
61           std::stable_partition(type->entries.begin(), end_iter, KeepResource);
62       for (auto iter = new_end_iter; iter != end_iter; ++iter) {
63         const ResourceName name(pkg->name, type->type, (*iter)->name);
64         IDiagnostics* diag = context->GetDiagnostics();
65         diag->Warn(DiagMessage() << "removing resource " << name
66                                  << " without required default value");
67         if (context->IsVerbose()) {
68           diag->Note(DiagMessage() << "  did you forget to remove all definitions?");
69           for (const auto& config_value : (*iter)->values) {
70             if (config_value->value != nullptr) {
71               diag->Note(DiagMessage(config_value->value->GetSource()) << "defined here");
72             }
73           }
74         }
75       }
76 
77       type->entries.erase(new_end_iter, type->entries.end());
78     }
79   }
80   return true;
81 }
82 
83 }  // namespace aapt
84