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 10class LocationTest : public PreprocessorTest 11{ 12protected: 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 30TEST_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 39TEST_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 48TEST_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 57TEST_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 66TEST_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 75TEST_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::PP_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 91TEST_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 100TEST_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 109TEST_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 127TEST_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 145TEST_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 163TEST_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 173TEST_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 183TEST_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 203TEST_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 215TEST_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 226TEST_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 236TEST_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 247TEST_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 257TEST_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::PP_EOF_IN_DIRECTIVE, _, _)); 265 266 pp::Token token; 267 mPreprocessor.lex(&token); 268} 269 270struct LineTestParam 271{ 272 const char* str; 273 pp::Diagnostics::ID id; 274}; 275 276class InvalidLineTest : public LocationTest, 277 public testing::WithParamInterface<LineTestParam> 278{ 279}; 280 281TEST_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 294static const LineTestParam kParams[] = { 295 {"#line\n", pp::Diagnostics::PP_INVALID_LINE_DIRECTIVE}, 296 {"#line foo\n", pp::Diagnostics::PP_INVALID_LINE_NUMBER}, 297 {"#line 10 foo\n", pp::Diagnostics::PP_INVALID_FILE_NUMBER}, 298 {"#line 10 20 foo\n", pp::Diagnostics::PP_UNEXPECTED_TOKEN}, 299 {"#line 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW}, 300 {"#line 10 0xffffffff\n", pp::Diagnostics::PP_INTEGER_OVERFLOW} 301}; 302 303INSTANTIATE_TEST_CASE_P(All, InvalidLineTest, testing::ValuesIn(kParams)); 304