You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
4.1 KiB

/*
* Copyright (C) 2019 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 <android-base/logging.h>
#include <iostream>
#include <vector>
#include "AST.h"
#include "Interface.h"
#include "Lint.h"
#include "LintRegistry.h"
#include "Method.h"
namespace android {
enum InterfaceMethodType { NONE = 0, ONEWAY = 1, TWOWAY = 2, MIXED = ONEWAY | TWOWAY };
// To use InterfaceMethodType as a bitfield
static inline InterfaceMethodType operator|(InterfaceMethodType lhs, InterfaceMethodType rhs) {
using T = std::underlying_type_t<InterfaceMethodType>;
return static_cast<InterfaceMethodType>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
// This function returns what kind of methods the interface contains
static InterfaceMethodType getInterfaceOnewayType(const Interface& iface,
bool includeParentMethods) {
InterfaceMethodType onewayType = NONE;
const std::vector<Method*>& methods = iface.userDefinedMethods();
if (methods.empty()) {
return (iface.superType() != nullptr && includeParentMethods)
? getInterfaceOnewayType(*iface.superType(), true)
: NONE;
}
for (auto method : methods) {
if (method->isOneway()) {
onewayType = onewayType | ONEWAY;
} else {
onewayType = onewayType | TWOWAY;
}
if (onewayType == MIXED) {
return onewayType;
}
}
if (includeParentMethods) {
onewayType = onewayType | getInterfaceOnewayType(*iface.superType(), true);
}
CHECK(onewayType != NONE) << "Functions are neither oneway nor non-oneway?: "
<< iface.location();
return onewayType;
}
static void onewayLint(const AST& ast, std::vector<Lint>* errors) {
const Interface* iface = ast.getInterface();
if (iface == nullptr) {
// No interfaces so no oneway methods.
return;
}
InterfaceMethodType ifaceType = getInterfaceOnewayType(*iface, false);
if (ifaceType == NONE) {
// Can occur for empty interfaces
return;
}
std::string lintExplanation =
"Since a function being oneway/non-oneway has large implications on the threading "
"model and how client code needs to call an interface, it can be confusing/problematic "
"when similar looking calls to the same interface result in wildly different "
"behavior.\n";
if (ifaceType == MIXED) {
// This interface in itself is MIXED. Flag to user.
errors->push_back(Lint(WARNING, iface->location())
<< iface->typeName() << " has both oneway and non-oneway methods. "
<< "It should only contain one of the two.\n"
<< lintExplanation);
return;
}
InterfaceMethodType parentType = getInterfaceOnewayType(*iface->superType(), true);
if (parentType == NONE || parentType == MIXED) {
// parents are mixed or don't have type, while this interface has only one type of
// method. parentType => MIXED would have generated a lint on the parent interface.
return;
}
if (parentType != ifaceType) {
// type mismatch raise warning.
errors->push_back(Lint(WARNING, iface->location())
<< iface->typeName() << " should only have "
<< (parentType == ONEWAY ? "oneway" : "non-oneway")
<< " methods like its parent.\n"
<< lintExplanation);
}
}
REGISTER_LINT(onewayLint);
} // namespace android