Skip to content

Commit

Permalink
Add support for /instrument codecoverage for new language features
Browse files Browse the repository at this point in the history
  • Loading branch information
gafter committed Oct 17, 2016
1 parent d233acc commit 6c65b16
Show file tree
Hide file tree
Showing 3 changed files with 288 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,12 @@ public override BoundStatement InstrumentForEachStatementIterationVarDeclaration
{
return AddDynamicAnalysis(original, base.InstrumentForEachStatementIterationVarDeclaration(original, iterationVarDecl));
}


public override BoundStatement InstrumentForEachStatementDeconstructionVariablesDeclaration(BoundForEachStatement original, BoundStatement iterationVarDecl)
{
return AddDynamicAnalysis(original, base.InstrumentForEachStatementDeconstructionVariablesDeclaration(original, iterationVarDecl));
}

public override BoundStatement InstrumentIfStatement(BoundIfStatement original, BoundStatement rewritten)
{
return AddDynamicAnalysis(original, base.InstrumentIfStatement(original, rewritten));
Expand Down Expand Up @@ -227,16 +232,25 @@ public override BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwit

public override BoundStatement InstrumentPatternSwitchWhenClauseConditionalGotoBody(BoundExpression original, BoundStatement ifConditionGotoBody)
{
// TODO: Desired behavior for a switch when clause has not been specified.
// See also https://github.com/dotnet/roslyn/issues/14156
return base.InstrumentPatternSwitchWhenClauseConditionalGotoBody(original, ifConditionGotoBody);
ifConditionGotoBody = base.InstrumentPatternSwitchWhenClauseConditionalGotoBody(original, ifConditionGotoBody);

// Instrument the statement using a factory with the same syntax as the statement, so that the instrumentation appears to be part of the statement.
SyntheticBoundNodeFactory statementFactory = new SyntheticBoundNodeFactory(_method, original.Syntax, _methodBodyFactory.CompilationState, _diagnostics);

// Instrument using the span of the expression
return statementFactory.StatementList(AddAnalysisPoint(original.Syntax, statementFactory), ifConditionGotoBody);
}

public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement original, BoundStatement usingTargetCapture)
{
return AddDynamicAnalysis(original, base.InstrumentUsingTargetCapture(original, usingTargetCapture));
}


public override BoundStatement InstrumentLocalDeconstructionDeclaration(BoundLocalDeconstructionDeclaration original, BoundStatement rewritten)
{
return AddDynamicAnalysis(original, base.InstrumentLocalDeconstructionDeclaration(original, rewritten));
}

private BoundStatement AddDynamicAnalysis(BoundStatement original, BoundStatement rewritten)
{
if (!original.WasCompilerGenerated)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,13 +424,121 @@ class Student : Person { public double GPA; }

VerifySpans(reader, reader.Methods[1], sourceLines,
new SpanResult(13, 4, 26, 5, "static string Operate(Person p)"),
new SpanResult(17, 32, 17, 43, "s.GPA > 3.5"),
new SpanResult(18, 16, 18, 56, "return $\"Student {s.Name} ({s.GPA:N1})\""),
new SpanResult(20, 16, 20, 56, "return $\"Student {s.Name} ({s.GPA:N1})\""),
new SpanResult(22, 16, 22, 58, "return $\"Teacher {t.Name} of {t.Subject}\""),
new SpanResult(24, 16, 24, 42, "return $\"Person {p.Name}\""),
new SpanResult(15, 16, 15, 17, "p"));
}

[Fact]
public void TestDeconstructionSpans()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 1
{
var (x, y) = new C();
}
public void Deconstruct(out int x, out int y)
{
x = 1;
y = 2;
}
}
";
var c = CreateCompilationWithMscorlib(Parse(source + InstrumentationHelperSource, @"C:\myproject\doc1.cs"));
var peImage = c.EmitToArray(EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage)));

var peReader = new PEReader(peImage);
var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "<DynamicAnalysisData>");

string[] sourceLines = source.Split('\n');

