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 "aidl_typenames.h"
18 #include "aidl_language.h"
19 #include "logging.h"
20
21 #include <android-base/file.h>
22 #include <android-base/strings.h>
23
24 #include <map>
25 #include <memory>
26 #include <set>
27 #include <string>
28 #include <utility>
29 #include <vector>
30
31 using android::base::Split;
32
33 using std::make_pair;
34 using std::map;
35 using std::pair;
36 using std::set;
37 using std::string;
38 using std::unique_ptr;
39 using std::vector;
40
41 namespace android {
42 namespace aidl {
43
44 // The built-in AIDL types..
45 static const set<string> kBuiltinTypes = {"void",
46 "boolean",
47 "byte",
48 "char",
49 "int",
50 "long",
51 "float",
52 "double",
53 "String",
54 "List",
55 "Map",
56 "IBinder",
57 "FileDescriptor",
58 "CharSequence",
59 "ParcelFileDescriptor",
60 "ParcelableHolder"};
61
62 static const set<string> kPrimitiveTypes = {"void", "boolean", "byte", "char",
63 "int", "long", "float", "double"};
64
65 // Note: these types may look wrong because they look like Java
66 // types, but they have long been supported from the time when Java
67 // was the only target language of this compiler. They are added here for
68 // backwards compatibility, but we internally treat them as List and Map,
69 // respectively.
70 static const map<string, string> kJavaLikeTypeToAidlType = {
71 {"java.util.List", "List"},
72 {"java.util.Map", "Map"},
73 {"android.os.ParcelFileDescriptor", "ParcelFileDescriptor"},
74 };
75
76 // Package name and type name can't be one of these as they are keywords
77 // in Java and C++. Using these names will eventually cause compilation error,
78 // so checking this here is not a must have, but early detection of errors
79 // is always better.
80 static const set<string> kCppOrJavaReservedWord = {
81 "break", "case", "catch", "char", "class", "continue", "default",
82 "do", "double", "else", "enum", "false", "float", "for",
83 "goto", "if", "int", "long", "new", "private", "protected",
84 "public", "return", "short", "static", "switch", "this", "throw",
85 "true", "try", "void", "volatile", "while"};
86
HasValidNameComponents(const AidlDefinedType & defined)87 static bool HasValidNameComponents(const AidlDefinedType& defined) {
88 bool success = true;
89 vector<string> pieces = Split(defined.GetCanonicalName(), ".");
90 for (const string& piece : pieces) {
91 if (kCppOrJavaReservedWord.find(piece) != kCppOrJavaReservedWord.end()) {
92 AIDL_ERROR(defined) << defined.GetCanonicalName() << " is an invalid name because '" << piece
93 << "' is a Java or C++ identifier.";
94 success = false;
95 }
96 // not checking kJavaLikeTypeToAidl, since that wouldn't make sense here
97 if (kBuiltinTypes.find(piece) != kBuiltinTypes.end()) {
98 AIDL_ERROR(defined) << defined.GetCanonicalName() << " is an invalid name because '" << piece
99 << "' is a built-in AIDL type.";
100 success = false;
101 }
102 }
103 return success;
104 }
105
IsIgnorableImport(const string & import) const106 bool AidlTypenames::IsIgnorableImport(const string& import) const {
107 if (IsBuiltinTypename(import)) return true;
108
109 static set<string> ignore_import = {
110 "android.os.IInterface", "android.os.IBinder", "android.os.Parcelable", "android.os.Parcel",
111 "android.content.Context", "java.lang.String", "java.lang.CharSequence"};
112 // these known built-in types don't need to be imported
113 if (ignore_import.find(import) != ignore_import.end()) return true;
114
115 if (TryGetDefinedType(import)) return true;
116
117 return false;
118 }
119
120 // Add a parsed document and populate type names in it.
121 // Name conflict is an error unless one of them is from preprocessed.
122 // For legacy, we populate unqualified names from preprocessed unstructured parcelable types
123 // so that they can be referenced via a simple name.
AddDocument(std::unique_ptr<AidlDocument> doc)124 bool AidlTypenames::AddDocument(std::unique_ptr<AidlDocument> doc) {
125 bool is_preprocessed = doc->IsPreprocessed();
126 std::vector<AidlDefinedType*> types_to_add;
127 // Add types in two steps to avoid adding a type while the doc is rejected.
128 // 1. filter types to add
129 // 2. add types
130
131 std::function<bool(const std::vector<std::unique_ptr<AidlDefinedType>>&)> collect_types_to_add;
132 collect_types_to_add = [&](auto& types) {
133 for (const auto& type : types) {
134 if (IsBuiltinTypename(type->GetName())) {
135 // ParcelFileDescriptor is treated as a built-in type, but it's also in the framework.aidl.
136 // So aidl should ignore built-in types in framework.aidl to prevent duplication.
137 // (b/130899491)
138 if (is_preprocessed) {
139 continue;
140 }
141 // HasValidNameComponents handles name conflicts with built-in types
142 }
143
144 if (auto prev_definition = defined_types_.find(type->GetCanonicalName());
145 prev_definition != defined_types_.end()) {
146 // Skip duplicate type in preprocessed document
147 if (is_preprocessed) {
148 continue;
149 }
150 // Overwrite duplicate type which is already added via preprocessed with a new one
151 if (!prev_definition->second->GetDocument().IsPreprocessed()) {
152 AIDL_ERROR(type) << "redefinition: " << type->GetCanonicalName() << " is defined "
153 << prev_definition->second->GetLocation();
154 return false;
155 }
156 }
157
158 if (!HasValidNameComponents(*type)) {
159 return false;
160 }
161
162 types_to_add.push_back(type.get());
163
164 // recursively check nested types
165 if (!collect_types_to_add(type->GetNestedTypes())) {
166 return false;
167 }
168 }
169 return true;
170 };
171
172 if (!collect_types_to_add(doc->DefinedTypes())) {
173 return false;
174 }
175
176 for (const auto& type : types_to_add) {
177 // populate global 'type' namespace with fully-qualified names
178 defined_types_.emplace(type->GetCanonicalName(), type);
179 // preprocessed unstructured parcelable types can be referenced without qualification
180 if (is_preprocessed && type->AsUnstructuredParcelable()) {
181 defined_types_.emplace(type->GetName(), type);
182 }
183 }
184
185 // transfer ownership of document
186 documents_.push_back(std::move(doc));
187 return true;
188 }
189
MainDocument() const190 const AidlDocument& AidlTypenames::MainDocument() const {
191 AIDL_FATAL_IF(documents_.size() == 0, AIDL_LOCATION_HERE) << "Main document doesn't exist";
192 return *(documents_[0]);
193 }
194
IsBuiltinTypename(const string & type_name)195 bool AidlTypenames::IsBuiltinTypename(const string& type_name) {
196 return kBuiltinTypes.find(type_name) != kBuiltinTypes.end() ||
197 kJavaLikeTypeToAidlType.find(type_name) != kJavaLikeTypeToAidlType.end();
198 }
199
IsPrimitiveTypename(const string & type_name)200 bool AidlTypenames::IsPrimitiveTypename(const string& type_name) {
201 return kPrimitiveTypes.find(type_name) != kPrimitiveTypes.end();
202 }
203
IsParcelable(const string & type_name) const204 bool AidlTypenames::IsParcelable(const string& type_name) const {
205 if (IsBuiltinTypename(type_name)) {
206 return type_name == "ParcelableHolder" || type_name == "ParcelFileDescriptor";
207 }
208 if (auto defined_type = TryGetDefinedType(type_name); defined_type) {
209 return defined_type->AsParcelable() != nullptr;
210 }
211 return false;
212 }
213
TryGetDefinedType(const string & type_name) const214 const AidlDefinedType* AidlTypenames::TryGetDefinedType(const string& type_name) const {
215 auto found_def = defined_types_.find(type_name);
216 if (found_def != defined_types_.end()) {
217 return found_def->second;
218 }
219 return nullptr;
220 }
221
AllDefinedTypes() const222 std::vector<const AidlDefinedType*> AidlTypenames::AllDefinedTypes() const {
223 std::vector<const AidlDefinedType*> res;
224 for (const auto& doc : AllDocuments()) {
225 VisitTopDown(
226 [&](const AidlNode& node) {
227 if (auto defined_type = AidlCast<AidlDefinedType>(node); defined_type) {
228 res.push_back(defined_type);
229 }
230 },
231 *doc);
232 }
233 return res;
234 }
235
ResolveTypename(const string & type_name) const236 AidlTypenames::ResolvedTypename AidlTypenames::ResolveTypename(const string& type_name) const {
237 if (IsBuiltinTypename(type_name)) {
238 auto found = kJavaLikeTypeToAidlType.find(type_name);
239 if (found != kJavaLikeTypeToAidlType.end()) {
240 return {found->second, true, nullptr};
241 }
242 return {type_name, true, nullptr};
243 }
244 const AidlDefinedType* defined_type = TryGetDefinedType(type_name);
245 if (defined_type != nullptr) {
246 return {defined_type->GetCanonicalName(), true, defined_type};
247 } else {
248 return {type_name, false, nullptr};
249 }
250 }
251
MakeResolvedType(const AidlLocation & location,const string & name,bool is_array) const252 std::unique_ptr<AidlTypeSpecifier> AidlTypenames::MakeResolvedType(const AidlLocation& location,
253 const string& name,
254 bool is_array) const {
255 std::optional<ArrayType> array;
256 if (is_array) {
257 array = DynamicArray{};
258 }
259 std::unique_ptr<AidlTypeSpecifier> type(
260 new AidlTypeSpecifier(location, name, std::move(array), nullptr, {}));
261 AIDL_FATAL_IF(!type->Resolve(*this, nullptr), type) << "Can't make unknown type: " << name;
262 type->MarkVisited();
263 return type;
264 }
265
266 // Only immutable Parcelable, primitive type, and String, and List, Map, array of the types can be
267 // immutable.
CanBeJavaOnlyImmutable(const AidlTypeSpecifier & type) const268 bool AidlTypenames::CanBeJavaOnlyImmutable(const AidlTypeSpecifier& type) const {
269 const string& name = type.GetName();
270 if (type.IsGeneric()) {
271 if (type.GetName() == "List" || type.GetName() == "Map") {
272 const auto& types = type.GetTypeParameters();
273 return std::all_of(types.begin(), types.end(),
274 [this](const auto& t) { return CanBeJavaOnlyImmutable(*t); });
275 }
276 AIDL_ERROR(type) << "For a generic type, an immutable parcelable can contain only List or Map.";
277 return false;
278 }
279 if (IsPrimitiveTypename(name) || name == "String") {
280 return true;
281 }
282 const AidlDefinedType* t = TryGetDefinedType(type.GetName());
283 if (t == nullptr) {
284 AIDL_ERROR(type) << "An immutable parcelable can contain only immutable Parcelable, primitive "
285 "type, and String.";
286 return false;
287 }
288 if (t->AsEnumDeclaration()) {
289 return true;
290 }
291 return t->IsJavaOnlyImmutable();
292 }
293
294 // Followings can be FixedSize:
295 // - @FixedSize parcelables
296 // - primitive types and enum types
297 // - fixed-size arrays of FixedSize types
CanBeFixedSize(const AidlTypeSpecifier & type) const298 bool AidlTypenames::CanBeFixedSize(const AidlTypeSpecifier& type) const {
299 const string& name = type.GetName();
300 if (type.IsGeneric() || type.IsNullable()) {
301 return false;
302 }
303 if (type.IsArray() && !type.IsFixedSizeArray()) {
304 return false;
305 }
306 if (IsPrimitiveTypename(name)) {
307 return true;
308 }
309 if (IsBuiltinTypename(name)) {
310 return false;
311 }
312 const AidlDefinedType* t = TryGetDefinedType(type.GetName());
313 AIDL_FATAL_IF(t == nullptr, type)
314 << "Failed to look up type. Cannot determine if it can be fixed size: " << type.GetName();
315
316 if (t->AsEnumDeclaration()) {
317 return true;
318 }
319 return t->IsFixedSize();
320 }
321
IsList(const AidlTypeSpecifier & type)322 bool AidlTypenames::IsList(const AidlTypeSpecifier& type) {
323 return type.GetName() == "List";
324 }
325
GetArgumentAspect(const AidlTypeSpecifier & type) const326 ArgumentAspect AidlTypenames::GetArgumentAspect(const AidlTypeSpecifier& type) const {
327 if (type.IsArray()) {
328 return {"array",
329 {AidlArgument::Direction::IN_DIR, AidlArgument::Direction::OUT_DIR,
330 AidlArgument::Direction::INOUT_DIR}};
331 }
332 const string& name = type.GetName();
333 if (IsBuiltinTypename(name)) {
334 if (name == "List" || name == "Map") {
335 return {name,
336 {AidlArgument::Direction::IN_DIR, AidlArgument::Direction::OUT_DIR,
337 AidlArgument::Direction::INOUT_DIR}};
338 } else if (name == "ParcelFileDescriptor") {
339 // "out ParcelFileDescriptor" is not allowed because ParcelFileDescriptor is not
340 // default-constructible.
341 return {name, {AidlArgument::Direction::IN_DIR, AidlArgument::Direction::INOUT_DIR}};
342 } else if (name == "ParcelableHolder") {
343 // TODO(b/156872582): Support it when ParcelableHolder supports every backend.
344 return {name, {}};
345 } else {
346 return {name, {AidlArgument::Direction::IN_DIR}};
347 }
348 }
349
350 const AidlDefinedType* t = TryGetDefinedType(name);
351 AIDL_FATAL_IF(t == nullptr, type) << "Unrecognized type: '" << name << "'";
352
353 // An 'out' field is passed as an argument, so it doesn't make sense if it is immutable.
354 if (t->AsParcelable() != nullptr) {
355 if (t->IsJavaOnlyImmutable()) {
356 return {"@JavaOnlyImmutable", {AidlArgument::Direction::IN_DIR}};
357 }
358 return {"parcelable/union",
359 {AidlArgument::Direction::IN_DIR, AidlArgument::Direction::OUT_DIR,
360 AidlArgument::Direction::INOUT_DIR}};
361 }
362
363 return {t->GetPreprocessDeclarationName(), {AidlArgument::Direction::IN_DIR}};
364 }
365
GetEnumDeclaration(const AidlTypeSpecifier & type) const366 const AidlEnumDeclaration* AidlTypenames::GetEnumDeclaration(const AidlTypeSpecifier& type) const {
367 if (auto defined_type = TryGetDefinedType(type.GetName()); defined_type != nullptr) {
368 if (auto enum_decl = defined_type->AsEnumDeclaration(); enum_decl != nullptr) {
369 return enum_decl;
370 }
371 }
372 return nullptr;
373 }
374
GetInterface(const AidlTypeSpecifier & type) const375 const AidlInterface* AidlTypenames::GetInterface(const AidlTypeSpecifier& type) const {
376 if (auto defined_type = TryGetDefinedType(type.GetName()); defined_type != nullptr) {
377 if (auto intf = defined_type->AsInterface(); intf != nullptr) {
378 return intf;
379 }
380 }
381 return nullptr;
382 }
383
GetParcelable(const AidlTypeSpecifier & type) const384 const AidlParcelable* AidlTypenames::GetParcelable(const AidlTypeSpecifier& type) const {
385 if (auto defined_type = TryGetDefinedType(type.GetName()); defined_type != nullptr) {
386 if (auto parcelable = defined_type->AsParcelable(); parcelable != nullptr) {
387 return parcelable;
388 }
389 }
390 return nullptr;
391 }
392
IterateTypes(const std::function<void (const AidlDefinedType &)> & body) const393 void AidlTypenames::IterateTypes(const std::function<void(const AidlDefinedType&)>& body) const {
394 for (const auto& kv : defined_types_) {
395 body(*kv.second);
396 }
397 }
398
Autofill() const399 bool AidlTypenames::Autofill() const {
400 bool success = true;
401 IterateTypes([&](const AidlDefinedType& type) {
402 // BackingType is filled in for all known enums, including imported enums,
403 // because other types that may use enums, such as Interface or
404 // StructuredParcelable, need to know the enum BackingType when
405 // generating code.
406 if (auto enum_decl = const_cast<AidlDefinedType&>(type).AsEnumDeclaration(); enum_decl) {
407 if (!enum_decl->Autofill(*this)) {
408 success = false;
409 }
410 }
411 });
412 return success;
413 }
414
415 } // namespace aidl
416 } // namespace android
417