Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass in the "isGeneratedCode" flag from editorconfig options into syn… #40330

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ public override Compilation CreateCompilation(
parseOptions,
scriptParseOptions,
analyzerConfigOptions.IsDefault
? null
: analyzerConfigOptions[i].TreeOptions,
? (AnalyzerConfigOptionsResult?)null
: analyzerConfigOptions[i],
ref hadErrors,
sourceFiles[i],
diagnosticBag,
Expand All @@ -85,8 +85,8 @@ public override Compilation CreateCompilation(
parseOptions,
scriptParseOptions,
analyzerConfigOptions.IsDefault
? null
: analyzerConfigOptions[i].TreeOptions,
? (AnalyzerConfigOptionsResult?)null
: analyzerConfigOptions[i],
ref hadErrors,
sourceFiles[i],
diagnosticBag,
Expand Down Expand Up @@ -176,7 +176,7 @@ public override Compilation CreateCompilation(
private SyntaxTree ParseFile(
CSharpParseOptions parseOptions,
CSharpParseOptions scriptParseOptions,
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions,
AnalyzerConfigOptionsResult? analyzerConfigOptionsResult,
ref bool addedDiagnostics,
CommandLineSourceFile file,
DiagnosticBag diagnostics,
Expand All @@ -198,7 +198,7 @@ private SyntaxTree ParseFile(
else
{
Debug.Assert(fileDiagnostics.Count == 0);
return ParseFile(parseOptions, scriptParseOptions, content, file, diagnosticOptions);
return ParseFile(parseOptions, scriptParseOptions, content, file, analyzerConfigOptionsResult);
}
}

Expand All @@ -207,13 +207,27 @@ private static SyntaxTree ParseFile(
CSharpParseOptions scriptParseOptions,
SourceText content,
CommandLineSourceFile file,
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions)
AnalyzerConfigOptionsResult? analyzerConfigOptionsResult)
{
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions;
bool? isUserConfiguredGeneratedCode;
if (analyzerConfigOptionsResult.HasValue)
{
diagnosticOptions = analyzerConfigOptionsResult.Value.TreeOptions;
isUserConfiguredGeneratedCode = GeneratedCodeUtilities.GetIsGeneratedCodeFromOptions(analyzerConfigOptionsResult.Value.AnalyzerOptions);
}
else
{
diagnosticOptions = null;
isUserConfiguredGeneratedCode = null;
}

var tree = SyntaxFactory.ParseSyntaxTree(
content,
file.IsScript ? scriptParseOptions : parseOptions,
file.Path,
diagnosticOptions);
diagnosticOptions,
isUserConfiguredGeneratedCode);

// prepopulate line tables.
// we will need line tables anyways and it is better to not wait until we are in emit
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*REMOVED*static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options = null, string path = "", System.Text.Encoding encoding = null, System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null) -> Microsoft.CodeAnalysis.SyntaxTree
*REMOVED*static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(Microsoft.CodeAnalysis.Text.SourceText text, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options = null, string path = "", System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree
*REMOVED*static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(string text, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options = null, string path = "", System.Text.Encoding encoding = null, System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(Microsoft.CodeAnalysis.Text.SourceText text, Microsoft.CodeAnalysis.ParseOptions options = null, string path = "", System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(string text, Microsoft.CodeAnalysis.ParseOptions options = null, string path = "", System.Text.Encoding encoding = null, System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree
Microsoft.CodeAnalysis.CSharp.Conversion.IsDefaultLiteral.get -> bool
Microsoft.CodeAnalysis.CSharp.ForEachStatementInfo.IsAsynchronous.get -> bool
Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax
Expand Down Expand Up @@ -43,6 +45,10 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AnonymousMethodExpression(Mic
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(Microsoft.CodeAnalysis.Text.SourceText text, Microsoft.CodeAnalysis.ParseOptions options = null, string path = "", System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null, bool? isGeneratedCode = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(string text, Microsoft.CodeAnalysis.ParseOptions options = null, string path = "", System.Text.Encoding encoding = null, System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions = null, bool? isGeneratedCode = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.SyntaxTree
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(string text, Microsoft.CodeAnalysis.ParseOptions options, string path, System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.SyntaxTree
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseSyntaxTree(string text, Microsoft.CodeAnalysis.ParseOptions options, string path, System.Text.Encoding encoding, System.Collections.Immutable.ImmutableDictionary<string, Microsoft.CodeAnalysis.ReportDiagnostic> diagnosticOptions, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.SyntaxTree
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax
37 changes: 32 additions & 5 deletions src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1557,9 +1557,10 @@ public static SyntaxTree ParseSyntaxTree(
string path = "",
Encoding encoding = null,
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions = null,
CancellationToken cancellationToken = default(CancellationToken))
bool? isGeneratedCode = null,
mavasani marked this conversation as resolved.
Show resolved Hide resolved
CancellationToken cancellationToken = default)
{
return ParseSyntaxTree(SourceText.From(text, encoding), options, path, diagnosticOptions, cancellationToken);
return ParseSyntaxTree(SourceText.From(text, encoding), options, path, diagnosticOptions, isGeneratedCode, cancellationToken);
}

/// <summary>
Expand All @@ -1570,9 +1571,10 @@ public static SyntaxTree ParseSyntaxTree(
ParseOptions options = null,
string path = "",
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions = null,
CancellationToken cancellationToken = default(CancellationToken))
bool? isGeneratedCode = null,
CancellationToken cancellationToken = default)
{
return CSharpSyntaxTree.ParseText(text, (CSharpParseOptions)options, path, diagnosticOptions, cancellationToken);
return CSharpSyntaxTree.ParseText(text, (CSharpParseOptions)options, path, diagnosticOptions, isGeneratedCode, cancellationToken);
}
#pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters

Expand Down Expand Up @@ -2596,9 +2598,34 @@ public static SyntaxTree ParseSyntaxTree(
ParseOptions options,
string path,
Encoding encoding,
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions,
CancellationToken cancellationToken)
{
return ParseSyntaxTree(SourceText.From(text, encoding), options, path, diagnosticOptions: null, cancellationToken);
return ParseSyntaxTree(SourceText.From(text, encoding), options, path, diagnosticOptions, isGeneratedCode: null, cancellationToken);
}

// BACK COMPAT OVERLOAD DO NOT MODIFY
[EditorBrowsable(EditorBrowsableState.Never)]
public static SyntaxTree ParseSyntaxTree(
string text,
ParseOptions options,
string path,
ImmutableDictionary<string, ReportDiagnostic> diagnosticOptions,
CancellationToken cancellationToken)
{
return CSharpSyntaxTree.ParseText(text, (CSharpParseOptions)options, path, encoding: null, diagnosticOptions, isGeneratedCode: null, cancellationToken);
}

// BACK COMPAT OVERLOAD DO NOT MODIFY
[EditorBrowsable(EditorBrowsableState.Never)]
public static SyntaxTree ParseSyntaxTree(
string text,
ParseOptions options,
string path,
Encoding encoding,
CancellationToken cancellationToken)
{
return ParseSyntaxTree(SourceText.From(text, encoding), options, path, diagnosticOptions: null, isGeneratedCode: null, cancellationToken);
}

// BACK COMPAT OVERLOAD DO NOT MODIFY
Expand Down
44 changes: 44 additions & 0 deletions src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11729,6 +11729,50 @@ private void TestAnalyzerConfigRespectedCore(DiagnosticAnalyzer analyzer, Diagno
Assert.DoesNotContain(descriptor.Id.ToString(), outWriter.ToString());
}
}

[Fact]
[WorkItem(3705, "https://github.com/dotnet/roslyn/issues/3705")]
public void IsUserConfiguredGeneratedCodeInAnalyzerConfig()
{
var dir = Temp.CreateDirectory();
var src = dir.CreateFile("temp.cs").WriteAllText(@"
class C
{
void M(C? c)
{
_ = c.ToString(); // warning CS8602: Dereference of a possibly null reference.
}
}");
var output = VerifyOutput(dir, src, additionalFlags: new[] { "/nullable" }, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false);
// warning CS8602: Dereference of a possibly null reference.
Assert.Contains("warning CS8602", output, StringComparison.Ordinal);

// generated_code = true
var analyzerConfigFile = dir.CreateFile(".editorconfig");
var analyzerConfig = analyzerConfigFile.WriteAllText(@"
[*.cs]
generated_code = true");
output = VerifyOutput(dir, src, additionalFlags: new[] { "/nullable", "/analyzerconfig:" + analyzerConfig.Path }, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false);
Assert.DoesNotContain("warning CS8602", output, StringComparison.Ordinal);
// warning CS8669: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.
Assert.Contains("warning CS8669", output, StringComparison.Ordinal);

// generated_code = false
analyzerConfig = analyzerConfigFile.WriteAllText(@"
[*.cs]
generated_code = false");
output = VerifyOutput(dir, src, additionalFlags: new[] { "/nullable", "/analyzerconfig:" + analyzerConfig.Path }, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false);
// warning CS8602: Dereference of a possibly null reference.
Assert.Contains("warning CS8602", output, StringComparison.Ordinal);

// generated_code = auto
analyzerConfig = analyzerConfigFile.WriteAllText(@"
[*.cs]
generated_code = auto");
output = VerifyOutput(dir, src, additionalFlags: new[] { "/nullable", "/analyzerconfig:" + analyzerConfig.Path }, expectedWarningCount: 1, includeCurrentAssemblyAsAnalyzerReference: false);
// warning CS8602: Dereference of a possibly null reference.
Assert.Contains("warning CS8602", output, StringComparison.Ordinal);
}
}

[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5585,6 +5585,7 @@ static void H()
}

[Fact]
[WorkItem(3705, "https://github.com/dotnet/roslyn/issues/3705")]
public void GeneratedSyntaxTrees_Nullable()
{
var source1 = CSharpSyntaxTree.ParseText(@"
Expand Down Expand Up @@ -5626,7 +5627,19 @@ static void I(object x)

Assert.False(((CSharpSyntaxTree)source3).IsGeneratedCode());

var comp = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Enable));
var source4 = SyntaxFactory.ParseSyntaxTree(@"
partial class Program
{
static void J(object x)
{
x = null; // no warning
F = null; // no warning
}
}", isGeneratedCode: true);

Assert.True(((CSharpSyntaxTree)source4).IsGeneratedCode());

var comp = CreateCompilation(new[] { source1, source2, source3, source4 }, options: TestOptions.DebugDll.WithNullableContextOptions(NullableContextOptions.Enable));
comp.VerifyDiagnostics(
// (6,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
// x = null; // warning 3
Expand Down
14 changes: 4 additions & 10 deletions src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1946,18 +1946,12 @@ protected bool IsGeneratedCode(SyntaxTree tree)

bool computeIsGeneratedCode()
{
// First check for explicit user configuration for generated code.
// Check for explicit user configuration for generated code from options.
// generated_code = true | false
// If there is no explicit user configuration, fallback to our generated code heuristic.
var options = AnalyzerExecutor.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(tree);
if (options.TryGetValue("generated_code", out string optionValue) &&
bool.TryParse(optionValue, out var boolValue))
{
return boolValue;
}

// Either no explicit user configuration or we don't recognize the option value.
// Compute isGeneratedCode using our generated code heuristic.
return _isGeneratedCode(tree, AnalyzerExecutor.CancellationToken);
return GeneratedCodeUtilities.GetIsGeneratedCodeFromOptions(options) ??
_isGeneratedCode(tree, AnalyzerExecutor.CancellationToken);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
#nullable enable

using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Roslyn.Utilities
{
Expand Down Expand Up @@ -142,5 +144,33 @@ private static bool BeginsWithAutoGeneratedComment(

return false;
}

internal static bool? GetIsGeneratedCodeFromOptions(ImmutableDictionary<string, string> options)
{
// Check for explicit user configuration for generated code.
// generated_code = true | false
if (options.TryGetValue("generated_code", out string optionValue) &&
bool.TryParse(optionValue, out var boolValue))
{
return boolValue;
}

// Either no explicit user configuration or we don't recognize the option value.
return null;
}

internal static bool? GetIsGeneratedCodeFromOptions(AnalyzerConfigOptions options)
{
// Check for explicit user configuration for generated code.
// generated_code = true | false
if (options.TryGetValue("generated_code", out string optionValue) &&
mavasani marked this conversation as resolved.
Show resolved Hide resolved
bool.TryParse(optionValue, out var boolValue))
{
return boolValue;
}

// Either no explicit user configuration or we don't recognize the option value.
return null;
}
}
}
Loading