VerifySpans(reader, reader.Methods[0], sourceLines,
new SpanResult(5, 4, 8, 5, "public static void Main()"),
new SpanResult(7, 8, 7, 29, "var (x, y) = new C()"));
}

[Fact]
public void TestForeachSpans()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 1
{
C[] a = null;
foreach
(var x
in a)
;
}
}
";
var c = CreateCompilationWithMscorlib(Parse(source + InstrumentationHelperSource, @"C:\myproject\doc1.cs"));
var peImage = c.EmitToArray(EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage)));

var peReader = new PEReader(peImage);
var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "<DynamicAnalysisData>");

string[] sourceLines = source.Split('\n');

VerifySpans(reader, reader.Methods[0], sourceLines,
new SpanResult(5, 4, 12, 5, "public static void Main()"),
new SpanResult(7, 8, 7, 21, "C[] a = null"),
new SpanResult(11, 12, 11, 13, ";"),
new SpanResult(10, 15, 10, 16, "a")
);
}

[Fact]
public void TestForeachDeconstructionSpans()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 1
{
C[] a = null;
foreach
(var (x, y)
in a)
;
}
public void Deconstruct(out int x, out int y)
{
x = 1;
y = 2;
}
}
";
var c = CreateCompilationWithMscorlib(Parse(source + InstrumentationHelperSource, @"C:\myproject\doc1.cs"));
var peImage = c.EmitToArray(EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage)));

var peReader = new PEReader(peImage);
var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "<DynamicAnalysisData>");

string[] sourceLines = source.Split('\n');

VerifySpans(reader, reader.Methods[0], sourceLines,
new SpanResult(5, 4, 12, 5, "public static void Main()"),
new SpanResult(7, 8, 7, 21, "C[] a = null"),
new SpanResult(11, 12, 11, 13, ";"),
new SpanResult(10, 15, 10, 16, "a")
);
}

[Fact]
public void TestFieldInitializerSpans()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,7 @@ File 1
Method 3
File 1
True
True
False
True
False
Expand Down Expand Up @@ -1405,6 +1406,166 @@ File 1
verifier.VerifyDiagnostics(Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Subject").WithArguments("Teacher.Subject", "null").WithLocation(37, 40));
}

[Fact]
public void DeconstructionStatementCoverage()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 1
{
TestMain2();
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
static void TestMain2() // Method 2
{
var (x, y) = new C();
}
static void TestMain3() // Method 3
{
var (x, y) = new C();
}
public C() // Method 4
{
}
public void Deconstruct(out int x, out int y) // Method 5
{
x = 1;
y = 2;
}
}
";
string expectedOutput = @"Flushing
Method 1
File 1
True
True
True
Method 2
File 1
True
True
Method 4
File 1
True
Method 5
File 1
True
True
True
Method 7
File 1
True
True
False
True
True
True
True
True
True
True
True
True
True
True
";
CompilationVerifier verifier = CompileAndVerify(source + InstrumentationHelperSource, expectedOutput: expectedOutput);
}

[Fact]
public void DeconstructionForeachStatementCoverage()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 1
{
TestMain2(new C[] { new C() });
TestMain3(new C[] { });
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
static void TestMain2(C[] a) // Method 2
{
foreach (
var (x, y)
in a)
;
}
static void TestMain3(C[] a) // Method 3
{
foreach (
var (x, y)
in a)
;
}
public C() // Method 4
{
}
public void Deconstruct(out int x, out int y) // Method 5
{
x = 1;
y = 2;
}
}
";
string expectedOutput = @"Flushing
Method 1
File 1
True
True
True
True
Method 2
File 1
True
True
True
Method 3
File 1
True
False
False
Method 4
File 1
True
Method 5
File 1
True
True
True
Method 7
File 1
True
True
False
True
True
True
True
True
True
True
True
True
True
True
";
CompilationVerifier verifier = CompileAndVerify(source + InstrumentationHelperSource, expectedOutput: expectedOutput);
}

[Fact]
public void LambdaCoverage()
{
Expand Down

0 comments on commit 6c65b16

Please sign in to comment.