blob: 06bcf2a594e04b7e9437d78ab3fe3e8fc8c3a04c [file] [log] [blame]
/*
* 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.
*/
#include "type_cpp.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <base/stringprintf.h>
#include <base/strings.h>
#include "logging.h"
using std::cerr;
using std::endl;
using std::set;
using std::string;
using std::unique_ptr;
using std::vector;
using android::base::Split;
using android::base::Join;
using android::base::StringPrintf;
namespace android {
namespace aidl {
namespace cpp {
namespace {
const char kNoPackage[] = "";
const char kNoHeader[] = "";
const char kNoValidMethod[] = "";
bool is_cpp_keyword(const std::string& str) {
static const std::vector<std::string> kCppKeywords{
"alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
"bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
"compl", "concept", "const", "constexpr", "const_cast", "continue",
"decltype", "default", "delete", "do", "double", "dynamic_cast", "else",
"enum", "explicit", "export", "extern", "false", "float", "for", "friend",
"goto", "if", "inline", "int", "long", "mutable", "namespace", "new",
"noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
"private", "protected", "public", "register", "reinterpret_cast",
"requires", "return", "short", "signed", "sizeof", "static",
"static_assert", "static_cast", "struct", "switch", "template", "this",
"thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
"union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
"while", "xor", "xor_eq",
};
return std::find(kCppKeywords.begin(), kCppKeywords.end(), str) !=
kCppKeywords.end();
}
class VoidType : public Type {
public:
VoidType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "void",
kNoHeader, "void", kNoValidMethod, kNoValidMethod) {}
virtual ~VoidType() = default;
bool CanBeOutParameter() const override { return false; }
bool CanWriteToParcel() const override { return false; }
}; // class VoidType
class BinderType : public Type {
public:
BinderType(const AidlInterface& interface, const std::string& src_file_name)
: Type(ValidatableType::KIND_GENERATED,
interface.GetPackage(), interface.GetName(),
GetCppHeader(interface), GetCppName(interface),
"readStrongBinder", "writeStrongBinder",
kNoValidMethod, kNoValidMethod,
src_file_name, interface.GetLine()) {}
virtual ~BinderType() = default;
string WriteCast(const string& val) const override {
return Name() + "::asBinder(" + val + ")";
}
private:
static string GetCppName(const AidlInterface& interface) {
vector<string> name = interface.GetSplitPackage();
string ret = "android::sp<";
name.push_back(interface.GetName());
for (const auto& term : name) {
ret += "::" + term;
}
return ret + ">";
}
static string GetCppHeader(const AidlInterface& interface) {
vector<string> name = interface.GetSplitPackage();
name.push_back(interface.GetName());
return Join(name, '/') + ".h";
}
};
class StringListType : public Type {
public:
StringListType()
: Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<String>",
"utils/String16.h", "std::vector<android::String16>",
"readString16Vector", "writeString16Vector") {}
virtual ~StringListType() = default;
bool CanBeOutParameter() const override { return true; }
void GetHeaders(bool is_array, set<string>* headers) const {
if (is_array) {
LOG(FATAL) << "Type checking did not catch that List<String> "
"was marked as array";
}
Type::GetHeaders(is_array, headers);
headers->insert("vector");
}
private:
DISALLOW_COPY_AND_ASSIGN(StringListType);
}; // class StringListType
} // namespace
Type::Type(int kind,
const std::string& package,
const std::string& aidl_type,
const string& header,
const string& cpp_type,
const string& read_method,
const string& write_method,
const string& read_array_method,
const string& write_array_method,
const string& src_file_name,
int line)
: ValidatableType(kind, package, aidl_type, src_file_name, line),
header_(header),
aidl_type_(aidl_type),
cpp_type_(cpp_type),
parcel_read_method_(read_method),
parcel_write_method_(write_method),
parcel_read_array_method_(read_array_method),
parcel_write_array_method_(write_array_method) {}
bool Type::CanBeArray() const { return ! parcel_read_array_method_.empty(); }
bool Type::CanWriteToParcel() const { return true; }
void Type::GetHeaders(bool is_array, set<string>* headers) const {
if (!header_.empty()) {
headers->insert(header_);
}
if (is_array) {
headers->insert("vector");
}
}
string Type::CppType(bool is_array) const {
if (is_array) {
return "std::vector<" + cpp_type_ + ">";
} else {
return cpp_type_;
}
}
const string& Type::ReadFromParcelMethod(bool is_array) const {
if (is_array) {
return parcel_read_array_method_;
} else {
return parcel_read_method_;
}
}
const string& Type::WriteToParcelMethod(bool is_array) const {
if (is_array) {
return parcel_write_array_method_;
} else {
return parcel_write_method_;
}
}
void TypeNamespace::Init() {
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "byte",
"cstdint", "int8_t", "readByte", "writeByte",
"readByteVector", "writeByteVector"));
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "int",
"cstdint", "int32_t", "readInt32", "writeInt32",
"readInt32Vector", "writeInt32Vector"));
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "long",
"cstdint", "int64_t", "readInt64", "writeInt64",
"readInt64Vector", "writeInt64Vector"));
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "float",
kNoHeader, "float", "readFloat", "writeFloat",
"readFloatVector", "writeFloatVector"));
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "double",
kNoHeader, "double", "readDouble", "writeDouble",
"readDoubleVector", "writeDoubleVector"));
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "boolean",
kNoHeader, "bool", "readBool", "writeBool",
"readBoolVector", "writeBoolVector"));
// C++11 defines the char16_t type as a built in for Unicode characters.
Add(new PrimitiveType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "char",
kNoHeader, "char16_t", "readChar", "writeChar",
"readCharVector", "writeCharVector"));
string_type_ = new Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "String",
"utils/String16.h", "android::String16",
"readString16", "writeString16",
"readString16Vector", "writeString16Vector");
Add(string_type_);
void_type_ = new class VoidType();
Add(void_type_);
}
bool TypeNamespace::AddParcelableType(const AidlParcelable* /* p */,
const string& /* filename */) {
// TODO Support parcelables b/23600712
LOG(ERROR) << "Passing parcelables in unimplemented in C++ generation.";
return true;
}
bool TypeNamespace::AddBinderType(const AidlInterface* b,
const string& file_name) {
Add(new BinderType(*b, file_name));
return true;
}
bool TypeNamespace::AddListType(const std::string& type_name) {
const Type* contained_type = Find(type_name);
if (!contained_type) {
LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
"type cannot be found or is invalid.";
return false;
}
if (contained_type->IsCppPrimitive()) {
LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
"type is a primitive in Java and Java List cannot hold "
"primitives.";
return false;
}
if (contained_type == StringType()) {
Add(new StringListType());
return true;
}
// TODO Support lists of parcelables b/23600712
// TODO Support lists of binders b/24470875
LOG(ERROR) << "aidl-cpp does not yet support List<" << type_name << ">";
return false;
}
bool TypeNamespace::AddMapType(const std::string& /* key_type_name */,
const std::string& /* value_type_name */) {
// TODO Support list types b/25242025
LOG(ERROR) << "aidl does not implement support for typed maps!";
return false;
}
bool TypeNamespace::IsValidPackage(const string& package) const {
if (package.empty()) {
return false;
}
auto pieces = Split(package, ".");
for (const string& piece : pieces) {
if (is_cpp_keyword(piece)) {
return false;
}
}
return true;
}
bool TypeNamespace::IsValidArg(const AidlArgument& a,
int arg_index,
const std::string& filename) const {
if (!::android::aidl::TypeNamespace::IsValidArg(a, arg_index, filename)) {
return false;
}
const string error_prefix = StringPrintf(
"In file %s line %d parameter %s (%d):\n ",
filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
// check that the name doesn't match a keyword
if (is_cpp_keyword(a.GetName().c_str())) {
cerr << error_prefix << "Argument name is a C++ keyword"
<< endl;
return false;
}
return true;
}
} // namespace cpp
} // namespace aidl
} // namespace android