1 // 2 // Copyright (c) 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 "Token.h" 9 10 class LocationTest : public PreprocessorTest 11 { 12 protected: 13 void expectLocation(int count, 14 const char* const string[], 15 const int length[], 16 const pp::SourceLocation& location) 17 { 18 ASSERT_TRUE(mPreprocessor.init(count, string, length)); 19 20 pp::Token token; 21 mPreprocessor.lex(&token); 22 EXPECT_EQ(pp::Token::IDENTIFIER, token.type); 23 EXPECT_EQ("foo", token.text); 24 25 EXPECT_EQ(location.file, token.location.file); 26 EXPECT_EQ(location.line, token.location.line); 27 } 28 }; 29 30 TEST_F(LocationTest, String0_Line1) 31 { 32 const char* str = "foo"; 33 pp::SourceLocation loc(0, 1); 34 35 SCOPED_TRACE("String0_Line1"); 36 expectLocation(1, &str, NULL, loc); 37 } 38 39 TEST_F(LocationTest, String0_Line2) 40 { 41 const char* str = "\nfoo"; 42 pp::SourceLocation loc(0, 2); 43 44 SCOPED_TRACE("String0_Line2"); 45 expectLocation(1, &str, NULL, loc); 46 } 47 48 TEST_F(LocationTest, String1_Line1) 49 { 50 const char* const str[] = {"\n\n", "foo"}; 51 pp::SourceLocation loc(1, 1); 52 53 SCOPED_TRACE("String1_Line1"); 54 expectLocation(2, str, NULL, loc); 55 } 56 57 TEST_F(LocationTest, String1_Line2) 58 { 59 const char* const str[] = {"\n\n", "\nfoo"}; 60 pp::SourceLocation loc(1, 2); 61 62 SCOPED_TRACE("String1_Line2"); 63 expectLocation(2, str, NULL, loc); 64 } 65 66 TEST_F(LocationTest, NewlineInsideCommentCounted) 67 { 68 const char* str = "/*\n\n*/foo"; 69 pp::SourceLocation loc(0, 3); 70 71 SCOPED_TRACE("NewlineInsideCommentCounted"); 72 expectLocation(1, &str, NULL, loc); 73 } 74 75 TEST_F(LocationTest, ErrorLocationAfterComment) 76 { 77 const char* str = "/*\n\n*/@"; 78 79 ASSERT_TRUE(mPreprocessor.init(1, &str, NULL)); 80 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::INVALID_CHARACTER, 81 pp::SourceLocation(0, 3), 82 "@")); 83 84 pp::Token token; 85 mPreprocessor.lex(&token); 86 } 87 88 // The location of a token straddling two or more strings is that of the 89 // first character of the token. 90 91 TEST_F(LocationTest, TokenStraddlingTwoStrings) 92 { 93 const char* const str[] = {"f", "oo"}; 94 pp::SourceLocation loc(0, 1); 95 96 SCOPED_TRACE("TokenStraddlingTwoStrings"); 97 expectLocation(2, str, NULL, loc); 98 } 99 100 TEST_F(LocationTest, TokenStraddlingThreeStrings) 101 { 102 const char* const str[] = {"f", "o", "o"}; 103 pp::SourceLocation loc(0, 1); 104 105 SCOPED_TRACE("TokenStraddlingThreeStrings"); 106 expectLocation(3, str, NULL, loc); 107 } 108 109 TEST_F(LocationTest, EndOfFileWithoutNewline) 110 { 111 const char* const str[] = {"foo"}; 112 ASSERT_TRUE(mPreprocessor.init(1, str, NULL)); 113 114 pp::Token token; 115 mPreprocessor.lex(&token); 116 EXPECT_EQ(pp::Token::IDENTIFIER, token.type); 117 EXPECT_EQ("foo", token.text); 118 EXPECT_EQ(0, token.location.file); 119 EXPECT_EQ(1, token.location.line); 120 121 mPreprocessor.lex(&token); 122 EXPECT_EQ(pp::Token::LAST, token.type); 123 EXPECT_EQ(0, token.location.file); 124 EXPECT_EQ(1, token.location.line); 125 } 126 127 TEST_F(LocationTest, EndOfFileAfterNewline) 128 { 129 const char* const str[] = {"foo\n"}; 130 ASSERT_TRUE(mPreprocessor.init(1, str, NULL)); 131 132 pp::Token token; 133 mPreprocessor.lex(&token); 134 EXPECT_EQ(pp::Token::IDENTIFIER, token.type); 135 EXPECT_EQ("foo", token.text); 136 EXPECT_EQ(0, token.location.file); 137 EXPECT_EQ(1, token.location.line); 138 139 mPreprocessor.lex(&token); 140 EXPECT_EQ(pp::Token::LAST, token.type); 141 EXPECT_EQ(0, token.location.file); 142 EXPECT_EQ(2, token.location.line); 143 } 144 145 TEST_F(LocationTest, EndOfFileAfterEmptyString) 146 { 147 const char* const str[] = {"foo\n", "\n", ""}; 148 ASSERT_TRUE(mPreprocessor.init(3, str, NULL)); 149 150 pp::Token token; 151 mPreprocessor.lex(&token); 152 EXPECT_EQ(pp::Token::IDENTIFIER, token.type); 153 EXPECT_EQ("foo", token.text); 154 EXPECT_EQ(0, token.location.file); 155 EXPECT_EQ(1, token.location.line); 156 157 mPreprocessor.lex(&token); 158 EXPECT_EQ(pp::Token::LAST, token.type); 159 EXPECT_EQ(2, token.location.file); 160 EXPECT_EQ(1, token.location.line); 161 } 162 163 TEST_F(LocationTest, ValidLineDirective1) 164 { 165 const char* str = "#line 10\n" 166 "foo"; 167 pp::SourceLocation loc(0, 10); 168 169 SCOPED_TRACE("ValidLineDirective1"); 170 expectLocation(1, &str, NULL, loc); 171 } 172 173 TEST_F(LocationTest, ValidLineDirective2) 174 { 175 const char* str = "#line 10 20\n" 176 "foo"; 177 pp::SourceLocation loc(20, 10); 178 179 SCOPED_TRACE("ValidLineDirective2"); 180 expectLocation(1, &str, NULL, loc); 181 } 182 183 TEST_F(LocationTest, LineDirectiveCommentsIgnored) 184 { 185 const char* str = "/* bar */" 186 "#" 187 "/* bar */" 188 "line" 189 "/* bar */" 190 "10" 191 "/* bar */" 192 "20" 193 "/* bar */" 194 "// bar " 195 "\n" 196 "foo"; 197 pp::SourceLocation loc(20, 10); 198 199 SCOPED_TRACE("LineDirectiveCommentsIgnored"); 200 expectLocation(1, &str, NULL, loc); 201 } 202 203 TEST_F(LocationTest, LineDirectiveWithMacro1) 204 { 205 const char* str = "#define L 10\n" 206 "#define F(x) x\n" 207 "#line L F(20)\n" 208 "foo"; 209 pp::SourceLocation loc(20, 10); 210 211 SCOPED_TRACE("LineDirectiveWithMacro1"); 212 expectLocation(1, &str, NULL, loc); 213 } 214 215 TEST_F(LocationTest, LineDirectiveWithMacro2) 216 { 217 const char* str = "#define LOC 10 20\n" 218 "#line LOC\n" 219 "foo"; 220 pp::SourceLocation loc(20, 10); 221 222 SCOPED_TRACE("LineDirectiveWithMacro2"); 223 expectLocation(1, &str, NULL, loc); 224 } 225 226 TEST_F(LocationTest, LineDirectiveWithPredefinedMacro) 227 { 228 const char* str = "#line __LINE__ __FILE__\n" 229 "foo"; 230 pp::SourceLocation loc(0, 1); 231 232 SCOPED_TRACE("LineDirectiveWithMacro"); 233 expectLocation(1, &str, NULL, loc); 234 } 235 236 TEST_F(LocationTest, LineDirectiveNewlineBeforeStringBreak) 237 { 238 const char* const str[] = {"#line 10 20\n", "foo"}; 239 // String number is incremented after it is set by the line directive. 240 // Also notice that line number is reset after the string break. 241 pp::SourceLocation loc(21, 1); 242 243 SCOPED_TRACE("LineDirectiveNewlineBeforeStringBreak"); 244 expectLocation(2, str, NULL, loc); 245 } 246 247 TEST_F(LocationTest, LineDirectiveNewlineAfterStringBreak) 248 { 249 const char* const str[] = {"#line 10 20", "\nfoo"}; 250 // String number is incremented before it is set by the line directive. 251 pp::SourceLocation loc(20, 10); 252 253 SCOPED_TRACE("LineDirectiveNewlineAfterStringBreak"); 254 expectLocation(2, str, NULL, loc); 255 } 256 257 TEST_F(LocationTest, LineDirectiveMissingNewline) 258 { 259 const char* str = "#line 10"; 260 ASSERT_TRUE(mPreprocessor.init(1, &str, NULL)); 261 262 using testing::_; 263 // Error reported about EOF. 264 EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_DIRECTIVE, _, _)); 265 266 pp::Token token; 267 mPreprocessor.lex(&token); 268 } 269 270 struct LineTestParam 271 { 272 const char* str; 273 pp::Diagnostics::ID id; 274 }; 275 276 class InvalidLineTest : public LocationTest, 277 public testing::WithParamInterface<LineTestParam> 278 { 279 }; 280 281 TEST_P(InvalidLineTest, Identified) 282 { 283 LineTestParam param = GetParam(); 284 ASSERT_TRUE(mPreprocessor.init(1, ¶m.str, NULL)); 285 286 using testing::_; 287 // Invalid line directive call. 288 EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _)); 289 290 pp::Token token; 291 mPreprocessor.lex(&token); 292 } 293 294 static const LineTestParam kParams[] = { 295 {"#line\n", pp::Diagnostics::INVALID_LINE_DIRECTIVE}, 296 {"#line foo\n", pp::Diagnostics::INVALID_LINE_NUMBER}, 297 {"#line 10 foo\n", pp::Diagnostics::INVALID_FILE_NUMBER}, 298 {"#line 10 20 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN}, 299 {"#line 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW}, 300 {"#line 10 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW} 301 }; 302 303 INSTANTIATE_TEST_CASE_P(All, InvalidLineTest, testing::ValuesIn(kParams)); 304