2015-06-08 11 views
20

Ho il seguente codice che mi dirà se una certa proprietà è usata o meno nel codice. L'idea alla base di questo è verificare se una proprietà con un setter private può essere effettuata in sola lettura.Perché ReSharper mi dice che questa espressione è sempre vera?

Qui ci sono diversi trucchi, ma i più importanti sono che un'assegnazione alla proprietà al di fuori del costruttore significa che non sparerà. Inoltre, una proprietà statica può avere solo un'assegnazione in un costruttore statico per attivare la diagnostica. Allo stesso modo, una proprietà di istanza richiede solo un costruttore di istanze.

Ora, la maggior parte degli scenari che ho finora sono spiegati, ma ReSharper mi dà un avvertimento in questo pezzo di codice e non riesco a capire la sua logica. La specifica di cui sopra è tradotto in questa porzione di codice:

var isStaticProperty = propertySymbol.IsStatic; 
bool hasInstanceUsage = false; 
bool hasStaticUsage = false; 

foreach (var identifier in outerClass.DescendantNodes().OfType<IdentifierNameSyntax>()) 
{ 
    var memberSymbol = context.SemanticModel.GetSymbolInfo(identifier); 
    if (memberSymbol.Symbol.Equals(propertySymbol)) 
    { 
     var constructor = identifier.Ancestors().OfType<ConstructorDeclarationSyntax>() 
               .FirstOrDefault(); 
     var isInConstructor = constructor != null; 
     var isAssignmentExpression = identifier.Ancestors() 
               .OfType<AssignmentExpressionSyntax>() 
               .FirstOrDefault() != null; 

     // Skip anything that isn't a setter 
     if (!isAssignmentExpression) 
     { 
      continue; 
     } 

     // if it is a setter but outside the constructor, we don't report any diagnostic 
     if (!isInConstructor) 
     { 
      return; 
     } 

     var isStaticConstructor = context.SemanticModel 
             .GetDeclaredSymbol(constructor).IsStatic; 
     if (isStaticConstructor && isStaticProperty) 
     { 
      hasStaticUsage = true; 
     } 

     if (!isStaticConstructor && !isStaticProperty) 
     { 
      hasInstanceUsage = true; 
     } 
    } 
} 

// We can't set it to readonly if it's set in both the instance 
// and the static constructor 
// We need a NAND operation: either it's never set, 
// it's set in ctor 1 or it's set in ctor 2 
if (!(hasStaticUsage & hasInstanceUsage)) 
{ 
    context.ReportDiagnostic(Diagnostic.Create(
       Rule, property.Identifier.GetLocation(), propertySymbol.Name)); 
} 

Con l'avvertimento essendo

espressione è sempre vero

sulla linea

if (!(hasStaticUsage & hasInstanceUsage)) 

Perché mostra questo avvertimento? Ci sono una quantità sconosciuta di discendenti quindi c'è una quantità sconosciuta di loop. Ogni loop può impostare hasStaticUsage o hasInstanceUsage a true, il che significa che dopo 2 cicli (al più presto), entrambi i valori potrebbero diventare true e se condizione dovrebbe sicuro: un NAND restituisce true, true, true, false.

Questa è la logica booleana ho intenzione di compiere:

+----------------+------------------+--------+ 
| hasStaticUsage | hasInstanceUsage | result | 
+----------------+------------------+--------+ 
| false   | false   | true | 
| false   | true    | true | 
| true   | false   | true | 
| true   | true    | false | 
+----------------+------------------+--------+ 
+0

Dove è inizializzato 'isStaticProperty'? –

+0

Allo stesso livello di 'hasInstanceUsage'. Lo includerò per completezza, ma non penso che abbia un impatto. –

+0

'Ho il seguente codice che mi dirà se una certa proprietà è usata o meno altrove nel codice' - non è questa una caratteristica nativa in VS? – Davor

risposta

25

isStaticProperty viene inizializzata all'esterno del ciclo:

var isStaticProperty = propertySymbol.IsStatic; 

Se isStaticProperty è falso, allora questa espressione:

(isStaticConstructor && isStaticProperty) 

è sempre falso, quindi hasStaticUsage è falso.

Se isStaticProperty è vero, allora questa espressione:

(!isStaticConstructor && !isStaticProperty) 

è sempre falso, quindi hasInstanceUsage è falso.

In ogni caso, hasStaticUsage e hasInstanceUsage non possono essere entrambi veri allo stesso tempo.

10

Questo blocco rende impossibile che si potrà mai impostare entrambe le variabili a true:

if (isStaticConstructor && isStaticProperty) 
{ 
    hasStaticUsage = true; 
} 

if (!isStaticConstructor && !isStaticProperty) 
{ 
    hasInstanceUsage = true; 
} 

solo una delle variabili può mai essere impostato su true. Quindi la tua istruzione if sarà sempre l'equivalente di !false == true.

+0

L'avviso persiste. –

+0

@JeroenVannevel si prega di consultare la mia modifica. Hai un problema logico altrove nel codice. –

+0

Si è scoperto che era davvero a causa di quella 'isStaticProperty' booleana che ho completamente trascurato. Apprezzo che tu stia cercando con me. –

14

È possibile trovare la risposta creando una tabella di verità per queste espressioni. isStaticConstructor && isStaticProperty e !isStaticConstructor && !isStaticProperty. Facciamolo assieme.

isStaticConstructor & & isStaticProperty

+---------------------+------------------+--------+ 
| isStaticConstructor | isStaticProperty | result | 
+---------------------+------------------+--------+ 
| false    | false   | false | 
| false    | true    | false | 
| true    | false   | false | 
| true    | true    | true | 
+---------------------+------------------+--------+ 

! IsStaticConstructor & &! IsStaticProperty

+---------------------+------------------+--------+ 
| isStaticConstructor | isStaticProperty | result | 
+---------------------+------------------+--------+ 
| false    | false   | true | 
| false    | true    | false | 
| true    | false   | false | 
| true    | true    | false | 
+---------------------+------------------+--------+ 

Così si può vedere, che non v'è alcuna possibilità che il sia isStaticConstructor && isStaticProperty e !isStaticConstructor && !isStaticProperty per essere true.

Quindi, a seconda della tabella di verità fornita, l'unica possibilità che !(hasStaticUsage & hasInstanceUsage) diventa false è quando entrambe le espressioni sono true nello stesso tempo, il che è impossibile.

+0

Questa è stata davvero la causa: non ho effettuato la connessione con 'isStaticProperty' e ho dimenticato che non poteva cambiare durante i cicli. –

Problemi correlati