Skip to content

Commit

Permalink
Test SemanticModel
Browse files Browse the repository at this point in the history
  • Loading branch information
cston committed Dec 9, 2020
1 parent 27ccf02 commit 92c6bee
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ ThreeState calculateResult()
}
}

#if DEBUG
internal bool ShouldRunNullableWalkerInDebug => Feature("nullableAnalysis") != "false";
#endif

/// <summary>
/// The language version that was used to parse the syntax trees of this compilation.
/// </summary>
Expand Down
10 changes: 8 additions & 2 deletions src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1730,7 +1730,10 @@ private BoundNode GetBoundLambdaOrQuery(CSharpSyntaxNode lambdaOrQuery)

// https://github.com/dotnet/roslyn/issues/35038: We need to do a rewrite here, and create a test that can hit this.
#if DEBUG
AnalyzeBoundNodeNullability(boundOuterExpression, incrementalBinder, diagnostics: new DiagnosticBag(), createSnapshots: false);
if (Compilation.ShouldRunNullableWalkerInDebug)
{
AnalyzeBoundNodeNullability(boundOuterExpression, incrementalBinder, diagnostics: new DiagnosticBag(), createSnapshots: false);
}
#endif

nodes = GuardedAddBoundTreeAndGetBoundNodeFromMap(lambdaOrQuery, boundOuterExpression);
Expand Down Expand Up @@ -2003,7 +2006,10 @@ void rewriteAndCache(DiagnosticBag diagnosticBag)
#if DEBUG
if (!Compilation.NullableSemanticAnalysisEnabled)
{
AnalyzeBoundNodeNullability(boundRoot, binder, diagnosticBag, createSnapshots: true);
if (Compilation.ShouldRunNullableWalkerInDebug)
{
AnalyzeBoundNodeNullability(boundRoot, binder, diagnosticBag, createSnapshots: true);
}
return;
}
#endif
Expand Down
13 changes: 3 additions & 10 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ internal static void AnalyzeIfNeeded(
if (compilation.LanguageVersion < MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion() || !compilation.ShouldRunNullableWalker)
{
#if DEBUG
if (ShouldRunAnalysisInDebug(compilation))
if (compilation.ShouldRunNullableWalkerInDebug)
{
// Always run analysis in debug builds so that we can more reliably catch
// nullable regressions e.g. https://github.com/dotnet/roslyn/issues/40136
Expand All @@ -1092,13 +1092,6 @@ internal static void AnalyzeIfNeeded(
Analyze(compilation, method, node, diagnostics, useConstructorExitWarnings, initialNullableState, getFinalNullableState, out finalNullableState);
}

#if DEBUG
private static bool ShouldRunAnalysisInDebug(CSharpCompilation compilation)
{
return compilation.Feature("nullableAnalysis") != "false";
}
#endif

internal static void Analyze(
CSharpCompilation compilation,
MethodSymbol method,
Expand Down Expand Up @@ -1305,7 +1298,7 @@ internal static bool NeedsAnalysis(CSharpCompilation compilation)
#if DEBUG
// Always run analysis in debug builds so that we can more reliably catch
// nullable regressions e.g. https://github.com/dotnet/roslyn/issues/40136
return ShouldRunAnalysisInDebug(compilation);
return compilation.ShouldRunNullableWalkerInDebug;
#else
var canSkipAnalysis = compilation.LanguageVersion < MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion() || !compilation.ShouldRunNullableWalker;
return !canSkipAnalysis;
Expand All @@ -1322,7 +1315,7 @@ internal static void AnalyzeIfNeeded(
if (compilation.LanguageVersion < MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion() || !compilation.ShouldRunNullableWalker)
{
#if DEBUG
if (ShouldRunAnalysisInDebug(compilation))
if (compilation.ShouldRunNullableWalkerInDebug)
{
// Always run analysis in debug builds so that we can more reliably catch
// nullable regressions e.g. https://github.com/dotnet/roslyn/issues/40136
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,61 @@ void verify(CSharpParseOptions parseOptions, params string[] expectedAnalyzedKey
}
}

[Fact]
public void NullableAnalysisFlags_04()
{
var source =
@"#nullable enable
class Program
{
static object F(object? obj)
{
if (obj == null) return null; // 1
return obj;
}
}";

// https://github.com/dotnet/roslyn/issues/49746: Currently, if we analyze any members, we analyze all.
var expectedAnalyzedKeysAll = new[] { ".cctor", ".ctor", "F" };

verify(parseOptions: TestOptions.Regular, expectedFlowState: true, expectedAnalyzedKeysAll);
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", null), expectedFlowState: true, expectedAnalyzedKeysAll);
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", "true"), expectedFlowState: true, expectedAnalyzedKeysAll);
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", "false"), expectedFlowState: false);
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", "false").WithFeature("run-nullable-analysis", "false"), expectedFlowState: false);
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", "false").WithFeature("run-nullable-analysis", "true"), expectedFlowState: true, "F");
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", "true").WithFeature("run-nullable-analysis", "false"), expectedFlowState: false, expectedAnalyzedKeysAll);
verify(parseOptions: TestOptions.Regular.WithFeature("nullableAnalysis", "true").WithFeature("run-nullable-analysis", "true"), expectedFlowState: true, expectedAnalyzedKeysAll);

void verify(CSharpParseOptions parseOptions, bool expectedFlowState, params string[] expectedAnalyzedKeys)
{
var comp = CreateCompilation(source, parseOptions: parseOptions);
comp.NullableAnalysisData = new ConcurrentDictionary<object, int>();
if (expectedAnalyzedKeys.Length > 0)
{
comp.VerifyDiagnostics(
// (6,33): warning CS8603: Possible null reference return.
// if (obj == null) return null; // 1
Diagnostic(ErrorCode.WRN_NullReferenceReturn, "null").WithLocation(6, 33));
}
else
{
comp.VerifyDiagnostics();
}

var syntaxTree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(syntaxTree);
var statement = syntaxTree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Skip(1).Single();
Assert.Equal("return obj;", statement.ToString());
var typeInfo = model.GetTypeInfo(statement.Expression);
var expectedNullability = expectedFlowState ? Microsoft.CodeAnalysis.NullableFlowState.NotNull : Microsoft.CodeAnalysis.NullableFlowState.None;
Assert.Equal(expectedNullability, typeInfo.Nullability.FlowState);

var actualAnalyzedKeys = GetNullableDataKeysAsStrings(comp.NullableAnalysisData);
AssertEx.Equal(expectedAnalyzedKeys, actualAnalyzedKeys);
}
}

private static string[] GetNullableDataKeysAsStrings(ConcurrentDictionary<object, int> nullableData) =>
nullableData.Keys.Select(key => GetNullableDataKeyAsString(key)).OrderBy(key => key).ToArray();

Expand Down

0 comments on commit 92c6bee

Please sign in to comment.