Für neu eingestellte Entwickler im PVS-Studio-Team ist es Tradition geworden, zunächst einen Artikel zu schreiben, in dem Fehler besprochen werden, die der Analysator in einem Open-Source-Projekt gefunden hat. Telerik UI für UWP ist das Projekt, das für die heutige Überprüfung ausgewählt wurde.
PVS-Studio Code Analyzer
PVS-Studio ist ein Tool zum Erkennen von Fehlern und potenziellen Schwachstellen im Quellcode von Programmen, die in C, C ++, C # und Java geschrieben wurden. Der Analysator läuft unter Windows, Linux und MacOS.
PVS-Studio kann auf verschiedene Arten ausgeführt werden:
- als Plugin für Visual Studio oder IntelliJ IDEA lokal auf den einzelnen Computern der Entwickler;
- durch Integration in SonarQube: die Plattform für die kontinuierliche Überprüfung der Codequalität;
- als eigenständige Anwendung zur Integration in ein Build-System;
- durch Ausführen in Kombination mit einem speziellen Dienstprogramm zur Kompilierungsüberwachung;
- durch Integration in Azure DevOps, Jenkins, TeamCity, Travis CI und andere ähnliche Systeme;
- usw.
Das zu analysierende Projekt
Telerik UI for UWP ist eine Reihe von UI-Steuerelementen für die Universal Windows Platform (UWP). Der Quellcode des Projekts ist
bei Github erhältlich . Das Set enthält über 20 Komponenten, mit denen Benutzer Daten in Diagrammform visualisieren, Listen und Tabellen erstellen und mithilfe einer Karte Inhalte in einem geografischen Kontext anzeigen können.
Interessante Codefragmente, die vom Analysator gemeldet wurden
PVS-Studio-Diagnosemeldung: V3013 Es ist merkwürdig, dass der Hauptteil der Funktion 'OnMinValuePropertyChanged' vollständig dem Hauptteil der Funktion 'OnMaxValuePropertyChanged' entspricht. RadGauge.cs 446
private static void OnMinValuePropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args) { double newVal = (double)args.NewValue; ValidateValue(newVal); RadGauge gauge = sender as RadGauge; if (gauge.panel != null) { gauge.panel.UpdateOnMinMaxValueChange(); } if(AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged)) { var peer = FrameworkElementAutomationPeer.FromElement(gauge) as RadGaugeAutomationPeer; if (peer != null) { peer.RaiseMinimumPropertyChangedEvent((double)args.OldValue, (double)args.NewValue); } } } private static void OnMaxValuePropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args) { double newVal = (double)args.NewValue; ValidateValue(newVal); RadGauge gauge = sender as RadGauge; if (gauge.panel != null) { gauge.panel.UpdateOnMinMaxValueChange(); } if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged)) { var peer = FrameworkElementAutomationPeer.FromElement(gauge) as RadGaugeAutomationPeer; if (peer != null) { peer.RaiseMinimumPropertyChangedEvent((double)args.OldValue, (double)args.NewValue); } } }
Zwei Methoden,
OnMinValuePropertyChanged und
OnMaxValuePropertyChanged , führen dieselben Aktionen aus. Ich vermute sehr, dass es hier einen Fehler gibt. Beachten Sie, dass beide Methoden dieselbe Methode,
RaiseMinimumPropertyChangedEvent ,
aufrufen , während die
RadGaugeAutomationPeer- Klasse einzelne Methoden für "Minimum" und "Maximum" implementiert:
internal void RaiseMaximumPropertyChangedEvent(double oldValue, double newValue) { this.RaisePropertyChangedEvent( RangeValuePatternIdentifiers.MaximumProperty, oldValue, newValue); } internal void RaiseMinimumPropertyChangedEvent(double oldValue, double newValue) { this.RaisePropertyChangedEvent( RangeValuePatternIdentifiers.MinimumProperty, oldValue, newValue); }
Die
RaiseMinimumPropertyChangedEvent- Methode wird zweimal verwendet, während die
RaiseMaximumPropertyChangedEvent- Methode überhaupt nicht verwendet wird. Dies lässt mich bezweifeln, dass die
OnMaxValuePropertyChanged- Methode gut funktioniert ... Ich denke, sie sollte so aussehen:
private static void OnMaxValuePropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args) { .... peer.RaiseMaximumPropertyChangedEvent((double)args.OldValue, (double)args.NewValue); .... }
Aber selbst mit diesem Fix sieht der Code aufgrund der zahlreichen doppelten Elemente nicht ordentlich aus. Es ist schwer zu lesen und die ähnlich aussehenden Linien trüben Ihre Aufmerksamkeit, was die Codeüberprüfung zu einer schwierigen Aufgabe macht. Im Gegensatz dazu können statische Analysetools problemlos damit umgehen (was nicht bedeutet, dass Sie Ihren Code nicht umgestalten und insbesondere doppelte Zeilen entfernen sollten).
Wenn ich mir dieses und das nächste Fragment ansehe, vermute ich, dass sich die Projektautoren hin und wieder dem Kopieren und Einfügen hingeben. Nun, wir alle tun es ... :)
PVS-Studio-Diagnosemeldung: V3001 Links und rechts von '||' befinden sich identische Unterausdrücke 'element.RenderSize == emptySize'. Betreiber. TiltInteractionEffect.cs 181
private static bool IsPointInElementBounds(FrameworkElement element, Point position) { Size emptySize = new Size(0, 0); if (element.RenderSize == emptySize || element.RenderSize == emptySize) { return false; } return new Rect(....).Contains(position); }
Beide Operanden des '||' Operatoren im bedingten Ausdruck der
if- Anweisung werden durch identische Unterausdrücke dargestellt. Offensichtlich sollte der zweite Unterausdruck unterschiedlich sein. Vielleicht sollte die zweite
RenderSize DesiredSize sein, oder vielleicht sollte der zweite Unterausdruck überhaupt nicht vorhanden sein. In jedem Fall muss dieser Code korrigiert werden.
PVS-Studio-Diagnosemeldung: V3001 Links und rechts von '||' befinden sich identische Unterausdrücke 'text [0] ==' - ''. Betreiber. RadNumericBox.cs 1057
private void ValidateText() { string text = this.textBox.Text; .... if (text.Length == 1 && (text[0] == '-' || text[0] == '-')) { if (this.isNegative) { this.isNegative = false; } else { this.SetText(string.Empty); } return; } .... }
Der in das Textfeld eingegebene Text wird in eine Variable eingelesen. Das erste Zeichen der Zeichenfolge wird dann zweimal mit dem Zeichen '-' verglichen, das nicht richtig aussieht. Offensichtlich führt diese Funktion die Textüberprüfung nicht wie beabsichtigt durch.
PVS-Studio-Diagnosemeldung: V3001 Links und rechts vom Operator '&&' befinden sich identische Unterausdrücke 'newValue.HasValue'. DateTimePicker.cs 576
private static void OnValueChanged(object sender, DependencyPropertyChangedEventArgs args) { DateTimePicker picker = sender as DateTimePicker; var newValue = (DateTime?)args.NewValue; if (newValue.HasValue && newValue != null)
Beide bedingten Ausdrücke,
newValue.HasValue und
newValue! = Null , geben
true zurück, wenn
newValue einen Wert hat. Der Analysator weist darauf hin, aber ob dieser Fehler durch Entfernen eines der Unterausdrücke oder durch Ersetzen durch einen anderen behoben werden sollte (falls noch etwas zu überprüfen war), können nur die Autoren dieses Codes herausfinden.
PVS-Studio-Diagnosemeldung: V3125 Das Objekt 'CurrentAttachedMenu' wurde verwendet, nachdem es gegen null überprüft wurde. Überprüfen Sie die Zeilen: 98, 96. PopupService.cs 98
internal static class PopupService { .... private static void Overlay_PointerPressed(....) { if (CurrentAttachedMenu == null || !CurrentAttachedMenu.hitTestService. HitTest(e.GetCurrentPoint(CurrentAttachedMenu).Position).Any()) { CurrentAttachedMenu.IsOpen = false; HideOverlay(); } } }
Wenn die Variable
CurrentAttachedMenu zufällig gleich
null ist , führt die Auswertung des Ausdrucks
CurrentAttachedMenu.IsOpen zu einer Ausnahme. Es sieht so aus, als wäre es nur ein Tippfehler, und die Entwickler meinten tatsächlich die entgegengesetzte Operation '! ='. Anstelle der
Nullprüfung wird in diesem Fall die Bedingung der
if- Anweisung eine Ausnahme
auslösen , wenn die Variable
CurrentAttachedMenu lautet gleich
null .
Es gab
37 weitere Warnungen dieser Art, von denen einige anscheinend auf echte Fehler hinweisen. Aber das sind ein bisschen zu viele Warnungen für einen Artikel, also werde ich sie überspringen.
PVS-Studio-Diagnosemeldung: V3019 Möglicherweise wird eine falsche Variable nach der Typkonvertierung mit dem Schlüsselwort 'as' mit null verglichen. Überprüfen Sie die Variablen 'dragDropElement', 'uiDragDropElement'. DragDrop.cs 91
internal static void StartDrag(....) { var dragDropElement = sender as IDragDropElement; .... UIElement uiDragDropElement = dragDropElement as UIElement; .... if (dragDropElement == null || !dragDropElement.CanStartDrag(trigger, initializeContext)) { return; } .... }
Der Programmierer muss eine Variable für eine andere verwechselt haben. Die
Nullprüfung wird für die
Quellreferenz dragDropElement durchgeführt und nicht für die Referenz, die sich aus der
Umwandlung uiDragDropElement ergibt , die eigentlich überprüft werden sollte. Diese Annahme wird durch die Tatsache gestützt, dass
uiDragDropElement ohne
Nullprüfungen weiter verwendet wird.
PVS-Studio-Diagnosemeldung: V3030 Wiederkehrende Prüfung. Die Bedingung '! ShowIndicatorWhenNoData' wurde bereits in Zeile 139 überprüft. RadDataBoundListBox.PullToRefresh.cs 141
internal void HandlePullToRefreshItemStateChanged(object item, ItemState state) { .... bool showIndicatorWhenNoData = this.ShowPullToRefreshWhenNoData; if (this.realizedItems.Count == 0 && !showIndicatorWhenNoData) { if (state == ItemState.Recycled && !showIndicatorWhenNoData) { this.StopPullToRefreshLoading(false); this.HidePullToRefreshIndicator(); } return; } .... }
Zwei Bedingungen überprüfen dieselbe Variable
showIndicatorWhenNoData . Die zweite Prüfung ist möglicherweise redundant, aber es ist auch möglich, dass einer der doppelten Unterausdrücke etwas ganz anderes ist.
PVS-Studio-Diagnosemeldung: V3031 Eine übermäßige Überprüfung kann vereinfacht werden. Das '||' Der Operator ist von entgegengesetzten Ausdrücken umgeben. SelectedItemCollection.cs 77
internal class SelectedItemCollection : ObservableCollection<object> { .... private bool CanInsertItem(object item) { return this.suspendLevel == 0 && this.AllowSelect && ((!this.AllowMultipleSelect && this.Count == 0) || this.AllowMultipleSelect); } }
Technisch gesehen ist dieses Snippet korrekt. Der Analysator weist nur auf eine bestimmte Redundanz in der Bedingung hin. Beachten Sie jedoch, dass redundanter Code häufig ein Zeichen für einen Programmierfehler ist, z. B. das mehrmalige Überprüfen einer Variablen als erforderlich anstelle einer anderen Variablen.
Die Bedingung kann ein wenig vereinfacht werden, indem unnötiger Code wie folgt entfernt wird:
internal class SelectedItemCollection : ObservableCollection<object> { .... private bool CanInsertItem(object item) { return this.suspendLevel == 0 && this.AllowSelect && (this.AllowMultipleSelect || this.Count == 0); } }
Andere ähnliche Warnungen:
- V3031 Eine übermäßige Überprüfung kann vereinfacht werden. Das '||' Der Operator ist von entgegengesetzten Ausdrücken umgeben. SelectedItemCollection.cs 93
- V3031 Eine übermäßige Überprüfung kann vereinfacht werden. Das '||' Der Operator ist von entgegengesetzten Ausdrücken umgeben. StackVirtualizationStrategy.cs 49
- V3031 Eine übermäßige Überprüfung kann vereinfacht werden. Das '||' Der Operator ist von entgegengesetzten Ausdrücken 'state == null' und 'state! = null' umgeben. LocalFieldDescriptionsProviderBase.cs 24
Betrachten wir einen weiteren Code, an den der Analysator Folgendes ausgegeben hat:
PVS-Studio-Diagnosemeldungen:- V3137 Die Variable 'leftMargin' wird zugewiesen, aber am Ende der Funktion nicht verwendet. DragDrop.cs 87
- V3137 Die Variable 'topMargin' wird zugewiesen, aber am Ende der Funktion nicht verwendet. DragDrop.cs 88
internal static class DragDrop { .... double leftMargin = 0d; double topMargin = 0d; if (frameworkElementSource != null) { leftMargin = frameworkElementSource.Margin.Left;
Die Variablen
leftMargin und
topMargin haben einige Werte
zugewiesen, danach jedoch nie mehr verwendet. Es ist nicht unbedingt ein Fehler, aber Code wie dieser sieht immer noch verdächtig aus. Es könnte ein Zeichen für einen Tippfehler oder ein schlechtes Refactoring sein.
Es gab eine weitere Warnung dieses Typs: V3137 Die Variable 'currentColumnLength' ist zugewiesen, wird jedoch am Ende der Funktion nicht verwendet. WrapLayout.cs 824
PVS-Studio-Diagnosemeldung: V3061 Der Parameter 'index' wird vor der Verwendung immer im Methodenkörper neu geschrieben. DataEngine.cs 1443
private static Tuple<Group, int> FindGroupAndItemIndex(.... int index, ....) { if (exhaustiveSearch) { .... } else { var aggregateRowGroup = rowRootGroup; var rowGroupNames = valueProvider.GetRowGroupNames(item); foreach (var groupName in rowGroupNames) { Group group; if (aggregateRowGroup.TryGetGroup(groupName, out group)) { aggregateRowGroup = group; } } index = aggregateRowGroup.IndexOf(item,
Der
Indexparameter der
FindGroupAndItemIndex- Methode wird vor der Verwendung überschrieben. Dies weist höchstwahrscheinlich auf einen Programmiererfehler hin.
PVS-Studio-Diagnosemeldung: V3083 Unsicherer Aufruf des Ereignisses 'Abgeschlossen', NullReferenceException ist möglich. Überlegen Sie, ob Sie einer lokalen Variablen ein Ereignis zuweisen möchten, bevor Sie sie aufrufen. ActionBase.cs 32
internal abstract class ActionBase { .... protected virtual void OnCompleted() { this.IsCompleted = true; if (this.Completed != null) { this.Completed(this, EventArgs.Empty); } } }
Der Ereignishandler wird möglicherweise unsicher aufgerufen, wobei das Risiko besteht, dass eine
NullReferenceException ausgelöst wird . Dies ist der Fall, wenn zwischen der Nullprüfung und dem Aufruf des Ereignishandlers keine Abonnenten mehr vorhanden sind.
Der Bericht weist auf
49 weitere Probleme dieser Art hin. Es ist nicht sehr interessant, sie hier zu diskutieren, und schließlich können die Projektautoren sie mit PVS-Studio leicht selbst finden. Fahren wir also mit den nächsten Beispielen fort.
PVS-Studio-Diagnosemeldung: V3145 Unsichere Dereferenzierung eines WeakReference-Ziels. Überprüfen Sie möglicherweise info.Target. Das Objekt könnte zwischen der Überprüfung von 'IsAlive' und dem Zugriff auf die Eigenschaft 'Target' Müll gesammelt haben. FadeAnimation.cs 84
public class RadFadeAnimation : RadAnimation { .... protected internal override void ApplyAnimationValues(PlayAnimationInfo info) { .... if (info.Target.Opacity != opacity)
Bei der Adressierung der Eigenschaft
info.Target.Opacity kann eine
NullReferenceException ausgelöst werden . Um besser zu verstehen, worum es bei dem Problem geht, müssen wir uns bestimmte Blöcke der
PlayAnimationInfo- Klasse
ansehen , insbesondere die
Target- Eigenschaft.
public class PlayAnimationInfo { .... private WeakReference target; .... public PlayAnimationInfo(Storyboard storyboard, RadAnimation animation, UIElement target) { .... this.target = new WeakReference(target); .... } .... public UIElement Target { get { if (this.target.IsAlive) { return this.target.Target as UIElement; } return null; } } .... }
Je tiefer Sie sich mit diesem Code befassen, desto mehr potenzielle Probleme werden tatsächlich aufgedeckt. Schauen wir uns das interessanteste an - das, das die Warnung ausgelöst hat. Das Problem ist, dass selbst wenn die Ausführung dem
else- Zweig der
if- Anweisung folgt, die Rückgabe einer Nicht-Null-Referenz nicht garantiert wird, selbst wenn die Auswirkungen der Typkonvertierung nicht berücksichtigt werden (das Objekt wird vom Konstruktor initialisiert). .
Wie ist das möglich Sie sehen, wenn das Objekt, auf das
WeakReference verweist , zwischen der
IsAlive- Prüfung und dem Aufruf von
Target durch Müll gesammelt wird, gibt
this.target.Target null zurück . Das heißt, die
IsAlive- Prüfung garantiert nicht, dass das Objekt beim nächsten Aufruf von
Target noch verfügbar ist.
Übrigens ist die
Rückgabe null; Das Problem wird von einer anderen Diagnose erkannt: V3080 Mögliche Null-Dereferenzierung. Überprüfen Sie 'info.Target'. FadeAnimation.cs 84
Es gab noch ein paar solche Mängel:
- V3145 Unsichere Dereferenzierung eines WeakReference-Ziels. Überprüfen Sie das Ziel. Das Objekt könnte Müll gesammelt worden sein, bevor auf die Eigenschaft 'Target' zugegriffen wurde. MoveXAnimation.cs 80
- V3145 Unsichere Dereferenzierung eines WeakReference-Ziels. Überprüfen Sie das Ziel. Das Objekt könnte Müll gesammelt worden sein, bevor auf die Eigenschaft 'Target' zugegriffen wurde. MoveYAnimation.cs 80
- V3145 Unsichere Dereferenzierung eines WeakReference-Ziels. Überprüfen Sie info.Target. Das Objekt könnte Müll gesammelt worden sein, bevor auf die Eigenschaft 'Target' zugegriffen wurde. PlaneProjectionAnimation.cs 244
- V3145 Unsichere Dereferenzierung eines WeakReference-Ziels. Das Objekt könnte zwischen der Überprüfung von 'IsAlive' und dem Zugriff auf die Eigenschaft 'Target' Müll gesammelt haben. WeakEventHandler.cs 109
Fahren wir mit dem nächsten Beispiel fort.
PVS-Studio-Diagnosemeldung: V3066 Möglicherweise falsche Reihenfolge der Argumente, die an den Konstruktor 'NotifyCollectionChangedEventArgs' übergeben wurden: 'oldItem' und 'newItem'. CheckedItemsCollection.cs 470
public class CheckedItemsCollection<T> : IList<T>, INotifyCollectionChanged { .... private NotifyCollectionChangedEventArgs GenerateArgs(....) { switch (action) { case NotifyCollectionChangedAction.Add: .... case NotifyCollectionChangedAction.Remove: .... case NotifyCollectionChangedAction.Replace: return new NotifyCollectionChangedEventArgs( action, oldItem, newItem, changeIndex);
Um die Bedeutung dieser Warnung herauszufinden, müssen wir uns die Parameter des
NotifyCollectionChangedEventArgs- Konstruktors
ansehen :
public NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction action, object newItem, object oldItem, int index);
Der Analysator teilt uns mit, dass die Variablen
oldItem und
newItem im folgenden Ausdruck ausgetauscht werden:
return new NotifyCollectionChangedEventArgs( action, oldItem, newItem, changeIndex);
In der Implementierung des Konstruktors sind diese Variablen jedoch in umgekehrter Reihenfolge aufgeführt. Sie können sich nur fragen, ob dies absichtlich gemacht wurde oder nicht.
PVS-Studio-Diagnosemeldung: V3102 Verdächtiger Zugriff auf das Element des Objekts 'x' durch einen konstanten Index innerhalb einer Schleife. DataEngine.cs 1718
private class ObjectArrayComparer : IEqualityComparer<object[]> { public bool Equals(object[] x, object[] y) { .... for (int i = 0; i < x.Length; i++) { if (!object.Equals(x[0], y[0]))
Die Elemente
x [0] und
y [0] werden bei jeder Schleifeniteration verglichen. Da jedoch nur die ersten Elemente verglichen werden, macht die Schleife keinen Sinn. Die Entwickler wollten wahrscheinlich stattdessen die jeweiligen Elemente der Arrays vergleichen. In diesem Fall würde die richtige Version folgendermaßen aussehen:
for (int i = 0; i < x.Length; i++) { if (!object.Equals(x[i], y[i])) { return false; } }
PVS-Studio-Diagnosemeldung: V3123 Möglicherweise
funktioniert der Operator '?:' Anders als erwartet. Seine Priorität ist niedriger als die Priorität anderer Betreiber in seinem Zustand. EditRowHostPanel.cs 35
protected override Size MeasureOverride(Size availableSize) { .... bool shouldUpdateRowHeight = editorLine == 0 || displayedElement == null ? false : displayedElement.ContainerType != typeof(DataGridGroupHeader); .... }
Diese Warnung befasst sich mit der Verwendung des Operators '?:'. Seine Priorität ist niedriger als die von
! =, || und
== , was bedeutet, dass die Reihenfolge der Bewertung des obigen Ausdrucks von der erwarteten abweichen kann. Dieser spezielle Fall scheint falsch positiv zu sein, da der Code tatsächlich wie beabsichtigt funktioniert. Aber Code wie dieser ist sehr schwer zu lesen, und Sie können nie sicher sein, ob Sie ihn richtig verstanden haben. Es sieht so aus, als ob es absichtlich so geschrieben wurde, damit niemand es herausfinden kann :) Der beste Weg, um das Lesen zu erleichtern, ist die Verwendung von Klammern oder einer
if- Anweisung.
PVS-Studio-Diagnosemeldung: V3078 Die ursprüngliche Sortierreihenfolge geht nach wiederholtem Aufruf der Methode 'OrderBy' verloren. Verwenden Sie die 'ThenBy'-Methode, um die ursprüngliche Sortierung beizubehalten. GridModel.Selection.cs 107
internal partial class GridModel { private void BuildCellSelectionRegions(....) { .... this.MergeCellSelectionRegions(selectedItemsInView .OrderBy(c => c.Column.ItemInfo.LayoutInfo.Line) .OrderBy(c => c.RowItemInfo.LayoutInfo.Line)); } }
Dieser Fehler hat mit einem wiederkehrenden Aufruf der
OrderBy- Methode für eine Auflistung vom Typ
IOrderedEnumerable zu tun . Die Sammlung wird zuerst nach Spalten und dann nach Zeilen sortiert. Das Problem ist, dass das Ergebnis der ersten Sortierung - nach Spalten - nirgendwo gespeichert wird und verloren geht, wenn die Sortierung nach Zeilen beginnt. Wenn Sie das Ergebnis der spaltenweisen Sortierung
beibehalten und nach mehreren Kriterien sortieren
möchten , verwenden Sie die
ThenBy- Methode:
this.MergeCellSelectionRegions(selectedItemsInView .OrderBy(c => c.Column.ItemInfo.LayoutInfo.Line) .ThenBy(c => c.RowItemInfo.LayoutInfo.Line));
PVS-Studio-Diagnosemeldung: V3008 Der Variablen 'currentColumnLength' werden zweimal nacheinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 791, 785. WrapLayout.cs 791
private void OnAvailableLengthChanged(double oldValue, double newValue) { .... if (....) { if (currentColumnLength > 0) { var paddingValue = Math.Max(0, newValue - currentColumnLength); this.paddingRenderInfo.Add(paddingValue); currentColumnLength = 0;
Der Analysator fand es seltsam, dass der Variablen
currentColumnLength zweimal ein Wert zugewiesen wird, während sie nirgendwo zwischen diesen beiden Zuweisungen verwendet wird. Unabhängig von der Bedingung wird die Variable schließlich als
null enden. Dieser Code ist entweder fehlerhaft oder redundant.
PVS-Studio-Diagnosemeldung: V3127 Es wurden zwei ähnliche Codefragmente gefunden. Möglicherweise handelt es sich um einen Tippfehler, und anstelle von RadRatingItem.cs 240 sollte die Variable 'emptyIconContainer' verwendet werden
public class RadRatingItem : RadContentControl { .... protected override void OnApplyTemplate() { .... this.filledIconContainer = this.GetTemplateChild( "FilledIconContainer") as Border; if (this.filledIconContainer == null)
Die beiden oben genannten identischen Bedingungen sind auf einen Tippfehler zurückzuführen. Die von diesem Code ausgelöste Ausnahme legt nahe, dass die zweite Bedingung folgendermaßen aussehen sollte:
if (this.emptyIconContainer == null) { throw new MissingTemplatePartException( "EmptyIconContainer", typeof(Border)); }
PVS-Studio-Diagnosemeldung: V3020 Eine bedingungslose Unterbrechung innerhalb einer Schleife. NodePool.cs 189
public IEnumerable<KeyValuePair<int, List<T>>> GetUnfrozenDisplayedElements() { foreach (var item in this.generatedContainers) { foreach (var pair in item.Value) { if (!pair.IsFrozen) { yield return item; } break; } } }
Die
break- Anweisung ist nicht Teil der
if- Anweisung. Es wird ausgeführt, unabhängig davon, welcher Wert in
pair.IsFrozen gespeichert
ist , sodass die
foreach- Schleife nur einmal iteriert.
Das ist alles für meine Überprüfung der in Telerik gefundenen Fehler. Wir sind bereit, den Entwicklern eine kostenlose temporäre Lizenz zur Verfügung zu stellen, damit sie eine gründlichere Analyse durchführen und die Fehler beheben können. Sie können auch die
kostenlosen PVS-Studio-Lizenzierungsoptionen nutzen , die Open-Source-Entwicklern zur Verfügung stehen.
Fazit
Obwohl die Autoren von Telerik UI for UWP bei der Entwicklung ihres Projekts große Arbeit geleistet haben, haben sie dennoch eine Reihe von Tippfehlern eingeschlichen, wie es normalerweise bei uns der Fall ist :). All diese Fehler hätten leicht mit einem statischen Analysegerät erkannt und behoben werden können. Das Wichtigste bei der statischen Analyse ist jedoch, dass sie
richtig und regelmäßig verwendet werden sollte .