Skip to content

Commit

Permalink
Detect unused record parameters (#48895)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv authored Oct 31, 2020
1 parent d7048e7 commit 0fdb64e
Show file tree
Hide file tree
Showing 21 changed files with 761 additions and 65 deletions.
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6579,4 +6579,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_FunctionPointersCannotBeCalledWithNamedArguments" xml:space="preserve">
<value>A function pointer cannot be called with named arguments.</value>
</data>
<data name="WRN_UnreadRecordParameter" xml:space="preserve">
<value>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</value>
</data>
<data name="WRN_UnreadRecordParameter_Title" xml:space="preserve">
<value>Parameter is unread. Did you forget to use it to initialize the property with that name?</value>
</data>
</root>
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1924,6 +1924,8 @@ internal enum ErrorCode

ERR_EqualityContractRequiresGetter = 8906,

WRN_UnreadRecordParameter = 8907,

#endregion diagnostics introduced for C# 9.0

// Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd)
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_ParameterNotNullIfNotNull:
case ErrorCode.WRN_ReturnNotNullIfNotNull:
case ErrorCode.WRN_AnalyzerReferencesFramework:
case ErrorCode.WRN_UnreadRecordParameter:
return 1;
default:
return 0;
Expand Down
33 changes: 33 additions & 0 deletions src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass<
/// </summary>
private readonly PooledHashSet<LocalSymbol> _usedVariables = PooledHashSet<LocalSymbol>.GetInstance();

#nullable enable
/// <summary>
/// Parameters of record primary constructors that were read anywhere.
/// </summary>
private PooledHashSet<ParameterSymbol>? _readParameters;
#nullable disable

/// <summary>
/// Variables that were used anywhere, in the sense required to suppress warnings about
/// unused variables.
Expand Down Expand Up @@ -186,6 +193,7 @@ internal DefiniteAssignmentPass(
protected override void Free()
{
_usedVariables.Free();
_readParameters?.Free();
_usedLocalFunctions.Free();
_writtenVariables.Free();
_capturedVariables.Free();
Expand Down Expand Up @@ -506,6 +514,17 @@ protected void Analyze(ref bool badRegion, DiagnosticBag diagnostics)
}

diagnostics.AddRange(this.Diagnostics);

if (CurrentSymbol is SynthesizedRecordConstructor)
{
foreach (ParameterSymbol parameter in MethodParameters)
{
if (_readParameters?.Contains(parameter) != true)
{
diagnostics.Add(ErrorCode.WRN_UnreadRecordParameter, parameter.Locations.FirstOrNone(), parameter.Name);
}
}
}
}
}

Expand Down Expand Up @@ -550,6 +569,14 @@ private void NoteCaptured(Symbol variable)

#region Tracking reads/writes of variables for warnings

private void NoteRecordParameterReadIfNeeded(Symbol symbol)
{
if (symbol is ParameterSymbol { ContainingSymbol: SynthesizedRecordConstructor } parameter)
{
_readParameters ??= PooledHashSet<ParameterSymbol>.GetInstance();
_readParameters.Add(parameter);
}
}
protected virtual void NoteRead(
Symbol variable,
ParameterSymbol rangeVariableUnderlyingParameter = null)
Expand All @@ -560,6 +587,8 @@ protected virtual void NoteRead(
_usedVariables.Add(local);
}

NoteRecordParameterReadIfNeeded(variable);

var localFunction = variable as LocalFunctionSymbol;
if ((object)localFunction != null)
{
Expand Down Expand Up @@ -1878,6 +1907,10 @@ public override BoundNode VisitParameter(BoundParameter node)
{
CheckAssigned(node.ParameterSymbol, node.Syntax);
}
else
{
NoteRecordParameterReadIfNeeded(node.ParameterSymbol);
}

return null;
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Není inicializované pole, které nemůže mít hodnotu null. Zvažte možnost deklarovat ho jako typ s možnou hodnotou null.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Das Non-Nullable-Feld ist nicht initialisiert. Deklarieren Sie das Feld ggf. als "Nullable".</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">El campo que acepta valores NULL está sin inicializar. Considere la posibilidad de declararlo como que acepta valores NULL.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Le champ non-nullable n'est pas initialisé. Déclarez-le comme étant nullable.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Il campo che non ammette i valori Null non è inizializzato. Provare a dichiararlo in modo che ammetta i valori Null.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Null 非許容フィールドは初期化されていません。null 許容として宣言することを検討してください。</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">null을 허용하지 않는 필드가 초기화되지 않았습니다. nullable로 선언하는 것이 좋습니다.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Nienullowalne pole jest niezainicjowane. Rozważ zadeklarowanie go jako nullowalnego.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2879,6 +2879,16 @@
<target state="needs-review-translation">O campo não anulável não foi inicializado. Considere declará-lo como anulável.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Поле, не допускающее значение NULL, не инициализировано. Рекомендуется объявить его как допускающее значение NULL.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">Null değer atanamayan alan başlatılmadı. Bunu null değer atanabilir olarak tanımlamayı deneyin.</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">不可为 null 的字段未初始化。请考虑声明为可以为 null。</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,16 @@
<target state="needs-review-translation">不可為 null 的欄位未初始化。請考慮宣告為可為 null。</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter">
<source>Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UnreadRecordParameter_Title">
<source>Parameter is unread. Did you forget to use it to initialize the property with that name?</source>
<target state="new">Parameter is unread. Did you forget to use it to initialize the property with that name?</target>
<note />
</trans-unit>
<trans-unit id="WRN_UseDefViolation">
<source>Use of unassigned local variable '{0}'</source>
<target state="new">Use of unassigned local variable '{0}'</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68086,7 +68086,7 @@ record Rec2<T>(T t = default)
T t { get; } = t; // 2
}

record Rec3<T>(T t = default)
record Rec3<T>(T t = default) // 3
{
T t { get; } = default!;
}
Expand All @@ -68098,7 +68098,10 @@ record Rec3<T>(T t = default)
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "T t = default").WithLocation(2, 16),
// (8,19): warning CS8601: Possible null reference assignment.
// T t { get; } = t; // 2
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(8, 19)
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(8, 19),
// (11,18): warning CS8907: Parameter 't' is unread. Did you forget to use it to initialize the property with that name?
// record Rec3<T>(T t = default) // 3
Diagnostic(ErrorCode.WRN_UnreadRecordParameter, "t").WithArguments("t").WithLocation(11, 18)
);
}

Expand Down
Loading

0 comments on commit 0fdb64e

Please sign in to comment.