| /* |
| * Copyright (C) 2015, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef AIDL_TYPE_NAMESPACE_H_ |
| #define AIDL_TYPE_NAMESPACE_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include <base/macros.h> |
| |
| #include "aidl_language.h" |
| #include "logging.h" |
| |
| namespace android { |
| namespace aidl { |
| |
| class ValidatableType { |
| public: |
| enum { |
| KIND_BUILT_IN, |
| KIND_PARCELABLE, |
| KIND_INTERFACE, |
| KIND_GENERATED, |
| }; |
| |
| ValidatableType(int kind, |
| const std::string& package, const std::string& type_name, |
| const std::string& decl_file, int decl_line); |
| virtual ~ValidatableType() = default; |
| |
| virtual bool CanBeArray() const = 0; |
| virtual bool CanBeOutParameter() const = 0; |
| virtual bool CanWriteToParcel() const = 0; |
| |
| // Name() returns the short name of an object (without package qualifiers). |
| virtual std::string Name() const { return type_name_; } |
| // QualifiedName() returns the canonical AIDL type, with packages. |
| virtual std::string QualifiedName() const { return canonical_name_; } |
| int Kind() const { return kind_; } |
| std::string HumanReadableKind() const; |
| std::string DeclFile() const { return origin_file_; } |
| int DeclLine() const { return origin_line_; } |
| |
| private: |
| const int kind_; |
| const std::string type_name_; |
| const std::string canonical_name_; |
| const std::string origin_file_; |
| const int origin_line_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ValidatableType); |
| }; |
| |
| class TypeNamespace { |
| public: |
| // Load the TypeNamespace with built in types. Don't do work in the |
| // constructor because many of the useful methods are virtual. |
| virtual void Init() = 0; |
| |
| // Load this TypeNamespace with user defined types. |
| virtual bool AddParcelableType(const AidlParcelable* p, |
| const std::string& filename) = 0; |
| virtual bool AddBinderType(const AidlInterface* b, |
| const std::string& filename) = 0; |
| // We dynamically create container types as we discover them in the parse |
| // tree. Returns false if the contained types cannot be canonicalized. |
| virtual bool AddListType(const std::string& contained_type_name) = 0; |
| virtual bool AddMapType(const std::string& key_type_name, |
| const std::string& value_type_name) = 0; |
| |
| // Add a container type to this namespace. Returns false only |
| // on error. Silently discards requests to add non-container types. |
| virtual bool MaybeAddContainerType(const std::string& type_name); |
| |
| // Returns true iff this has a type for |type_name|. |
| virtual bool HasType(const std::string& type_name) const; |
| |
| // Returns true iff |package| is a valid package name. |
| virtual bool IsValidPackage(const std::string& package) const; |
| |
| // Returns true iff |raw_type| is a valid return type. |
| virtual bool IsValidReturnType(const AidlType& raw_type, |
| const std::string& filename) const; |
| |
| // Returns true iff |arg_type| is a valid method argument. |
| virtual bool IsValidArg(const AidlArgument& a, |
| int arg_index, |
| const std::string& filename) const; |
| |
| // Returns true if this is a container type, rather than a normal type. |
| virtual bool IsContainerType(const std::string& type_name) const; |
| |
| // Returns true iff the name can be canonicalized to a container type. |
| virtual bool CanonicalizeContainerType( |
| const std::string& raw_type_name, |
| std::vector<std::string>* container_class, |
| std::vector<std::string>* contained_type_names) const; |
| |
| protected: |
| TypeNamespace() = default; |
| virtual ~TypeNamespace() = default; |
| |
| // Get a pointer to an existing type. |
| virtual const ValidatableType* GetValidatableType( |
| const std::string& name) const = 0; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TypeNamespace); |
| }; |
| |
| template<typename T> |
| class LanguageTypeNamespace : public TypeNamespace { |
| public: |
| LanguageTypeNamespace() = default; |
| virtual ~LanguageTypeNamespace() = default; |
| |
| // Get a pointer to an existing type. Searches first by fully-qualified |
| // name, and then class name (dropping package qualifiers). |
| const T* Find(const std::string& name) const; |
| |
| protected: |
| bool Add(const T* type); |
| const ValidatableType* GetValidatableType( |
| const std::string& name) const override { return Find(name); } |
| |
| private: |
| std::vector<std::unique_ptr<const T>> types_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LanguageTypeNamespace); |
| }; // class LanguageTypeNamespace |
| |
| template<typename T> |
| bool LanguageTypeNamespace<T>::Add(const T* type) { |
| const T* existing = Find(type->QualifiedName()); |
| if (!existing) { |
| types_.emplace_back(type); |
| return true; |
| } |
| |
| if (existing->Kind() == ValidatableType::KIND_BUILT_IN) { |
| LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine() |
| << " attempt to redefine built in class " |
| << type->QualifiedName(); |
| return false; |
| } |
| |
| if (type->Kind() != existing->Kind()) { |
| LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine() |
| << " attempt to redefine " << type->QualifiedName() |
| << " as " << type->HumanReadableKind(); |
| LOG(ERROR) << existing->DeclFile() << ":" << existing->DeclLine() |
| << " previously defined here as " |
| << existing->HumanReadableKind(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| template<typename T> |
| const T* LanguageTypeNamespace<T>::Find(const std::string& raw_name) const { |
| using std::string; |
| using std::vector; |
| using android::base::Join; |
| using android::base::Trim; |
| |
| string name = Trim(raw_name); |
| if (IsContainerType(name)) { |
| vector<string> container_class; |
| vector<string> contained_type_names; |
| if (!CanonicalizeContainerType(name, &container_class, |
| &contained_type_names)) { |
| return nullptr; |
| } |
| for (string& contained_type_name : contained_type_names) { |
| const T* contained_type = Find(contained_type_name); |
| if (!contained_type) { |
| return nullptr; |
| } |
| contained_type_name = contained_type->QualifiedName(); |
| } |
| name = Join(container_class, '.') + |
| "<" + Join(contained_type_names, ',') + ">"; |
| } |
| |
| const T* ret = nullptr; |
| for (const auto& type : types_) { |
| // Always prefer a exact match if possible. |
| // This works for primitives and class names qualified with a package. |
| if (type->QualifiedName() == name) { |
| ret = type.get(); |
| break; |
| } |
| // We allow authors to drop packages when refering to a class name. |
| if (type->Name() == name) { |
| ret = type.get(); |
| } |
| } |
| |
| return ret; |
| } |
| |
| } // namespace aidl |
| } // namespace android |
| |
| #endif // AIDL_TYPE_NAMESPACE_H_ |