1 //
2 // Copyright 2012 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "PreprocessorTest.h"
8 #include "compiler/preprocessor/Token.h"
9
10 namespace angle
11 {
12
13 class LocationTest : public PreprocessorTest
14 {
15 protected:
LocationTest()16 LocationTest() : PreprocessorTest(SH_GLES2_SPEC) {}
17
expectLocation(int count,const char * const string[],const int length[],const pp::SourceLocation & location)18 void expectLocation(int count,
19 const char *const string[],
20 const int length[],
21 const pp::SourceLocation &location)
22 {
23 ASSERT_TRUE(mPreprocessor.init(count, string, length));
24
25 pp::Token token;
26 mPreprocessor.lex(&token);
27 EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
28 EXPECT_EQ("foo", token.text);
29
30 EXPECT_EQ(location.file, token.location.file);
31 EXPECT_EQ(location.line, token.location.line);
32 }
33 };
34
TEST_F(LocationTest,String0_Line1)35 TEST_F(LocationTest, String0_Line1)
36 {
37 const char *str = "foo";
38 pp::SourceLocation loc(0, 1);
39
40 SCOPED_TRACE("String0_Line1");
41 expectLocation(1, &str, nullptr, loc);
42 }
43
TEST_F(LocationTest,String0_Line2)44 TEST_F(LocationTest, String0_Line2)
45 {
46 const char *str = "\nfoo";
47 pp::SourceLocation loc(0, 2);
48
49 SCOPED_TRACE("String0_Line2");
50 expectLocation(1, &str, nullptr, loc);
51 }
52
TEST_F(LocationTest,String1_Line1)53 TEST_F(LocationTest, String1_Line1)
54 {
55 const char *const str[] = {"\n\n", "foo"};
56 pp::SourceLocation loc(1, 1);
57
58 SCOPED_TRACE("String1_Line1");
59 expectLocation(2, str, nullptr, loc);
60 }
61
TEST_F(LocationTest,String1_Line2)62 TEST_F(LocationTest, String1_Line2)
63 {
64 const char *const str[] = {"\n\n", "\nfoo"};
65 pp::SourceLocation loc(1, 2);
66
67 SCOPED_TRACE("String1_Line2");
68 expectLocation(2, str, nullptr, loc);
69 }
70
TEST_F(LocationTest,NewlineInsideCommentCounted)71 TEST_F(LocationTest, NewlineInsideCommentCounted)
72 {
73 const char *str = "/*\n\n*/foo";
74 pp::SourceLocation loc(0, 3);
75
76 SCOPED_TRACE("NewlineInsideCommentCounted");
77 expectLocation(1, &str, nullptr, loc);
78 }
79
TEST_F(LocationTest,ErrorLocationAfterComment)80 TEST_F(LocationTest, ErrorLocationAfterComment)
81 {
82 const char *str = "/*\n\n*/@";
83
84 ASSERT_TRUE(mPreprocessor.init(1, &str, nullptr));
85 EXPECT_CALL(mDiagnostics,
86 print(pp::Diagnostics::PP_INVALID_CHARACTER, pp::SourceLocation(0, 3), "@"));
87
88 pp::Token token;
89 mPreprocessor.lex(&token);
90 }
91
92 // The location of a token straddling two or more strings is that of the
93 // first character of the token.
94
TEST_F(LocationTest,TokenStraddlingTwoStrings)95 TEST_F(LocationTest, TokenStraddlingTwoStrings)
96 {
97 const char *const str[] = {"f", "oo"};
98 pp::SourceLocation loc(0, 1);
99
100 SCOPED_TRACE("TokenStraddlingTwoStrings");
101 expectLocation(2, str, nullptr, loc);
102 }
103
TEST_F(LocationTest,TokenStraddlingThreeStrings)104 TEST_F(LocationTest, TokenStraddlingThreeStrings)
105 {
106 const char *const str[] = {"f", "o", "o"};
107 pp::SourceLocation loc(0, 1);
108
109 SCOPED_TRACE("TokenStraddlingThreeStrings");
110 expectLocation(3, str, nullptr, loc);
111 }
112
TEST_F(LocationTest,EndOfFileWithoutNewline)113 TEST_F(LocationTest, EndOfFileWithoutNewline)
114 {
115 const char *const str[] = {"foo"};
116 ASSERT_TRUE(mPreprocessor.init(1, str, nullptr));
117
118 pp::Token token;
119 mPreprocessor.lex(&token);
120 EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
121 EXPECT_EQ("foo", token.text);
122 EXPECT_EQ(0, token.location.file);
123 EXPECT_EQ(1, token.location.line);
124
125 mPreprocessor.lex(&token);
126 EXPECT_EQ(pp::Token::LAST, token.type);
127 EXPECT_EQ(0, token.location.file);
128 EXPECT_EQ(1, token.location.line);
129 }
130
TEST_F(LocationTest,EndOfFileAfterNewline)131 TEST_F(LocationTest, EndOfFileAfterNewline)
132 {
133 const char *const str[] = {"foo\n"};
134 ASSERT_TRUE(mPreprocessor.init(1, str, nullptr));
135
136 pp::Token token;
137 mPreprocessor.lex(&token);
138 EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
139 EXPECT_EQ("foo", token.text);
140 EXPECT_EQ(0, token.location.file);
141 EXPECT_EQ(1, token.location.line);
142
143 mPreprocessor.lex(&token);
144 EXPECT_EQ(pp::Token::LAST, token.type);
145 EXPECT_EQ(0, token.location.file);
146 EXPECT_EQ(2, token.location.line);
147 }
148
TEST_F(LocationTest,EndOfFileAfterEmptyString)149 TEST_F(LocationTest, EndOfFileAfterEmptyString)
150 {
151 const char *const str[] = {"foo\n", "\n", ""};
152 ASSERT_TRUE(mPreprocessor.init(3, str, nullptr));
153
154 pp::Token token;
155 mPreprocessor.lex(&token);
156 EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
157 EXPECT_EQ("foo", token.text);
158 EXPECT_EQ(0, token.location.file);
159 EXPECT_EQ(1, token.location.line);
160
161 mPreprocessor.lex(&token);
162 EXPECT_EQ(pp::Token::LAST, token.type);
163 EXPECT_EQ(2, token.location.file);
164 EXPECT_EQ(1, token.location.line);
165 }
166
TEST_F(LocationTest,ValidLineDirective1)167 TEST_F(LocationTest, ValidLineDirective1)
168 {
169 const char *str =
170 "#line 10\n"
171 "foo";
172 pp::SourceLocation loc(0, 10);
173
174 SCOPED_TRACE("ValidLineDirective1");
175 expectLocation(1, &str, nullptr, loc);
176 }
177
TEST_F(LocationTest,ValidLineDirective2)178 TEST_F(LocationTest, ValidLineDirective2)
179 {
180 const char *str =
181 "#line 10 20\n"
182 "foo";
183 pp::SourceLocation loc(20, 10);
184
185 SCOPED_TRACE("ValidLineDirective2");
186 expectLocation(1, &str, nullptr, loc);
187 }
188
TEST_F(LocationTest,LineDirectiveCommentsIgnored)189 TEST_F(LocationTest, LineDirectiveCommentsIgnored)
190 {
191 const char *str =
192 "/* bar */"
193 "#"
194 "/* bar */"
195 "line"
196 "/* bar */"
197 "10"
198 "/* bar */"
199 "20"
200 "/* bar */"
201 "// bar "
202 "\n"
203 "foo";
204 pp::SourceLocation loc(20, 10);
205
206 SCOPED_TRACE("LineDirectiveCommentsIgnored");
207 expectLocation(1, &str, nullptr, loc);
208 }
209
TEST_F(LocationTest,LineDirectiveWithMacro1)210 TEST_F(LocationTest, LineDirectiveWithMacro1)
211 {
212 const char *str =
213 "#define L 10\n"
214 "#define F(x) x\n"
215 "#line L F(20)\n"
216 "foo";
217 pp::SourceLocation loc(20, 10);
218
219 SCOPED_TRACE("LineDirectiveWithMacro1");
220 expectLocation(1, &str, nullptr, loc);
221 }
222
TEST_F(LocationTest,LineDirectiveWithMacro2)223 TEST_F(LocationTest, LineDirectiveWithMacro2)
224 {
225 const char *str =
226 "#define LOC 10 20\n"
227 "#line LOC\n"
228 "foo";
229 pp::SourceLocation loc(20, 10);
230
231 SCOPED_TRACE("LineDirectiveWithMacro2");
232 expectLocation(1, &str, nullptr, loc);
233 }
234
TEST_F(LocationTest,LineDirectiveWithPredefinedMacro)235 TEST_F(LocationTest, LineDirectiveWithPredefinedMacro)
236 {
237 const char *str =
238 "#line __LINE__ __FILE__\n"
239 "foo";
240 pp::SourceLocation loc(0, 1);
241
242 SCOPED_TRACE("LineDirectiveWithMacro");
243 expectLocation(1, &str, nullptr, loc);
244 }
245
TEST_F(LocationTest,LineDirectiveNewlineBeforeStringBreak)246 TEST_F(LocationTest, LineDirectiveNewlineBeforeStringBreak)
247 {
248 const char *const str[] = {"#line 10 20\n", "foo"};
249 // String number is incremented after it is set by the line directive.
250 // Also notice that line number is reset after the string break.
251 pp::SourceLocation loc(21, 1);
252
253 SCOPED_TRACE("LineDirectiveNewlineBeforeStringBreak");
254 expectLocation(2, str, nullptr, loc);
255 }
256
TEST_F(LocationTest,LineDirectiveNewlineAfterStringBreak)257 TEST_F(LocationTest, LineDirectiveNewlineAfterStringBreak)
258 {
259 const char *const str[] = {"#line 10 20", "\nfoo"};
260 // String number is incremented before it is set by the line directive.
261 pp::SourceLocation loc(20, 10);
262
263 SCOPED_TRACE("LineDirectiveNewlineAfterStringBreak");
264 expectLocation(2, str, nullptr, loc);
265 }
266
TEST_F(LocationTest,LineDirectiveMissingNewline)267 TEST_F(LocationTest, LineDirectiveMissingNewline)
268 {
269 const char *str = "#line 10";
270 ASSERT_TRUE(mPreprocessor.init(1, &str, nullptr));
271
272 using testing::_;
273 // Error reported about EOF.
274 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_EOF_IN_DIRECTIVE, _, _));
275
276 pp::Token token;
277 mPreprocessor.lex(&token);
278 }
279
280 // Test for an error being generated when the line number overflows - regular version
TEST_F(LocationTest,LineOverflowRegular)281 TEST_F(LocationTest, LineOverflowRegular)
282 {
283 const char *str = "#line 0x7FFFFFFF\n\n";
284
285 ASSERT_TRUE(mPreprocessor.init(1, &str, nullptr));
286
287 using testing::_;
288 // Error reported about EOF.
289 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_TOKENIZER_ERROR, _, _));
290
291 pp::Token token;
292 mPreprocessor.lex(&token);
293 }
294
295 // Test for an error being generated when the line number overflows - inside /* */ comment version
TEST_F(LocationTest,LineOverflowInComment)296 TEST_F(LocationTest, LineOverflowInComment)
297 {
298 const char *str = "#line 0x7FFFFFFF\n/*\n*/";
299
300 ASSERT_TRUE(mPreprocessor.init(1, &str, nullptr));
301
302 using testing::_;
303 // Error reported about EOF.
304 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_TOKENIZER_ERROR, _, _));
305
306 pp::Token token;
307 mPreprocessor.lex(&token);
308 }
309
310 // Test for an error being generated when the line number overflows - inside \n continuation
311 // version
TEST_F(LocationTest,LineOverflowInContinuationN)312 TEST_F(LocationTest, LineOverflowInContinuationN)
313 {
314 const char *str = "#line 0x7FFFFFFF\n \\\n\n";
315
316 ASSERT_TRUE(mPreprocessor.init(1, &str, nullptr));
317
318 using testing::_;
319 // Error reported about EOF.
320 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_TOKENIZER_ERROR, _, _));
321
322 pp::Token token;
323 mPreprocessor.lex(&token);
324 }
325
326 // Test for an error being generated when the line number overflows - inside \r\n continuation
327 // version
TEST_F(LocationTest,LineOverflowInContinuationRN)328 TEST_F(LocationTest, LineOverflowInContinuationRN)
329 {
330 const char *str = "#line 0x7FFFFFFF\n \\\r\n\n";
331
332 ASSERT_TRUE(mPreprocessor.init(1, &str, nullptr));
333
334 using testing::_;
335 // Error reported about EOF.
336 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_TOKENIZER_ERROR, _, _));
337
338 pp::Token token;
339 mPreprocessor.lex(&token);
340 }
341
342 struct LineTestParam
343 {
344 const char *str;
345 pp::Diagnostics::ID id;
346 };
347
348 class InvalidLineTest : public LocationTest, public testing::WithParamInterface<LineTestParam>
349 {};
350
TEST_P(InvalidLineTest,Identified)351 TEST_P(InvalidLineTest, Identified)
352 {
353 LineTestParam param = GetParam();
354 ASSERT_TRUE(mPreprocessor.init(1, ¶m.str, nullptr));
355
356 using testing::_;
357 // Invalid line directive call.
358 EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
359
360 pp::Token token;
361 mPreprocessor.lex(&token);
362 }
363
364 static const LineTestParam kParams[] = {
365 {"#line\n", pp::Diagnostics::PP_INVALID_LINE_DIRECTIVE},
366 {"#line foo\n", pp::Diagnostics::PP_INVALID_LINE_NUMBER},
367 {"#line defined(foo)\n", pp::Diagnostics::PP_INVALID_LINE_NUMBER},
368 {"#line 10 foo\n", pp::Diagnostics::PP_INVALID_FILE_NUMBER},
369 {"#line 10 20 foo\n", pp::Diagnostics::PP_UNEXPECTED_TOKEN},
370 {"#line 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW},
371 {"#line 10 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW}};
372
373 INSTANTIATE_TEST_SUITE_P(All, InvalidLineTest, testing::ValuesIn(kParams));
374
375 struct LineExpressionTestParam
376 {
377 const char *expression;
378 int expectedLine;
379 };
380
381 class LineExpressionTest : public LocationTest,
382 public testing::WithParamInterface<LineExpressionTestParam>
383 {};
384
TEST_P(LineExpressionTest,ExpressionEvaluation)385 TEST_P(LineExpressionTest, ExpressionEvaluation)
386 {
387 LineExpressionTestParam param = GetParam();
388 const char *strs[3] = {"#line ", param.expression, "\nfoo"};
389
390 pp::SourceLocation loc(2, param.expectedLine);
391
392 expectLocation(3, strs, nullptr, loc);
393 }
394
395 static const LineExpressionTestParam kParamsLineExpressionTest[] = {
396 {"1 + 2", 3}, {"5 - 3", 2}, {"7 * 11", 77}, {"20 / 10", 2}, {"10 % 5", 0},
397 {"7 && 3", 1}, {"7 || 0", 1}, {"11 == 11", 1}, {"11 != 11", 0}, {"11 > 7", 1},
398 {"11 < 7", 0}, {"11 >= 7", 1}, {"11 <= 7", 0}, {"!11", 0}, {"-1", -1},
399 {"+9", 9}, {"(1 + 2) * 4", 12}, {"3 | 5", 7}, {"3 ^ 5", 6}, {"3 & 5", 1},
400 {"~5", ~5}, {"2 << 3", 16}, {"16 >> 2", 4}};
401
402 INSTANTIATE_TEST_SUITE_P(All, LineExpressionTest, testing::ValuesIn(kParamsLineExpressionTest));
403
404 } // namespace angle
405