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