• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/logging.h>
18 
19 #include <iostream>
20 #include <vector>
21 
22 #include "AST.h"
23 #include "Interface.h"
24 #include "Lint.h"
25 #include "LintRegistry.h"
26 #include "Method.h"
27 
28 namespace android {
29 
30 enum InterfaceMethodType { NONE = 0, ONEWAY = 1, TWOWAY = 2, MIXED = ONEWAY | TWOWAY };
31 
32 // To use InterfaceMethodType as a bitfield
operator |(InterfaceMethodType lhs,InterfaceMethodType rhs)33 static inline InterfaceMethodType operator|(InterfaceMethodType lhs, InterfaceMethodType rhs) {
34     using T = std::underlying_type_t<InterfaceMethodType>;
35     return static_cast<InterfaceMethodType>(static_cast<T>(lhs) | static_cast<T>(rhs));
36 }
37 
38 // This function returns what kind of methods the interface contains
getInterfaceOnewayType(const Interface & iface,bool includeParentMethods)39 static InterfaceMethodType getInterfaceOnewayType(const Interface& iface,
40                                                   bool includeParentMethods) {
41     InterfaceMethodType onewayType = NONE;
42 
43     const std::vector<Method*>& methods = iface.userDefinedMethods();
44     if (methods.empty()) {
45         return (iface.superType() != nullptr && includeParentMethods)
46                        ? getInterfaceOnewayType(*iface.superType(), true)
47                        : NONE;
48     }
49 
50     for (auto method : methods) {
51         if (method->isOneway()) {
52             onewayType = onewayType | ONEWAY;
53         } else {
54             onewayType = onewayType | TWOWAY;
55         }
56 
57         if (onewayType == MIXED) {
58             return onewayType;
59         }
60     }
61 
62     if (includeParentMethods) {
63         onewayType = onewayType | getInterfaceOnewayType(*iface.superType(), true);
64     }
65 
66     CHECK(onewayType != NONE) << "Functions are neither oneway nor non-oneway?: "
67                               << iface.location();
68 
69     return onewayType;
70 }
71 
onewayLint(const AST & ast,std::vector<Lint> * errors)72 static void onewayLint(const AST& ast, std::vector<Lint>* errors) {
73     const Interface* iface = ast.getInterface();
74     if (iface == nullptr) {
75         // No interfaces so no oneway methods.
76         return;
77     }
78 
79     InterfaceMethodType ifaceType = getInterfaceOnewayType(*iface, false);
80     if (ifaceType == NONE) {
81         // Can occur for empty interfaces
82         return;
83     }
84 
85     std::string lintExplanation =
86             "Since a function being oneway/non-oneway has large implications on the threading "
87             "model and how client code needs to call an interface, it can be confusing/problematic "
88             "when similar looking calls to the same interface result in wildly different "
89             "behavior.\n";
90     if (ifaceType == MIXED) {
91         // This interface in itself is MIXED. Flag to user.
92         errors->push_back(Lint(WARNING, iface->location())
93                           << iface->typeName() << " has both oneway and non-oneway methods. "
94                           << "It should only contain one of the two.\n"
95                           << lintExplanation);
96         return;
97     }
98 
99     InterfaceMethodType parentType = getInterfaceOnewayType(*iface->superType(), true);
100     if (parentType == NONE || parentType == MIXED) {
101         // parents are mixed or don't have type, while this interface has only one type of
102         // method. parentType => MIXED would have generated a lint on the parent interface.
103         return;
104     }
105 
106     if (parentType != ifaceType) {
107         // type mismatch raise warning.
108         errors->push_back(Lint(WARNING, iface->location())
109                           << iface->typeName() << " should only have "
110                           << (parentType == ONEWAY ? "oneway" : "non-oneway")
111                           << " methods like its parent.\n"
112                           << lintExplanation);
113     }
114 }
115 
116 REGISTER_LINT(onewayLint);
117 
118 }  // namespace android
119