• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020, 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 #include "diagnostics.h"
17 
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <string>
21 #include <vector>
22 
23 #include "aidl.h"
24 #include "parser.h"
25 #include "tests/fake_io_delegate.h"
26 
27 using android::aidl::AidlTypenames;
28 using android::aidl::DiagnosticID;
29 using android::aidl::Options;
30 using android::aidl::internals::load_and_validate_aidl;
31 using android::aidl::test::FakeIoDelegate;
32 using testing::internal::CaptureStderr;
33 using testing::internal::GetCapturedStderr;
34 
35 struct DiagnosticsTest : testing::Test {
ParseFilesDiagnosticsTest36   void ParseFiles(std::vector<std::pair<std::string, std::string>>&& files) {
37     ASSERT_TRUE(files.size() > 0);
38     const std::string main = files.begin()->first;
39     for (const auto& [file, contents] : files) {
40       io.SetFileContents(file, contents);
41     }
42     if (!enable_diagnostic) {
43       ASSERT_TRUE(expect_diagnostic);
44       enable_diagnostic = expect_diagnostic;
45     }
46     // emit diagnostics as warnings.
47     // "java" has no specific meaning here because we're testing CheckValid()
48     const Options options = Options::From("aidl " + optional_args + " -I . --lang java -o out -W" +
49                                           to_string(*enable_diagnostic) + " " + main);
50     CaptureStderr();
51     load_and_validate_aidl(main, options, io, &typenames, nullptr);
52     const std::string err = GetCapturedStderr();
53     if (expect_diagnostic) {
54       EXPECT_THAT(err, testing::HasSubstr("-W" + to_string(*expect_diagnostic)));
55     } else {
56       EXPECT_EQ("", err);
57     }
58   }
59 
60   AidlTypenames typenames;
61   FakeIoDelegate io;
62   std::string optional_args;
63   // The type of diagnostic to enable for the test. If expect_diagnostic is
64   // set, use the same value.
65   std::optional<DiagnosticID> enable_diagnostic;
66   // The expected diagnostic. Must be set.
67   std::optional<DiagnosticID> expect_diagnostic;
68 };
69 
TEST_F(DiagnosticsTest,const_name_ForEnumerator)70 TEST_F(DiagnosticsTest, const_name_ForEnumerator) {
71   expect_diagnostic = DiagnosticID::const_name;
72   ParseFiles({{"Foo.aidl", "enum Foo { foo }"}});
73 }
74 
TEST_F(DiagnosticsTest,const_name_ForConstants)75 TEST_F(DiagnosticsTest, const_name_ForConstants) {
76   expect_diagnostic = DiagnosticID::const_name;
77   ParseFiles({{"IFoo.aidl", "interface IFoo { const int foo = 1; }"}});
78 }
79 
TEST_F(DiagnosticsTest,interface_name)80 TEST_F(DiagnosticsTest, interface_name) {
81   expect_diagnostic = DiagnosticID::interface_name;
82   ParseFiles({{"Foo.aidl", "interface Foo { }"}});
83 }
84 
TEST_F(DiagnosticsTest,enum_explicit_default)85 TEST_F(DiagnosticsTest, enum_explicit_default) {
86   expect_diagnostic = DiagnosticID::enum_explicit_default;
87   ParseFiles({{"Foo.aidl", "parcelable Foo { E e; }"}, {"E.aidl", "enum E { A }"}});
88 }
89 
TEST_F(DiagnosticsTest,inout_parameter)90 TEST_F(DiagnosticsTest, inout_parameter) {
91   expect_diagnostic = DiagnosticID::inout_parameter;
92   ParseFiles({{"IFoo.aidl", "interface IFoo { void foo(inout Bar bar); }"},
93               {"Bar.aidl", "parcelable Bar {}"}});
94 }
95 
TEST_F(DiagnosticsTest,inout_parameter_SuppressAtMethodLevel)96 TEST_F(DiagnosticsTest, inout_parameter_SuppressAtMethodLevel) {
97   enable_diagnostic = DiagnosticID::inout_parameter;
98   expect_diagnostic = {};
99   ParseFiles({
100       {"IFoo.aidl",
101        "interface IFoo { @SuppressWarnings(value={\"inout-parameter\"}) void foo(inout Bar b); }"},
102       {"Bar.aidl", "parcelable Bar {}"},
103   });
104 }
105 
TEST_F(DiagnosticsTest,inout_parameter_SuppressAtDeclLevel)106 TEST_F(DiagnosticsTest, inout_parameter_SuppressAtDeclLevel) {
107   enable_diagnostic = DiagnosticID::inout_parameter;
108   expect_diagnostic = {};
109   ParseFiles({
110       {"IFoo.aidl",
111        "@SuppressWarnings(value={\"inout-parameter\"}) interface IFoo { void foo(inout Bar b); }"},
112       {"Bar.aidl", "parcelable Bar {}"},
113   });
114 }
115 
TEST_F(DiagnosticsTest,UnknownWarning)116 TEST_F(DiagnosticsTest, UnknownWarning) {
117   expect_diagnostic = DiagnosticID::unknown_warning;
118   ParseFiles({
119       {"IFoo.aidl", "@SuppressWarnings(value={\"blahblah\"}) interface IFoo { void foo(); }"},
120   });
121 }
122 
TEST_F(DiagnosticsTest,CantSuppressUnknownWarning)123 TEST_F(DiagnosticsTest, CantSuppressUnknownWarning) {
124   expect_diagnostic = DiagnosticID::unknown_warning;
125   ParseFiles({
126       {"IFoo.aidl",
127        "@SuppressWarnings(value={\"unknown-warning\"})\n"
128        "interface IFoo { @SuppressWarnings(value={\"blah-blah\"}) void foo(); }"},
129   });
130 }
131 
TEST_F(DiagnosticsTest,DontMixOnewayWithTwowayMethods)132 TEST_F(DiagnosticsTest, DontMixOnewayWithTwowayMethods) {
133   expect_diagnostic = DiagnosticID::mixed_oneway;
134   ParseFiles({
135       {"IFoo.aidl", "interface IFoo { void foo(); oneway void bar(); }"},
136   });
137 }
138 
TEST_F(DiagnosticsTest,DontMixOnewayWithTwowayMethodsSuppressedAtMethod)139 TEST_F(DiagnosticsTest, DontMixOnewayWithTwowayMethodsSuppressedAtMethod) {
140   enable_diagnostic = DiagnosticID::mixed_oneway;
141   expect_diagnostic = {};
142   ParseFiles({
143       {"IFoo.aidl",
144        "interface IFoo {\n"
145        "  void foo();\n"
146        "  @SuppressWarnings(value={\"mixed-oneway\"}) oneway void bar();\n"
147        "}"},
148   });
149 }
150 
TEST_F(DiagnosticsTest,OnewayInterfaceIsOkayWithSyntheticMethods)151 TEST_F(DiagnosticsTest, OnewayInterfaceIsOkayWithSyntheticMethods) {
152   optional_args = "--version 2";  // will add getInterfaceVersion() synthetic method
153   enable_diagnostic = DiagnosticID::mixed_oneway;
154   expect_diagnostic = {};
155   ParseFiles({
156       {"IFoo.aidl", "oneway interface IFoo { void foo(); }"},
157   });
158 }
159 
TEST_F(DiagnosticsTest,ArraysAsOutputParametersConsideredHarmful)160 TEST_F(DiagnosticsTest, ArraysAsOutputParametersConsideredHarmful) {
161   expect_diagnostic = DiagnosticID::out_array;
162   ParseFiles({
163       {"IFoo.aidl", "interface IFoo { void foo(out String[] ret); }"},
164   });
165 }
166 
TEST_F(DiagnosticsTest,file_descriptor)167 TEST_F(DiagnosticsTest, file_descriptor) {
168   expect_diagnostic = DiagnosticID::file_descriptor;
169   ParseFiles({{"IFoo.aidl",
170                "interface IFoo {\n"
171                "  void foo(in FileDescriptor fd);\n"
172                "}"}});
173 }
174 
TEST_F(DiagnosticsTest,out_nullable)175 TEST_F(DiagnosticsTest, out_nullable) {
176   expect_diagnostic = DiagnosticID::out_nullable;
177   ParseFiles({{"IFoo.aidl",
178                "interface IFoo {\n"
179                "  void foo(out @nullable Bar bar);\n"
180                "}"},
181               {"Bar.aidl", "parcelable Bar {}"}});
182 }
183 
TEST_F(DiagnosticsTest,inout_nullable)184 TEST_F(DiagnosticsTest, inout_nullable) {
185   expect_diagnostic = DiagnosticID::out_nullable;
186   ParseFiles({{"IFoo.aidl",
187                "interface IFoo {\n"
188                "  void foo(inout @nullable Bar bar);\n"
189                "}"},
190               {"Bar.aidl", "parcelable Bar {}"}});
191 }
192 
TEST_F(DiagnosticsTest,out_nullable_OkayForArrays)193 TEST_F(DiagnosticsTest, out_nullable_OkayForArrays) {
194   expect_diagnostic = DiagnosticID::out_array;  // not triggering out_nullable
195   ParseFiles({{"IFoo.aidl",
196                "interface IFoo {\n"
197                "  void foo(inout @nullable Bar[] bar1, out @nullable Bar[] bar2);\n"
198                "}"},
199               {"Bar.aidl", "parcelable Bar {}"}});
200 }
201 
TEST_F(DiagnosticsTest,RejectImportsCollisionWithTopLevelDecl)202 TEST_F(DiagnosticsTest, RejectImportsCollisionWithTopLevelDecl) {
203   expect_diagnostic = DiagnosticID::unique_import;
204   ParseFiles({{"p/IFoo.aidl",
205                "package p;\n"
206                "import q.IFoo;\n"  // should collide with previous import
207                "interface IFoo{}"},
208               {"q/IFoo.aidl", "package q; interface IFoo{}"}});
209 }
210 
TEST_F(DiagnosticsTest,RejectImportsCollision)211 TEST_F(DiagnosticsTest, RejectImportsCollision) {
212   expect_diagnostic = DiagnosticID::unique_import;
213   ParseFiles({{"p/IFoo.aidl",
214                "package p;\n"
215                "import q.IBar;\n"
216                "import r.IBar;\n"  // should collide with previous import
217                "interface IFoo{}"},
218               {"q/IBar.aidl", "package q; interface IBar{}"},
219               {"r/IBar.aidl", "package r; interface IBar{}"}});
220 }
221 
TEST_F(DiagnosticsTest,AllowImportingSelf)222 TEST_F(DiagnosticsTest, AllowImportingSelf) {
223   enable_diagnostic = DiagnosticID::unique_import;
224   expect_diagnostic = {};
225   ParseFiles({{"p/IFoo.aidl",
226                "package p;\n"
227                "import p.IFoo;\n"
228                "interface IFoo{}"}});
229 }
230 
TEST_F(DiagnosticsTest,RedundantImports)231 TEST_F(DiagnosticsTest, RedundantImports) {
232   expect_diagnostic = DiagnosticID::unique_import;
233   ParseFiles({{"p/IFoo.aidl",
234                "package p;\n"
235                "import q.IBar;\n"
236                "import q.IBar;\n"
237                "interface IFoo{}"},
238               {"q/IBar.aidl", "package q; interface IBar{}"}});
239 }
240 
TEST_F(DiagnosticsTest,UntypedCollectionInterface)241 TEST_F(DiagnosticsTest, UntypedCollectionInterface) {
242   expect_diagnostic = DiagnosticID::untyped_collection;
243   ParseFiles({{"IFoo.aidl", "interface IFoo { void foo(in Map m); }"}});
244 }
245 
TEST_F(DiagnosticsTest,UntypedCollectionParcelable)246 TEST_F(DiagnosticsTest, UntypedCollectionParcelable) {
247   expect_diagnostic = DiagnosticID::untyped_collection;
248   ParseFiles({{"Foo.aidl", "parcelable Foo { Map m; }"}});
249 }
250 
TEST_F(DiagnosticsTest,UntypedCollectionUnion)251 TEST_F(DiagnosticsTest, UntypedCollectionUnion) {
252   expect_diagnostic = DiagnosticID::untyped_collection;
253   ParseFiles({{"Foo.aidl", "union Foo { List l; }"}});
254 }
255 
TEST_F(DiagnosticsTest,UntypedCollectionInTypeArg)256 TEST_F(DiagnosticsTest, UntypedCollectionInTypeArg) {
257   expect_diagnostic = DiagnosticID::untyped_collection;
258   ParseFiles({{"IFoo.aidl", "interface IFoo { void foo(in Bar<Map> m); }"},
259               {"Bar.aidl", "parcelable Bar<T> {}"}});
260 }
261 
TEST_F(DiagnosticsTest,PermissionMissing)262 TEST_F(DiagnosticsTest, PermissionMissing) {
263   expect_diagnostic = DiagnosticID::missing_permission_annotation;
264   ParseFiles({{"IFoo.aidl", "interface IFoo { void food(); }"}});
265 }
266 
TEST_F(DiagnosticsTest,PermissionMethod)267 TEST_F(DiagnosticsTest, PermissionMethod) {
268   enable_diagnostic = DiagnosticID::missing_permission_annotation;
269   expect_diagnostic = {};
270   ParseFiles({{"IFoo.aidl", "interface IFoo { @EnforcePermission(\"INTERNET\") void food(); }"}});
271 }
272 
TEST_F(DiagnosticsTest,PermissionMethodMissing)273 TEST_F(DiagnosticsTest, PermissionMethodMissing) {
274   expect_diagnostic = DiagnosticID::missing_permission_annotation;
275   ParseFiles({{"IFoo.aidl",
276                "interface IFoo { @EnforcePermission(\"INTERNET\") void food(); void foo2(); }"}});
277 }
278 
TEST_F(DiagnosticsTest,PermissionInterface)279 TEST_F(DiagnosticsTest, PermissionInterface) {
280   enable_diagnostic = DiagnosticID::missing_permission_annotation;
281   expect_diagnostic = {};
282   ParseFiles({{"IFoo.aidl", "@EnforcePermission(\"INTERNET\") interface IFoo { void food(); }"}});
283 }
284