未验证 提交 0fdb64eb 编写于 作者: J Julien Couvreur 提交者: GitHub

Detect unused record parameters (#48895)

上级 d7048e72
......@@ -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>
......@@ -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)
......
......@@ -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;
......
......@@ -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.
......@@ -186,6 +193,7 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass<
protected override void Free()
{
_usedVariables.Free();
_readParameters?.Free();
_usedLocalFunctions.Free();
_writtenVariables.Free();
_capturedVariables.Free();
......@@ -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);
}
}
}
}
}
......@@ -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)
......@@ -560,6 +587,8 @@ private void NoteCaptured(Symbol variable)
_usedVariables.Add(local);
}
NoteRecordParameterReadIfNeeded(variable);
var localFunction = variable as LocalFunctionSymbol;
if ((object)localFunction != null)
{
......@@ -1878,6 +1907,10 @@ public override BoundNode VisitParameter(BoundParameter node)
{
CheckAssigned(node.ParameterSymbol, node.Syntax);
}
else
{
NoteRecordParameterReadIfNeeded(node.ParameterSymbol);
}
return null;
}
......
......@@ -266,6 +266,7 @@ public static bool IsWarning(ErrorCode code)
case ErrorCode.WRN_SyncAndAsyncEntryPoints:
case ErrorCode.WRN_ParameterIsStaticClass:
case ErrorCode.WRN_ReturnTypeIsStaticClass:
case ErrorCode.WRN_UnreadRecordParameter:
return true;
default:
return false;
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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>
......
......@@ -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!;
}
......@@ -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)
);
}
......@@ -261,6 +261,7 @@ public void WarningLevel_2()
case ErrorCode.WRN_RecordNamedDisallowed:
case ErrorCode.WRN_ParameterNotNullIfNotNull:
case ErrorCode.WRN_ReturnNotNullIfNotNull:
case ErrorCode.WRN_UnreadRecordParameter:
Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode));
break;
case ErrorCode.WRN_MainIgnored:
......@@ -415,6 +416,7 @@ public void NullableWarnings()
ErrorCode.WRN_RecordNamedDisallowed,
ErrorCode.WRN_RecordEqualsWithoutGetHashCode,
ErrorCode.WRN_AnalyzerReferencesFramework,
ErrorCode.WRN_UnreadRecordParameter,
};
Assert.Contains(error, nullableUnrelatedWarnings);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册