xref: /aosp_15_r20/external/stg/type_normalisation.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2023-2024 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License.  You may obtain a copy of the License at
9 //
10 //     https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Aleksei Vetrov
19 
20 #include "type_normalisation.h"
21 
22 #include <map>
23 #include <string>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <vector>
27 
28 #include "graph.h"
29 
30 namespace stg {
31 
32 namespace {
33 
34 struct ResolveQualifiedChain {
ResolveQualifiedChainstg::__anon694f6cb90111::ResolveQualifiedChain35   ResolveQualifiedChain(const Graph& graph,
36                         std::unordered_map<Id, Id>& resolved)
37       : graph(graph), resolved(resolved) {}
38 
operator ()stg::__anon694f6cb90111::ResolveQualifiedChain39   Id operator()(Id node_id) {
40     return graph.Apply(*this, node_id, node_id);
41   }
42 
operator ()stg::__anon694f6cb90111::ResolveQualifiedChain43   Id operator()(const Qualified& x, Id node_id) {
44     auto [it, emplaced] = resolved.emplace(node_id, Id::kInvalid);
45     if (!emplaced) {
46       Check(it->second != Id::kInvalid) << "qualified cycle detected";
47       return it->second;
48     }
49     return it->second = (*this)(x.qualified_type_id);
50   }
51 
52   template <typename Node>
operator ()stg::__anon694f6cb90111::ResolveQualifiedChain53   Id operator()(const Node&, Id node_id) {
54     return node_id;
55   }
56 
57   const Graph& graph;
58   std::unordered_map<Id, Id>& resolved;
59 };
60 
61 // Traverse rooted graph and produce mapping from qualified type to
62 // non-qualified. Produced keys should not intersect with values.
63 // It also collects all functions seen during traversal.
64 struct FindQualifiedTypesAndFunctions {
FindQualifiedTypesAndFunctionsstg::__anon694f6cb90111::FindQualifiedTypesAndFunctions65   FindQualifiedTypesAndFunctions(const Graph& graph,
66                                  std::unordered_map<Id, Id>& resolved,
67                                  std::unordered_set<Id>& functions)
68       : graph(graph),
69         resolved(resolved),
70         functions(functions),
71         resolve_qualified_chain(graph, resolved) {}
72 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions73   void operator()(Id id) {
74     if (seen.insert(id).second) {
75       graph.Apply(*this, id, id);
76     }
77   }
78 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions79   void operator()(const std::vector<Id>& ids) {
80     for (const auto& id : ids) {
81       (*this)(id);
82     }
83   }
84 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions85   void operator()(const std::map<std::string, Id>& x) {
86     for (const auto& [_, id] : x) {
87       (*this)(id);
88     }
89   }
90 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions91   void operator()(const Special&, Id) {}
92 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions93   void operator()(const PointerReference& x, Id) {
94     (*this)(x.pointee_type_id);
95   }
96 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions97   void operator()(const PointerToMember& x, Id) {
98     (*this)(x.containing_type_id);
99     (*this)(x.pointee_type_id);
100   }
101 
102   // Typedefs are not considered when looking for useless qualifiers.
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions103   void operator()(const Typedef& x, Id) {
104     (*this)(x.referred_type_id);
105   }
106 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions107   void operator()(const Qualified&, Id node_id) {
108     (*this)(resolve_qualified_chain(node_id));
109   }
110 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions111   void operator()(const Primitive&, Id) {}
112 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions113   void operator()(const Array& x, Id) {
114     (*this)(x.element_type_id);
115   }
116 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions117   void operator()(const BaseClass& x, Id) {
118     (*this)(x.type_id);
119   }
120 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions121   void operator()(const Method& x, Id) {
122     (*this)(x.type_id);
123   }
124 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions125   void operator()(const Member& x, Id) {
126     (*this)(x.type_id);
127   }
128 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions129   void operator()(const VariantMember& x, Id) {
130     (*this)(x.type_id);
131   }
132 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions133   void operator()(const StructUnion& x, Id) {
134     if (x.definition.has_value()) {
135       auto& definition = x.definition.value();
136       (*this)(definition.base_classes);
137       (*this)(definition.methods);
138       (*this)(definition.members);
139     }
140   }
141 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions142   void operator()(const Enumeration& x, Id) {
143     if (x.definition.has_value()) {
144       (*this)(x.definition->underlying_type_id);
145     }
146   }
147 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions148   void operator()(const Variant& x, Id) {
149     if (x.discriminant.has_value()) {
150       (*this)(x.discriminant.value());
151     }
152     (*this)(x.members);
153   }
154 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions155   void operator()(const Function& x, Id node_id) {
156     functions.emplace(node_id);
157     for (auto& id : x.parameters) {
158       (*this)(id);
159     }
160     (*this)(x.return_type_id);
161   }
162 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions163   void operator()(const ElfSymbol& x, Id) {
164     if (x.type_id) {
165       (*this)(*x.type_id);
166     }
167   }
168 
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions169   void operator()(const Interface& x, Id) {
170     (*this)(x.symbols);
171     (*this)(x.types);
172   }
173 
174   const Graph& graph;
175   std::unordered_map<Id, Id>& resolved;
176   std::unordered_set<Id>& functions;
177   std::unordered_set<Id> seen;
178   ResolveQualifiedChain resolve_qualified_chain;
179 };
180 
181 // Remove qualifiers from function parameters and return type.
182 // "resolved" mapping should have resolutions from qualified type to
183 // non-qualified. Thus, keys and values should not intersect.
184 struct RemoveFunctionQualifiers {
RemoveFunctionQualifiersstg::__anon694f6cb90111::RemoveFunctionQualifiers185   RemoveFunctionQualifiers(Graph& graph,
186                            const std::unordered_map<Id, Id>& resolved)
187       : graph(graph), resolved(resolved) {}
188 
operator ()stg::__anon694f6cb90111::RemoveFunctionQualifiers189   void operator()(Id id) {
190     graph.Apply(*this, id);
191   }
192 
operator ()stg::__anon694f6cb90111::RemoveFunctionQualifiers193   void operator()(Function& x) {
194     for (auto& id : x.parameters) {
195       RemoveQualifiers(id);
196     }
197     RemoveQualifiers(x.return_type_id);
198   }
199 
200   template<typename Node>
operator ()stg::__anon694f6cb90111::RemoveFunctionQualifiers201   void operator()(Node&) {
202     Die() << "only functions should have qualifiers substituted";
203   }
204 
RemoveQualifiersstg::__anon694f6cb90111::RemoveFunctionQualifiers205   void RemoveQualifiers(Id& id) {
206     const auto it = resolved.find(id);
207     if (it != resolved.end()) {
208       id = it->second;
209       Check(!resolved.contains(id)) << "qualifier was resolved to qualifier";
210     }
211   }
212 
213   Graph& graph;
214   const std::unordered_map<Id, Id>& resolved;
215 };
216 
217 }  // namespace
218 
RemoveUselessQualifiers(Graph & graph,Id root)219 Id RemoveUselessQualifiers(Graph& graph, Id root) {
220   std::unordered_map<Id, Id> resolved;
221   std::unordered_set<Id> functions;
222   FindQualifiedTypesAndFunctions(graph, resolved, functions)(root);
223 
224   RemoveFunctionQualifiers remove_qualifiers(graph, resolved);
225   for (const auto& id : functions) {
226     remove_qualifiers(id);
227   }
228   return root;
229 }
230 
231 }  // namespace stg
232