xref: /aosp_15_r20/external/angle/src/tests/preprocessor_tests/location_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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, &param.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