• 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 "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