#include "aidl_language.h"
|
#include "aidl_typenames.h"
|
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <algorithm>
|
#include <cassert>
|
#include <iostream>
|
#include <set>
|
#include <sstream>
|
#include <string>
|
#include <utility>
|
|
#include <android-base/parsedouble.h>
|
#include <android-base/parseint.h>
|
#include <android-base/strings.h>
|
|
#include "aidl_language_y.h"
|
#include "logging.h"
|
#include "type_java.h"
|
#include "type_namespace.h"
|
|
#ifdef _WIN32
|
int isatty(int fd)
|
{
|
return (fd == 0);
|
}
|
#endif
|
|
using android::aidl::IoDelegate;
|
using android::base::Join;
|
using android::base::Split;
|
using std::cerr;
|
using std::endl;
|
using std::pair;
|
using std::set;
|
using std::string;
|
using std::unique_ptr;
|
using std::vector;
|
|
void yylex_init(void **);
|
void yylex_destroy(void *);
|
void yyset_in(FILE *f, void *);
|
int yyparse(Parser*);
|
YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *);
|
void yy_delete_buffer(YY_BUFFER_STATE, void *);
|
|
AidlToken::AidlToken(const std::string& text, const std::string& comments)
|
: text_(text),
|
comments_(comments) {}
|
|
AidlLocation::AidlLocation(const std::string& file, Point begin, Point end)
|
: file_(file), begin_(begin), end_(end) {}
|
|
std::ostream& operator<<(std::ostream& os, const AidlLocation& l) {
|
os << l.file_ << ":" << l.begin_.line << "." << l.begin_.column << "-";
|
if (l.begin_.line != l.end_.line) {
|
os << l.end_.line << ".";
|
}
|
os << l.end_.column;
|
return os;
|
}
|
|
AidlNode::AidlNode(const AidlLocation& location) : location_(location) {}
|
|
std::string AidlNode::PrintLocation() const {
|
std::stringstream ss;
|
ss << location_.file_ << ":" << location_.begin_.line;
|
return ss.str();
|
}
|
|
AidlError::AidlError(bool fatal) : os_(std::cerr), fatal_(fatal) {
|
os_ << "ERROR: ";
|
}
|
|
static const string kNullable("nullable");
|
static const string kUtf8InCpp("utf8InCpp");
|
static const string kUnsupportedAppUsage("UnsupportedAppUsage");
|
static const string kSystemApi("SystemApi");
|
static const string kStableParcelable("JavaOnlyStableParcelable");
|
|
static const set<string> kAnnotationNames{kNullable, kUtf8InCpp, kUnsupportedAppUsage, kSystemApi,
|
kStableParcelable};
|
|
AidlAnnotation* AidlAnnotation::Parse(const AidlLocation& location, const string& name) {
|
if (kAnnotationNames.find(name) == kAnnotationNames.end()) {
|
std::ostringstream stream;
|
stream << "'" << name << "' is not a recognized annotation. ";
|
stream << "It must be one of:";
|
for (const string& kv : kAnnotationNames) {
|
stream << " " << kv;
|
}
|
stream << ".";
|
AIDL_ERROR(location) << stream.str();
|
return nullptr;
|
}
|
return new AidlAnnotation(location, name);
|
}
|
|
AidlAnnotation::AidlAnnotation(const AidlLocation& location, const string& name)
|
: AidlNode(location), name_(name) {}
|
|
static bool HasAnnotation(const vector<AidlAnnotation>& annotations, const string& name) {
|
for (const auto& a : annotations) {
|
if (a.GetName() == name) {
|
return true;
|
}
|
}
|
return false;
|
}
|
|
AidlAnnotatable::AidlAnnotatable(const AidlLocation& location) : AidlNode(location) {}
|
|
bool AidlAnnotatable::IsNullable() const {
|
return HasAnnotation(annotations_, kNullable);
|
}
|
|
bool AidlAnnotatable::IsUtf8InCpp() const {
|
return HasAnnotation(annotations_, kUtf8InCpp);
|
}
|
|
bool AidlAnnotatable::IsUnsupportedAppUsage() const {
|
return HasAnnotation(annotations_, kUnsupportedAppUsage);
|
}
|
|
bool AidlAnnotatable::IsSystemApi() const {
|
return HasAnnotation(annotations_, kSystemApi);
|
}
|
|
bool AidlAnnotatable::IsStableParcelable() const {
|
return HasAnnotation(annotations_, kStableParcelable);
|
}
|
|
string AidlAnnotatable::ToString() const {
|
vector<string> ret;
|
for (const auto& a : annotations_) {
|
ret.emplace_back(a.ToString());
|
}
|
std::sort(ret.begin(), ret.end());
|
return Join(ret, " ");
|
}
|
|
AidlTypeSpecifier::AidlTypeSpecifier(const AidlLocation& location, const string& unresolved_name,
|
bool is_array,
|
vector<unique_ptr<AidlTypeSpecifier>>* type_params,
|
const string& comments)
|
: AidlAnnotatable(location),
|
unresolved_name_(unresolved_name),
|
is_array_(is_array),
|
type_params_(type_params),
|
comments_(comments) {}
|
|
AidlTypeSpecifier AidlTypeSpecifier::ArrayBase() const {
|
AIDL_FATAL_IF(!is_array_, this);
|
|
AidlTypeSpecifier arrayBase = *this;
|
arrayBase.is_array_ = false;
|
return arrayBase;
|
}
|
|
string AidlTypeSpecifier::ToString() const {
|
string ret = GetName();
|
if (IsGeneric()) {
|
vector<string> arg_names;
|
for (const auto& ta : GetTypeParameters()) {
|
arg_names.emplace_back(ta->ToString());
|
}
|
ret += "<" + Join(arg_names, ",") + ">";
|
}
|
if (IsArray()) {
|
ret += "[]";
|
}
|
return ret;
|
}
|
|
string AidlTypeSpecifier::Signature() const {
|
string ret = ToString();
|
string annotations = AidlAnnotatable::ToString();
|
if (annotations != "") {
|
ret = annotations + " " + ret;
|
}
|
return ret;
|
}
|
|
bool AidlTypeSpecifier::Resolve(android::aidl::AidlTypenames& typenames) {
|
assert(!IsResolved());
|
pair<string, bool> result = typenames.ResolveTypename(unresolved_name_);
|
if (result.second) {
|
fully_qualified_name_ = result.first;
|
}
|
return result.second;
|
}
|
|
bool AidlTypeSpecifier::CheckValid(const AidlTypenames& typenames) const {
|
if (IsGeneric()) {
|
const string& type_name = GetName();
|
const int num = GetTypeParameters().size();
|
if (type_name == "List") {
|
if (num > 1) {
|
AIDL_ERROR(this) << " List cannot have type parameters more than one, but got "
|
<< "'" << ToString() << "'";
|
return false;
|
}
|
} else if (type_name == "Map") {
|
if (num != 0 && num != 2) {
|
AIDL_ERROR(this) << "Map must have 0 or 2 type parameters, but got "
|
<< "'" << ToString() << "'";
|
return false;
|
}
|
}
|
}
|
|
if (GetName() == "void") {
|
if (IsArray() || IsNullable() || IsUtf8InCpp()) {
|
AIDL_ERROR(this) << "void type cannot be an array or nullable or utf8 string";
|
return false;
|
}
|
}
|
|
if (IsArray()) {
|
const auto definedType = typenames.TryGetDefinedType(GetName());
|
if (definedType != nullptr && definedType->AsInterface() != nullptr) {
|
AIDL_ERROR(this) << "Binder type cannot be an array";
|
return false;
|
}
|
}
|
|
if (IsNullable()) {
|
if (AidlTypenames::IsPrimitiveTypename(GetName()) && !IsArray()) {
|
AIDL_ERROR(this) << "Primitive type cannot get nullable annotation";
|
return false;
|
}
|
}
|
return true;
|
}
|
|
std::string AidlConstantValueDecorator(const AidlTypeSpecifier& /*type*/,
|
const std::string& raw_value) {
|
return raw_value;
|
}
|
|
AidlVariableDeclaration::AidlVariableDeclaration(const AidlLocation& location,
|
AidlTypeSpecifier* type, const std::string& name)
|
: AidlVariableDeclaration(location, type, name, nullptr /*default_value*/) {}
|
|
AidlVariableDeclaration::AidlVariableDeclaration(const AidlLocation& location,
|
AidlTypeSpecifier* type, const std::string& name,
|
AidlConstantValue* default_value)
|
: AidlNode(location), type_(type), name_(name), default_value_(default_value) {}
|
|
bool AidlVariableDeclaration::CheckValid(const AidlTypenames& typenames) const {
|
bool valid = true;
|
valid &= type_->CheckValid(typenames);
|
|
if (default_value_ == nullptr) return valid;
|
valid &= default_value_->CheckValid();
|
|
if (!valid) return false;
|
|
return !ValueString(AidlConstantValueDecorator).empty();
|
}
|
|
string AidlVariableDeclaration::ToString() const {
|
string ret = type_->Signature() + " " + name_;
|
if (default_value_ != nullptr) {
|
ret += " = " + ValueString(AidlConstantValueDecorator);
|
}
|
return ret;
|
}
|
|
string AidlVariableDeclaration::Signature() const {
|
return type_->Signature() + " " + name_;
|
}
|
|
std::string AidlVariableDeclaration::ValueString(const ConstantValueDecorator& decorator) const {
|
if (default_value_ != nullptr) {
|
return GetDefaultValue()->As(GetType(), decorator);
|
} else {
|
return "";
|
}
|
}
|
|
AidlArgument::AidlArgument(const AidlLocation& location, AidlArgument::Direction direction,
|
AidlTypeSpecifier* type, const std::string& name)
|
: AidlVariableDeclaration(location, type, name),
|
direction_(direction),
|
direction_specified_(true) {}
|
|
AidlArgument::AidlArgument(const AidlLocation& location, AidlTypeSpecifier* type,
|
const std::string& name)
|
: AidlVariableDeclaration(location, type, name),
|
direction_(AidlArgument::IN_DIR),
|
direction_specified_(false) {}
|
|
string AidlArgument::GetDirectionSpecifier() const {
|
string ret;
|
if (direction_specified_) {
|
switch(direction_) {
|
case AidlArgument::IN_DIR:
|
ret += "in ";
|
break;
|
case AidlArgument::OUT_DIR:
|
ret += "out ";
|
break;
|
case AidlArgument::INOUT_DIR:
|
ret += "inout ";
|
break;
|
}
|
}
|
return ret;
|
}
|
|
string AidlArgument::ToString() const {
|
return GetDirectionSpecifier() + AidlVariableDeclaration::ToString();
|
}
|
|
std::string AidlArgument::Signature() const {
|
class AidlInterface;
|
class AidlInterface;
|
class AidlParcelable;
|
class AidlStructuredParcelable;
|
class AidlParcelable;
|
class AidlStructuredParcelable;
|
return GetDirectionSpecifier() + AidlVariableDeclaration::Signature();
|
}
|
|
AidlMember::AidlMember(const AidlLocation& location) : AidlNode(location) {}
|
|
AidlConstantValue::AidlConstantValue(const AidlLocation& location, Type type,
|
const std::string& checked_value)
|
: AidlNode(location), type_(type), value_(checked_value) {
|
CHECK(!value_.empty() || type_ == Type::ERROR);
|
CHECK(type_ != Type::ARRAY);
|
}
|
|
AidlConstantValue::AidlConstantValue(const AidlLocation& location, Type type,
|
std::vector<std::unique_ptr<AidlConstantValue>>* values)
|
: AidlNode(location), type_(type), values_(std::move(*values)) {}
|
|
static bool isValidLiteralChar(char c) {
|
return !(c <= 0x1f || // control characters are < 0x20
|
c >= 0x7f || // DEL is 0x7f
|
c == '\\'); // Disallow backslashes for future proofing.
|
}
|
|
AidlConstantValue* AidlConstantValue::Boolean(const AidlLocation& location, bool value) {
|
return new AidlConstantValue(location, Type::BOOLEAN, value ? "true" : "false");
|
}
|
|
AidlConstantValue* AidlConstantValue::Character(const AidlLocation& location, char value) {
|
if (!isValidLiteralChar(value)) {
|
AIDL_ERROR(location) << "Invalid character literal " << value;
|
return new AidlConstantValue(location, Type::ERROR, "");
|
}
|
return new AidlConstantValue(location, Type::CHARACTER, std::string("'") + value + "'");
|
}
|
|
AidlConstantValue* AidlConstantValue::Floating(const AidlLocation& location,
|
const std::string& value) {
|
return new AidlConstantValue(location, Type::FLOATING, value);
|
}
|
|
AidlConstantValue* AidlConstantValue::Hex(const AidlLocation& location, const std::string& value) {
|
return new AidlConstantValue(location, Type::HEXIDECIMAL, value);
|
}
|
|
AidlConstantValue* AidlConstantValue::Integral(const AidlLocation& location,
|
const std::string& value) {
|
return new AidlConstantValue(location, Type::INTEGRAL, value);
|
}
|
|
AidlConstantValue* AidlConstantValue::Array(
|
const AidlLocation& location, std::vector<std::unique_ptr<AidlConstantValue>>* values) {
|
return new AidlConstantValue(location, Type::ARRAY, values);
|
}
|
|
AidlConstantValue* AidlConstantValue::String(const AidlLocation& location,
|
const std::string& value) {
|
for (size_t i = 0; i < value.length(); ++i) {
|
if (!isValidLiteralChar(value[i])) {
|
AIDL_ERROR(location) << "Found invalid character at index " << i << " in string constant '"
|
<< value << "'";
|
return new AidlConstantValue(location, Type::ERROR, "");
|
}
|
}
|
|
return new AidlConstantValue(location, Type::STRING, value);
|
}
|
|
bool AidlConstantValue::CheckValid() const {
|
// error always logged during creation
|
return type_ != AidlConstantValue::Type::ERROR;
|
}
|
|
static string TrimIfSuffix(const string& str, const string& suffix) {
|
if (str.size() > suffix.size() &&
|
0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix)) {
|
return str.substr(0, str.size() - suffix.size());
|
}
|
return str;
|
}
|
|
string AidlConstantValue::As(const AidlTypeSpecifier& type,
|
const ConstantValueDecorator& decorator) const {
|
if (type.IsGeneric()) {
|
AIDL_ERROR(type) << "Generic type cannot be specified with a constant literal.";
|
return "";
|
}
|
|
const std::string& type_string = type.GetName();
|
|
if ((type_ == Type::ARRAY) != type.IsArray()) {
|
goto mismatch_error;
|
}
|
|
switch (type_) {
|
case AidlConstantValue::Type::ARRAY: {
|
vector<string> raw_values;
|
raw_values.reserve(values_.size());
|
|
bool success = true;
|
for (const auto& value : values_) {
|
const AidlTypeSpecifier& array_base = type.ArrayBase();
|
const std::string raw_value = value->As(array_base, decorator);
|
|
success &= !raw_value.empty();
|
raw_values.push_back(decorator(array_base, raw_value));
|
}
|
if (!success) {
|
AIDL_ERROR(this) << "Default value must be a literal array of " << type_string << ".";
|
return "";
|
}
|
return decorator(type, "{" + Join(raw_values, ", ") + "}");
|
}
|
case AidlConstantValue::Type::BOOLEAN:
|
if (type_string == "boolean") return decorator(type, value_);
|
goto mismatch_error;
|
case AidlConstantValue::Type::CHARACTER:
|
if (type_string == "char") return decorator(type, value_);
|
goto mismatch_error;
|
case AidlConstantValue::Type::FLOATING: {
|
bool is_float_literal = value_.back() == 'f';
|
const std::string raw_value = TrimIfSuffix(value_, "f");
|
|
if (type_string == "double") {
|
double parsed_value;
|
if (!android::base::ParseDouble(raw_value, &parsed_value)) goto parse_error;
|
return decorator(type, std::to_string(parsed_value));
|
}
|
if (is_float_literal && type_string == "float") {
|
float parsed_value;
|
if (!android::base::ParseFloat(raw_value, &parsed_value)) goto parse_error;
|
return decorator(type, std::to_string(parsed_value) + "f");
|
}
|
goto mismatch_error;
|
}
|
case AidlConstantValue::Type::HEXIDECIMAL:
|
// For historical reasons, a hexidecimal int needs to have the specified bits interpreted
|
// as the signed type, so the other types are made consistent with it.
|
if (type_string == "byte") {
|
uint8_t unsigned_value;
|
if (!android::base::ParseUint<uint8_t>(value_, &unsigned_value)) goto parse_error;
|
return decorator(type, std::to_string((int8_t)unsigned_value));
|
}
|
if (type_string == "int") {
|
uint32_t unsigned_value;
|
if (!android::base::ParseUint<uint32_t>(value_, &unsigned_value)) goto parse_error;
|
return decorator(type, std::to_string((int32_t)unsigned_value));
|
}
|
if (type_string == "long") {
|
uint64_t unsigned_value;
|
if (!android::base::ParseUint<uint64_t>(value_, &unsigned_value)) goto parse_error;
|
return decorator(type, std::to_string((int64_t)unsigned_value));
|
}
|
goto mismatch_error;
|
case AidlConstantValue::Type::INTEGRAL:
|
if (type_string == "byte") {
|
if (!android::base::ParseInt<int8_t>(value_, nullptr)) goto parse_error;
|
return decorator(type, value_);
|
}
|
if (type_string == "int") {
|
if (!android::base::ParseInt<int32_t>(value_, nullptr)) goto parse_error;
|
return decorator(type, value_);
|
}
|
if (type_string == "long") {
|
if (!android::base::ParseInt<int64_t>(value_, nullptr)) goto parse_error;
|
return decorator(type, value_);
|
}
|
goto mismatch_error;
|
case AidlConstantValue::Type::STRING:
|
if (type_string == "String") return decorator(type, value_);
|
goto mismatch_error;
|
default:
|
AIDL_FATAL(this) << "Unrecognized constant value type";
|
}
|
|
mismatch_error:
|
AIDL_ERROR(this) << "Expecting type " << type_string << " but constant is " << ToString(type_);
|
return "";
|
parse_error:
|
AIDL_ERROR(this) << "Could not parse " << value_ << " as " << type_string;
|
return "";
|
}
|
|
string AidlConstantValue::ToString(Type type) {
|
switch (type) {
|
case Type::ARRAY:
|
return "a literal array";
|
case Type::BOOLEAN:
|
return "a literal boolean";
|
case Type::CHARACTER:
|
return "a literal char";
|
case Type::FLOATING:
|
return "a floating-point literal";
|
case Type::HEXIDECIMAL:
|
return "a hexidecimal literal";
|
case Type::INTEGRAL:
|
return "an integral literal";
|
case Type::STRING:
|
return "a literal string";
|
case Type::ERROR:
|
LOG(FATAL) << "aidl internal error: error type failed to halt program";
|
return "";
|
default:
|
LOG(FATAL) << "aidl internal error: unknown constant type: " << static_cast<int>(type);
|
return ""; // not reached
|
}
|
}
|
|
AidlConstantDeclaration::AidlConstantDeclaration(const AidlLocation& location,
|
AidlTypeSpecifier* type, const std::string& name,
|
AidlConstantValue* value)
|
: AidlMember(location), type_(type), name_(name), value_(value) {}
|
|
bool AidlConstantDeclaration::CheckValid(const AidlTypenames& typenames) const {
|
bool valid = true;
|
valid &= type_->CheckValid(typenames);
|
valid &= value_->CheckValid();
|
if (!valid) return false;
|
|
const static set<string> kSupportedConstTypes = {"String", "int"};
|
if (kSupportedConstTypes.find(type_->ToString()) == kSupportedConstTypes.end()) {
|
AIDL_ERROR(this) << "Constant of type " << type_->ToString() << " is not supported.";
|
return false;
|
}
|
|
return !ValueString(AidlConstantValueDecorator).empty();
|
}
|
|
string AidlConstantDeclaration::ToString() const {
|
return "const " + type_->ToString() + " " + name_ + " = " +
|
ValueString(AidlConstantValueDecorator);
|
}
|
|
string AidlConstantDeclaration::Signature() const {
|
return type_->Signature() + " " + name_;
|
}
|
|
AidlMethod::AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type,
|
const std::string& name, std::vector<std::unique_ptr<AidlArgument>>* args,
|
const std::string& comments)
|
: AidlMethod(location, oneway, type, name, args, comments, 0, true) {
|
has_id_ = false;
|
}
|
|
AidlMethod::AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type,
|
const std::string& name, std::vector<std::unique_ptr<AidlArgument>>* args,
|
const std::string& comments, int id, bool is_user_defined)
|
: AidlMember(location),
|
oneway_(oneway),
|
comments_(comments),
|
type_(type),
|
name_(name),
|
arguments_(std::move(*args)),
|
id_(id),
|
is_user_defined_(is_user_defined) {
|
has_id_ = true;
|
delete args;
|
for (const unique_ptr<AidlArgument>& a : arguments_) {
|
if (a->IsIn()) { in_arguments_.push_back(a.get()); }
|
if (a->IsOut()) { out_arguments_.push_back(a.get()); }
|
}
|
}
|
|
|
string AidlMethod::Signature() const {
|
vector<string> arg_signatures;
|
for (const auto& arg : GetArguments()) {
|
arg_signatures.emplace_back(arg->GetType().ToString());
|
}
|
return GetName() + "(" + Join(arg_signatures, ", ") + ")";
|
}
|
|
string AidlMethod::ToString() const {
|
vector<string> arg_strings;
|
for (const auto& arg : GetArguments()) {
|
arg_strings.emplace_back(arg->Signature());
|
}
|
string ret = (IsOneway() ? "oneway " : "") + GetType().Signature() + " " + GetName() + "(" +
|
Join(arg_strings, ", ") + ")";
|
if (HasId()) {
|
ret += " = " + std::to_string(GetId());
|
}
|
return ret;
|
}
|
|
AidlDefinedType::AidlDefinedType(const AidlLocation& location, const std::string& name,
|
const std::string& comments,
|
const std::vector<std::string>& package)
|
: AidlAnnotatable(location), name_(name), comments_(comments), package_(package) {}
|
|
std::string AidlDefinedType::GetPackage() const {
|
return Join(package_, '.');
|
}
|
|
std::string AidlDefinedType::GetCanonicalName() const {
|
if (package_.empty()) {
|
return GetName();
|
}
|
return GetPackage() + "." + GetName();
|
}
|
|
AidlParcelable::AidlParcelable(const AidlLocation& location, AidlQualifiedName* name,
|
const std::vector<std::string>& package, const std::string& comments,
|
const std::string& cpp_header)
|
: AidlDefinedType(location, name->GetDotName(), comments, package),
|
name_(name),
|
cpp_header_(cpp_header) {
|
// Strip off quotation marks if we actually have a cpp header.
|
if (cpp_header_.length() >= 2) {
|
cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2);
|
}
|
}
|
|
bool AidlParcelable::CheckValid(const AidlTypenames&) const {
|
static const std::set<string> allowed{kStableParcelable};
|
for (const auto& v : GetAnnotations()) {
|
if (allowed.find(v.GetName()) == allowed.end()) {
|
std::ostringstream stream;
|
stream << "Unstructured parcelable can contain only";
|
for (const string& kv : allowed) {
|
stream << " " << kv;
|
}
|
stream << ".";
|
AIDL_ERROR(this) << stream.str();
|
return false;
|
}
|
}
|
|
return true;
|
}
|
|
void AidlParcelable::Write(CodeWriter* writer) const {
|
writer->Write("parcelable %s ;\n", GetName().c_str());
|
}
|
|
AidlStructuredParcelable::AidlStructuredParcelable(
|
const AidlLocation& location, AidlQualifiedName* name, const std::vector<std::string>& package,
|
const std::string& comments, std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables)
|
: AidlParcelable(location, name, package, comments, "" /*cpp_header*/),
|
variables_(std::move(*variables)) {}
|
|
void AidlStructuredParcelable::Write(CodeWriter* writer) const {
|
writer->Write("parcelable %s {\n", GetName().c_str());
|
writer->Indent();
|
for (const auto& field : GetFields()) {
|
writer->Write("%s;\n", field->ToString().c_str());
|
}
|
writer->Dedent();
|
writer->Write("}\n");
|
}
|
|
bool AidlStructuredParcelable::CheckValid(const AidlTypenames& typenames) const {
|
for (const auto& v : GetFields()) {
|
if (!(v->CheckValid(typenames))) {
|
return false;
|
}
|
}
|
|
return true;
|
}
|
|
AidlInterface::AidlInterface(const AidlLocation& location, const std::string& name,
|
const std::string& comments, bool oneway,
|
std::vector<std::unique_ptr<AidlMember>>* members,
|
const std::vector<std::string>& package)
|
: AidlDefinedType(location, name, comments, package) {
|
for (auto& member : *members) {
|
AidlMember* local = member.release();
|
AidlMethod* method = local->AsMethod();
|
AidlConstantDeclaration* constant = local->AsConstantDeclaration();
|
|
CHECK(method == nullptr || constant == nullptr);
|
|
if (method) {
|
method->ApplyInterfaceOneway(oneway);
|
methods_.emplace_back(method);
|
} else if (constant) {
|
constants_.emplace_back(constant);
|
} else {
|
AIDL_FATAL(this) << "Member is neither method nor constant!";
|
}
|
}
|
|
delete members;
|
}
|
|
void AidlInterface::Write(CodeWriter* writer) const {
|
writer->Write("interface %s {\n", GetName().c_str());
|
writer->Indent();
|
for (const auto& method : GetMethods()) {
|
writer->Write("%s;\n", method->ToString().c_str());
|
}
|
for (const auto& constdecl : GetConstantDeclarations()) {
|
writer->Write("%s;\n", constdecl->ToString().c_str());
|
}
|
writer->Dedent();
|
writer->Write("}\n");
|
}
|
|
bool AidlInterface::CheckValid(const AidlTypenames& typenames) const {
|
// Has to be a pointer due to deleting copy constructor. No idea why.
|
map<string, const AidlMethod*> method_names;
|
for (const auto& m : GetMethods()) {
|
if (!m->GetType().CheckValid(typenames)) {
|
return false;
|
}
|
|
if (m->IsOneway() && m->GetType().GetName() != "void") {
|
AIDL_ERROR(m) << "oneway method '" << m->GetName() << "' cannot return a value";
|
return false;
|
}
|
|
set<string> argument_names;
|
for (const auto& arg : m->GetArguments()) {
|
auto it = argument_names.find(arg->GetName());
|
if (it != argument_names.end()) {
|
AIDL_ERROR(m) << "method '" << m->GetName() << "' has duplicate argument name '"
|
<< arg->GetName() << "'";
|
return false;
|
}
|
argument_names.insert(arg->GetName());
|
|
if (!arg->GetType().CheckValid(typenames)) {
|
return false;
|
}
|
|
if (m->IsOneway() && arg->IsOut()) {
|
AIDL_ERROR(m) << "oneway method '" << m->GetName() << "' cannot have out parameters";
|
return false;
|
}
|
}
|
|
auto it = method_names.find(m->GetName());
|
// prevent duplicate methods
|
if (it == method_names.end()) {
|
method_names[m->GetName()] = m.get();
|
} else {
|
AIDL_ERROR(m) << "attempt to redefine method " << m->GetName() << ":";
|
AIDL_ERROR(it->second) << "previously defined here.";
|
return false;
|
}
|
|
static set<string> reserved_methods{"asBinder()", "getInterfaceVersion()",
|
"getTransactionName(int)"};
|
|
if (reserved_methods.find(m->Signature()) != reserved_methods.end()) {
|
AIDL_ERROR(m) << " method " << m->Signature() << " is reserved for internal use." << endl;
|
return false;
|
}
|
}
|
|
bool success = true;
|
set<string> constant_names;
|
for (const std::unique_ptr<AidlConstantDeclaration>& constant : GetConstantDeclarations()) {
|
if (constant_names.count(constant->GetName()) > 0) {
|
LOG(ERROR) << "Found duplicate constant name '" << constant->GetName() << "'";
|
success = false;
|
}
|
constant_names.insert(constant->GetName());
|
success = success && constant->CheckValid(typenames);
|
}
|
|
return success;
|
}
|
|
AidlQualifiedName::AidlQualifiedName(const AidlLocation& location, const std::string& term,
|
const std::string& comments)
|
: AidlNode(location), terms_({term}), comments_(comments) {
|
if (term.find('.') != string::npos) {
|
terms_ = Split(term, ".");
|
for (const auto& subterm : terms_) {
|
if (subterm.empty()) {
|
AIDL_FATAL(this) << "Malformed qualified identifier: '" << term << "'";
|
}
|
}
|
}
|
}
|
|
void AidlQualifiedName::AddTerm(const std::string& term) {
|
terms_.push_back(term);
|
}
|
|
AidlImport::AidlImport(const AidlLocation& location, const std::string& needed_class)
|
: AidlNode(location), needed_class_(needed_class) {}
|
|
std::unique_ptr<Parser> Parser::Parse(const std::string& filename,
|
const android::aidl::IoDelegate& io_delegate,
|
AidlTypenames& typenames) {
|
// Make sure we can read the file first, before trashing previous state.
|
unique_ptr<string> raw_buffer = io_delegate.GetFileContents(filename);
|
if (raw_buffer == nullptr) {
|
AIDL_ERROR(filename) << "Error while opening file for parsing";
|
return nullptr;
|
}
|
|
// We're going to scan this buffer in place, and yacc demands we put two
|
// nulls at the end.
|
raw_buffer->append(2u, '\0');
|
|
std::unique_ptr<Parser> parser(new Parser(filename, *raw_buffer, typenames));
|
|
if (yy::parser(parser.get()).parse() != 0 || parser->HasError()) return nullptr;
|
|
return parser;
|
}
|
|
std::vector<std::string> Parser::Package() const {
|
if (!package_) {
|
return {};
|
}
|
return package_->GetTerms();
|
}
|
|
void Parser::AddImport(AidlImport* import) {
|
imports_.emplace_back(import);
|
}
|
|
bool Parser::Resolve() {
|
bool success = true;
|
for (AidlTypeSpecifier* typespec : unresolved_typespecs_) {
|
if (!typespec->Resolve(typenames_)) {
|
AIDL_ERROR(typespec) << "Failed to resolve '" << typespec->GetUnresolvedName() << "'";
|
success = false;
|
// don't stop to show more errors if any
|
}
|
}
|
return success;
|
}
|
|
Parser::Parser(const std::string& filename, std::string& raw_buffer,
|
android::aidl::AidlTypenames& typenames)
|
: filename_(filename), typenames_(typenames) {
|
yylex_init(&scanner_);
|
buffer_ = yy_scan_buffer(&raw_buffer[0], raw_buffer.length(), scanner_);
|
}
|
|
Parser::~Parser() {
|
yy_delete_buffer(buffer_, scanner_);
|
yylex_destroy(scanner_);
|
}
|