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

CA2246 Warning for unobvious assignment #2717

Merged
merged 19 commits into from Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -252,4 +252,13 @@
<data name="AvoidPropertySelfAssignmentMessage" xml:space="preserve">
<value>The property {0} should not be assigned to itself.</value>
</data>
<data name="ReferencingAndReassigningObjectInSameStatementMessage" xml:space="preserve">
<value>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</value>
maxkoshevoi marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="ReferencingAndReassigningObjectInSameStatementTitle" xml:space="preserve">
<value>Referring to object and reassigning it in the same statement.</value>
maxkoshevoi marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="ReferencingAndReassigningObjectInSameStatementDescription" xml:space="preserve">
<value>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</value>
maxkoshevoi marked this conversation as resolved.
Show resolved Hide resolved
</data>
</root>
@@ -0,0 +1,97 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Analyzer.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;

namespace Microsoft.CodeQuality.Analyzers.QualityGuidelines
{
/// <summary>
/// CA2246: Prevent objects from being referenced in statements where they are reassigned
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class ReferencingAndReassigningObjectInSameStatement : DiagnosticAnalyzer
{
internal const string RuleId = "CA2246";

private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(MicrosoftQualityGuidelinesAnalyzersResources.ReferencingAndReassigningObjectInSameStatementTitle), MicrosoftQualityGuidelinesAnalyzersResources.ResourceManager, typeof(MicrosoftQualityGuidelinesAnalyzersResources));
private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(MicrosoftQualityGuidelinesAnalyzersResources.ReferencingAndReassigningObjectInSameStatementMessage), MicrosoftQualityGuidelinesAnalyzersResources.ResourceManager, typeof(MicrosoftQualityGuidelinesAnalyzersResources));
private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(MicrosoftQualityGuidelinesAnalyzersResources.ReferencingAndReassigningObjectInSameStatementDescription), MicrosoftQualityGuidelinesAnalyzersResources.ResourceManager, typeof(MicrosoftQualityGuidelinesAnalyzersResources));

internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
s_localizableTitle,
s_localizableMessage,
DiagnosticCategory.Usage,
DiagnosticHelpers.DefaultDiagnosticSeverity,
DiagnosticHelpers.EnabledByDefaultIfNotBuildingVSIX,
s_localizableDescription);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext context)
{
context.RegisterOperationAction(AnalyzeAssignment, OperationKind.SimpleAssignment);
}

private void AnalyzeAssignment(OperationAnalysisContext context)
{
var assignmentOperation = (ISimpleAssignmentOperation)context.Operation;

// Check if there are more then one assignment in a statement
if (!(assignmentOperation.Target is IMemberReferenceOperation operationTarget))
{
return;
}

// This analyzer makes sense only for reference type objects
if (operationTarget.Instance?.Type.IsValueType == true)
{
return;
}

// Search for object equal to operationTarget.Instance further in assignment chain
bool isViolationFound = false;
if (operationTarget.Instance is ILocalReferenceOperation localInstance)
{
isViolationFound = AnalyzeAssignmentToMember(assignmentOperation, localInstance, (a, b) => a.Local == b.Local);
}
else if (operationTarget.Instance is IMemberReferenceOperation memberInstance)
{
isViolationFound = AnalyzeAssignmentToMember(assignmentOperation, memberInstance, (a, b) => a.Member == b.Member && a.Instance?.Syntax.ToString() == b.Instance?.Syntax.ToString());
}
else if (operationTarget.Instance is IParameterReferenceOperation parameterInstance)
{
isViolationFound = AnalyzeAssignmentToMember(assignmentOperation, parameterInstance, (a, b) => a.Parameter == b.Parameter);
}
else
{
return;
}

if (isViolationFound)
{
var diagnostic = Diagnostic.Create(Rule, operationTarget.Syntax.GetLocation(), operationTarget.Instance.Syntax.ToString());
context.ReportDiagnostic(diagnostic);
}
}

private static bool AnalyzeAssignmentToMember<T>(ISimpleAssignmentOperation assignmentOperation, T instance, Func<T, T, bool> equalityComparer) where T : class, IOperation
{
// Check every simple assignments target in a statement for equality to `instance`
while (assignmentOperation.Value.Kind == OperationKind.SimpleAssignment)
{
assignmentOperation = (ISimpleAssignmentOperation)assignmentOperation.Value;

var operationValue = assignmentOperation.Target as T;
if (equalityComparer(instance, operationValue))
{
return true;
}
}
return false;
}
}
}
Expand Up @@ -22,6 +22,21 @@
<target state="translated">Některé odkazy na {0} nešlo opravit. Měly by se opravit ručně.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">Tam, kde je to vhodné, použijte literály</target>
Expand Down
Expand Up @@ -22,6 +22,21 @@
<target state="translated">Einige Verweise auf "{0}" konnten nicht korrigiert werden. Korrigieren Sie sie manuell.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">Nach Möglichkeit Literale verwenden</target>
Expand Down
Expand Up @@ -22,6 +22,21 @@
<target state="translated">Algunas referencias a "{0}" podrían no corregirse, así que tendría que hacerlo manualmente.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">Usar literales cuando resulte apropiado</target>
Expand Down
Expand Up @@ -22,6 +22,21 @@
<target state="translated">Des références à '{0}' n'ont pas pu être corrigées, elles doivent être corrigées manuellement.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">Utiliser des littéraux quand cela est approprié</target>
Expand Down
Expand Up @@ -22,6 +22,21 @@
<target state="translated">Non è stato possibile correggere alcuni riferimenti a '{0}'. Correggerli manualmente.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">Usa valori letterali dove appropriato</target>
Expand Down
Expand Up @@ -22,6 +22,21 @@
<target state="translated">'{0}' への参照を修正できませんでした。手動で修正する必要があります。</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">適切な場所にリテラルを使用します</target>
Expand Down
Expand Up @@ -22,6 +22,21 @@
<target state="translated">'{0}'에 대한 일부 참조를 수정할 수 없습니다. 수동으로 수정해야 합니다.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementDescription">
<source>When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</source>
<target state="new">When you go through the assignment chain right to left, firstly, reference in object '{0}' will be changed, but when you reffer to this object second time, since it's still the same statement, it will be pointing to it's old value. So if old value of '{0}' isn't saved elsewhere, result of the latter assignment will be lost.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementMessage">
<source>Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</source>
<target state="new">Object '{0}' is referenced and reassigned in the same statement. You are at risk of referring to unintended object.</target>
<note />
</trans-unit>
<trans-unit id="ReferencingAndReassigningObjectInSameStatementTitle">
<source>Referring to object and reassigning it in the same statement.</source>
<target state="new">Referring to object and reassigning it in the same statement.</target>
<note />
</trans-unit>
<trans-unit id="UseLiteralsWhereAppropriateTitle">
<source>Use literals where appropriate</source>
<target state="translated">적합한 리터럴을 사용하세요.</target>
Expand Down