Index: runtime/vm/flow_graph_builder_test.cc |
diff --git a/runtime/vm/flow_graph_builder_test.cc b/runtime/vm/flow_graph_builder_test.cc |
index 91a13b250cb69dcdc5b28a35ffc294c97a3822b9..2213d0bf9531320fb813730eba1b50f7d4523746 100644 |
--- a/runtime/vm/flow_graph_builder_test.cc |
+++ b/runtime/vm/flow_graph_builder_test.cc |
@@ -95,6 +95,26 @@ class SourcePositionTest : public ValueObject { |
DUMP_ASSERT(count > 0); |
} |
+ // Expect to find an instance call at |line| and |column|. |
+ void InstanceCallAt(const char* needle, |
+ intptr_t line, |
+ intptr_t column = -1) { |
+ ZoneGrowableArray<Instruction*>* instructions = |
+ FindInstructionsAt(line, column); |
+ intptr_t count = 0; |
+ for (intptr_t i = 0; i < instructions->length(); i++) { |
+ Instruction* instr = instructions->At(i); |
+ EXPECT(instr != NULL); |
+ if (instr->IsInstanceCall()) { |
+ const char* haystack = instr->ToCString(); |
+ if (strstr(haystack, needle) != NULL) { |
+ count++; |
+ } |
+ } |
+ } |
+ DUMP_ASSERT(count > 0); |
+ } |
+ |
// Expect to find at least one static call at |line| and |column|. The |
// static call will have |needle| in its |ToCString| representation. |
void StaticCallAt(const char* needle, |
@@ -146,9 +166,26 @@ class SourcePositionTest : public ValueObject { |
} |
} |
+ // Fails if any of the IR nodes has a token position of Token::kNoSourcePos. |
+ void EnsureSourcePositions() { |
+ for (intptr_t i = 0; i < blocks_->length(); i++) { |
+ BlockEntryInstr* entry = (*blocks_)[i]; |
+ DUMP_ASSERT(entry->token_pos() != Token::kNoSourcePos); |
+ for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
+ Instruction* instr = it.Current(); |
+ DUMP_ASSERT(instr->token_pos() != Token::kNoSourcePos); |
+ } |
+ } |
+ } |
+ |
private: |
void DumpInstruction(Instruction* instr) { |
- const intptr_t token_pos = instr->token_pos(); |
+ intptr_t token_pos = instr->token_pos(); |
+ bool synthetic = false; |
+ if (Token::IsSynthetic(token_pos)) { |
+ synthetic = true; |
+ token_pos = Token::FromSynthetic(token_pos); |
+ } |
if (token_pos < 0) { |
const char* token_pos_string = |
ClassifyingTokenPositions::ToCString(token_pos); |
@@ -161,10 +198,17 @@ class SourcePositionTest : public ValueObject { |
&token_line, |
&token_column, |
NULL); |
- THR_Print(" %02d:%02d -- %s\n", |
- static_cast<int>(token_line), |
- static_cast<int>(token_column), |
- instr->ToCString()); |
+ if (synthetic) { |
+ THR_Print(" *%02d:%02d -- %s\n", |
+ static_cast<int>(token_line), |
+ static_cast<int>(token_column), |
+ instr->ToCString()); |
+ } else { |
+ THR_Print(" %02d:%02d -- %s\n", |
+ static_cast<int>(token_line), |
+ static_cast<int>(token_column), |
+ instr->ToCString()); |
+ } |
} |
Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) { |
@@ -185,6 +229,9 @@ class SourcePositionTest : public ValueObject { |
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
Instruction* instr = it.Current(); |
intptr_t token_pos = instr->token_pos(); |
+ if (Token::IsSynthetic(token_pos)) { |
+ token_pos = Token::FromSynthetic(token_pos); |
+ } |
if (token_pos < 0) { |
continue; |
} |
@@ -267,6 +314,8 @@ TEST_CASE(SourcePosition_InstanceCalls) { |
spt.InstanceCallAt(4, 13, Token::kADD); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 3); |
spt.FuzzyInstructionMatchAt("Return", 5, 3); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -294,6 +343,8 @@ TEST_CASE(SourcePosition_If) { |
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3); |
spt.FuzzyInstructionMatchAt("Return", 7, 3); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -323,6 +374,8 @@ TEST_CASE(SourcePosition_ForLoop) { |
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3); |
spt.FuzzyInstructionMatchAt("Return", 7, 3); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -370,6 +423,8 @@ TEST_CASE(SourcePosition_While) { |
spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3); |
spt.FuzzyInstructionMatchAt("Return", 10, 3); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -408,6 +463,8 @@ TEST_CASE(SourcePosition_WhileContinueBreak) { |
spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3); |
spt.FuzzyInstructionMatchAt("Return", 10, 3); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -445,6 +502,8 @@ TEST_CASE(SourcePosition_LoadIndexed) { |
spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1); |
spt.FuzzyInstructionMatchAt("Return", 6, 1); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -487,6 +546,8 @@ TEST_CASE(SourcePosition_StoreIndexed) { |
spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1); |
spt.FuzzyInstructionMatchAt("Return", 6, 1); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -535,6 +596,8 @@ TEST_CASE(SourcePosition_BitwiseOperations) { |
spt.FuzzyInstructionMatchAt("LoadLocal(z", 9, 10); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3); |
spt.FuzzyInstructionMatchAt("Return", 9, 3); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -563,6 +626,8 @@ TEST_CASE(SourcePosition_IfElse) { |
spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 12); |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 5); |
spt.FuzzyInstructionMatchAt("Return", 7, 5); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -607,6 +672,8 @@ TEST_CASE(SourcePosition_Switch) { |
spt.FuzzyInstructionMatchAt("Constant(#5", 7, 21); // '5' |
spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 14); |
spt.FuzzyInstructionMatchAt("Return", 7, 14); |
+ |
+ spt.EnsureSourcePositions(); |
} |
@@ -657,6 +724,82 @@ TEST_CASE(SourcePosition_TryCatchFinally) { |
spt.FuzzyInstructionMatchAt("Constant(#99", 10, 12); // '9' |
spt.FuzzyInstructionMatchAt("Return", 10, 5); // 'r' |
+ |
+ spt.EnsureSourcePositions(); |
+} |
+ |
+ |
+TEST_CASE(SourcePosition_InstanceFields) { |
+ const char* kScript = |
+ "class A {\n" |
+ " var x;\n" |
+ " var y;\n" |
+ "}\n" |
+ "main() {\n" |
+ " var z = new A();\n" |
+ " z.x = 99;\n" |
+ " z.y = z.x;\n" |
+ " return z.y;\n" |
+ "}\n"; |
+ |
+ SourcePositionTest spt(thread, kScript); |
+ spt.BuildGraphFor("main"); |
+ spt.FuzzyInstructionMatchAt("AllocateObject(A)", 6, 15); // 'A' |
+ spt.FuzzyInstructionMatchAt("StaticCall", 6, 15); // 'A' |
+ spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 9); // '=' |
+ spt.InstanceCallAt("set:x", 7, 5); // 'x' |
+ spt.InstanceCallAt("get:x", 8, 11); // 'x' |
+ spt.InstanceCallAt("set:y", 8, 5); // 'y' |
+ |
+ spt.InstanceCallAt("get:y", 9, 12); // 'y' |
+ spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3); |
+ spt.FuzzyInstructionMatchAt("Return", 9, 3); |
+ |
+ spt.EnsureSourcePositions(); |
+} |
+ |
+ |
+TEST_CASE(SourcePosition_Async) { |
+ const char* kScript = |
+ "import 'dart:async';\n" |
+ "var x = 5;\n" |
+ "var y = 5;\n" |
+ "foo(Future f1, Future f2) async {\n" |
+ " await f1;\n" |
+ " await f2;\n" |
+ " return 55;\n" |
+ "}\n" |
+ "main() {\n" |
+ " foo(new Future.value(33));\n" |
+ "}\n"; |
+ |
+ SourcePositionTest spt(thread, kScript); |
+ spt.BuildGraphFor("foo"); |
+ spt.EnsureSourcePositions(); |
+ spt.Dump(); |
+} |
+ |
+ |
+static bool SyntheticRoundTripTest(intptr_t token_pos) { |
+ return Token::FromSynthetic(Token::ToSynthetic(token_pos)) == token_pos; |
+} |
+ |
+ |
+UNIT_TEST_CASE(SourcePosition_SyntheticTokens) { |
+ EXPECT(Token::kNoSourcePos == -1); |
+ EXPECT(Token::kMinSourcePos == 0); |
+ EXPECT(Token::kMaxSourcePos > 0); |
+ |
+ EXPECT(!Token::IsSynthetic(0)); |
+ EXPECT(Token::IsSynthetic(Token::ToSynthetic(0))); |
+ EXPECT(Token::IsSynthetic(Token::ToSynthetic(9))); |
+ EXPECT(!Token::IsSynthetic(Token::FromSynthetic(-1))); |
+ EXPECT(!Token::IsSynthetic(ClassifyingTokenPositions::kPrivate)); |
+ EXPECT(!Token::IsSynthetic(ClassifyingTokenPositions::kLast)); |
+ |
+ EXPECT(SyntheticRoundTripTest(0)); |
+ EXPECT(SyntheticRoundTripTest(Token::kMaxSourcePos)); |
+ EXPECT(SyntheticRoundTripTest(Token::kMinSourcePos)); |
} |
} // namespace dart |