提交 204d75ed 编写于 作者: J John Hamby

Make instrumenting implicit constructs work for C#.

上级 73553c7c
......@@ -886,7 +886,7 @@ public override object VisitField(FieldSymbol symbol, TypeCompilationState argum
analyzedInitializers = InitializerRewriter.RewriteConstructor(processedInitializers.BoundInitializers, methodSymbol);
processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors;
if (body != null && (methodSymbol.ContainingType.IsStructType() || instrumentForDynamicAnalysis) && !methodSymbol.IsImplicitConstructor)
if (body != null && ((methodSymbol.ContainingType.IsStructType() && !methodSymbol.IsImplicitConstructor) || instrumentForDynamicAnalysis))
{
// In order to get correct diagnostics, we need to analyze initializers and the body together.
body = body.Update(body.Locals, body.LocalFunctions, body.Statements.Insert(0, analyzedInitializers));
......
......@@ -30,8 +30,8 @@ internal sealed class DynamicAnalysisInjector : CompoundInstrumenter
public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
{
// Do not instrument implicitly-declared methods.
if (!method.IsImplicitlyDeclared)
// Do not instrument implicitly-declared methods, except for constructors.
if (!method.IsImplicitlyDeclared || method.IsImplicitConstructor)
{
MethodSymbol createPayload = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics);
......@@ -64,7 +64,10 @@ private DynamicAnalysisInjector(MethodSymbol method, BoundStatement methodBody,
// The first point indicates entry into the method and has the span of the method definition.
CSharpSyntaxNode syntax = MethodDeclarationIfAvailable(methodBody.Syntax);
_methodEntryInstrumentation = AddAnalysisPoint(syntax, SkipAttributes(syntax), methodBodyFactory);
if (!method.IsImplicitlyDeclared)
{
_methodEntryInstrumentation = AddAnalysisPoint(syntax, SkipAttributes(syntax), methodBodyFactory);
}
}
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal)
......@@ -100,7 +103,11 @@ public override BoundStatement CreateBlockPrologue(BoundBlock original, out Loca
ArrayBuilder<BoundStatement> prologueStatements = ArrayBuilder<BoundStatement>.GetInstance(previousPrologue == null ? 3 : 4);
prologueStatements.Add(payloadInitialization);
prologueStatements.Add(payloadIf);
prologueStatements.Add(_methodEntryInstrumentation);
if (_methodEntryInstrumentation != null)
{
prologueStatements.Add(_methodEntryInstrumentation);
}
if (previousPrologue != null)
{
prologueStatements.Add(previousPrologue);
......
......@@ -533,6 +533,69 @@ public class C
new SpanResult(41, 8, 41, 19, "_z = a + b"));
}
[Fact]
public void TestImplicitConstructorSpans()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 0
{
TestMain();
}
static void TestMain() // Method 1
{
C local = new C();
}
static int Init() => 33; // Method 2
int _x = Init();
int _y = Init() + 12;
static int s_x = Init();
static int s_y = Init() + 153;
static int s_z = 144;
int Prop1 { get; } = 15;
static int Prop2 { get; } = 255;
}
";
var c = CreateCompilationWithMscorlib(Parse(source + InstrumentationHelperSource, @"C:\myproject\doc1.cs"));
var peImage = c.EmitToArray(EmitOptions.Default.WithInstrument("Test.Flag"));
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, 19, "TestMain()"));
VerifySpans(reader, reader.Methods[1], sourceLines,
new SpanResult(10, 4, 13, 5, "static void TestMain()"),
new SpanResult(12, 8, 12, 26, "C local = new C()"));
VerifySpans(reader, reader.Methods[2], sourceLines,
new SpanResult(15, 4, 15, 28, "static int Init() => 33"),
new SpanResult(15, 25, 15, 27, "33"));
VerifySpans(reader, reader.Methods[5], sourceLines, // Synthesized instance constructor
new SpanResult(17, 13, 17, 19, "Init()"),
new SpanResult(18, 13, 18, 24, "Init() + 12"),
new SpanResult(23, 25, 23, 27, "15"));
VerifySpans(reader, reader.Methods[6], sourceLines, // Synthesized static constructor
new SpanResult(19, 21, 19, 27, "Init()"),
new SpanResult(20, 21, 20, 33, "Init() + 153"),
new SpanResult(21, 21, 21, 24, "144"),
new SpanResult(24, 32, 24, 35, "255"));
}
[Fact]
public void TestDynamicAnalysisResourceMissingWhenInstrumentationFlagIsDisabled()
{
......
......@@ -782,6 +782,8 @@ static int Lambda(int x, Func<int, int> l)
{
return l(x);
}
// Method 11 is a synthesized static constructor.
}
";
// There is no entry for method '8' since it's a Prop2_set which is never called.
......@@ -823,6 +825,9 @@ Method 9
File 1
True
True
Method 11
File 1
True
Method 13
File 1
True
......@@ -854,27 +859,30 @@ public void MultipleFilesCoverage()
public class Program
{
#line 10 ""File1.cs""
public static void Main(string[] args)
public static void Main(string[] args) // Method 1
{
TestMain();
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
#line 20 ""File2.cs""
static void TestMain()
static void TestMain() // Method 2
{
Fred();
Fred();
Program p = new Program();
return;
}
#line 30 ""File3.cs""
static void Fred()
static void Fred() // Method 3
{
return;
}
#line 40 ""File4.cs""
#line 40 ""File5.cs""
// The synthesized instance constructor is method 4 and
// appears in the original source file, which gets file index 4.
}
";
......@@ -894,8 +902,10 @@ Method 3
File 3
True
True
Method 6
Method 4
File 4
Method 6
File 5
True
True
False
......@@ -1329,6 +1339,8 @@ public static void Main()
class Person { public string Name; }
class Teacher : Person { public string Subject; }
class Student : Person { public double GPA; }
// Methods 5 and 7 are implicit constructors.
";
string expectedOutput = @"Flushing
Method 1
......@@ -1351,6 +1363,10 @@ File 1
False
False
True
Method 5
File 1
Method 7
File 1
Method 9
File 1
True
......@@ -1658,6 +1674,89 @@ File 1
CompileAndVerify(source + InstrumentationHelperSource, expectedOutput: expectedOutput);
}
[Fact]
public void TestImplicitConstructorSpans()
{
string source = @"
using System;
public class C
{
public static void Main() // Method 1
{
TestMain();
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
static void TestMain() // Method 2
{
C local = new C();
int x = local._x + C.s_x;
}
static int Init() => 33; // Method 3
// Method 6 is the implicit instance constructor.
// Method 7 is the implicit shared constructor.
int _x = Init();
int _y = Init() + 12;
static int s_x = Init();
static int s_y = Init() + 153;
static int s_z = 144;
int Prop1 { get; } = 15;
static int Prop2 { get; } = 255;
}
";
string expectedOutput = @"
Flushing
Method 1
File 1
True
True
True
Method 2
File 1
True
True
True
Method 3
File 1
True
True
Method 6
File 1
True
True
True
Method 7
File 1
True
True
True
True
Method 9
File 1
True
True
False
True
True
True
True
True
True
True
True
True
True
True
";
CompileAndVerify(source + InstrumentationHelperSource, expectedOutput: expectedOutput);
}
[Fact]
public void MissingMethodNeededForAnalysis()
{
......
......@@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private ReadOnly _methodBodyFactory As SyntheticBoundNodeFactory
Public Shared Function TryCreate(method As MethodSymbol, methodBody As BoundStatement, methodBodyFactory As SyntheticBoundNodeFactory, diagnostics As DiagnosticBag, debugDocumentProvider As DebugDocumentProvider, previous As Instrumenter) As DynamicAnalysisInjector
' Do not instrument implicitly-declared methods.
' Do not instrument implicitly-declared methods, except for constructors.
If Not method.IsImplicitlyDeclared OrElse method.IsAnyConstructor Then
Dim createPayload As MethodSymbol = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册