/* * 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 #include #include #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; return static_cast(static_cast(lhs) | static_cast(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& 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* 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