Überprüfen Sie die Telerik-Benutzeroberfläche auf UWP, um sich mit PVS-Studio vertraut zu machen

Bild 2

Es ist bereits Tradition geworden, dass Programmierer, die das PVS-Studio-Team auffüllen, ihre Arbeit mit dem Schreiben eines Artikels über die Analyse eines Open-Source-Projekts beginnen. Dieses Mal wird ein solch bewährtes Projekt die Telerik-Benutzeroberfläche für UWP sein.

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. Läuft unter Windows, Linux und MacOS.

Der Analysator bietet verschiedene Verwendungsszenarien:

  • kann lokal auf Entwicklungsmaschinen verwendet werden und als Plug-In in Visual Studio oder IntelliJ IDEA integriert werden;
  • kann in die SonarQube-Plattform für kontinuierliche Qualitätssicherung integriert werden;
  • kann unabhängig verwendet werden und in das Montagesystem integriert werden;
  • Es ist möglich, das Dienstprogramm zur Kompilierungsüberwachung zu verwenden.
  • Die Integration mit Azure DevOps, Jenkins, TeamCity, Travis CI und ähnlichen Systemen ist möglich.
  • usw.

Geprüftes Projekt


Telerik UI for UWP ist eine Reihe von Benutzeroberflächenkomponenten für die Universal Windows Platform (UWP). Der Quellcode für das Projekt ist auf Github zu finden . Das Set enthält mehr als 20 Komponenten, mit denen Sie Daten in Form von Diagrammen visualisieren, Listen und Tabellen erstellen und mithilfe einer Karte Daten demonstrieren können, die einem Standort zugeordnet sind.

Fragmente, die beim Studium des Analysatorberichts Aufmerksamkeit erregt haben


PVS-Studio Warnung : V3013 Es ist merkwürdig, dass der Hauptteil der Funktion 'OnMinValuePropertyChanged' dem Hauptteil der Funktion 'OnMaxValuePropertyChanged' vollständig 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); } } } 

Der Analysator hat zwei Methoden erkannt, OnMinValuePropertyChanged und OnMaxValuePropertyChanged , die dieselben Aktionen ausführen. Ich habe den starken Verdacht, dass sich ein Fehler in diesen Code eingeschlichen hat. Beachten Sie, dass sowohl die OnMinValuePropertyChanged- Methode als auch die OnMaxValuePropertyChanged- Methode RaiseMinimumPropertyChangedEvent verwenden . Gleichzeitig finden Sie in der RadGaugeAutomationPeer- Klasse sowohl eine Methode für "Minimum" als auch für "Maximum":

 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 RaiseMaximumPropertyChangedEvent- Methode wird im Code nie verwendet, RaiseMinimumPropertyChangedEvent wird jedoch zweimal verwendet. Und, wissen Sie, die Leistung der OnMaxValuePropertyChanged- Methode wirft Fragen auf ... Ich denke, sie sollte Folgendes schreiben:

 private static void OnMaxValuePropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs args) { .... peer.RaiseMaximumPropertyChangedEvent((double)args.OldValue, (double)args.NewValue); .... } 

Trotzdem sieht der Code aufgrund der großen Anzahl sich wiederholender Elemente nicht sehr ordentlich aus. Es ist schwer zu verstehen, und wiederholte Zeilen trüben die Aufmerksamkeit des Programmierers, und es wird schwieriger, unter solchen Bedingungen eine Codeüberprüfung durchzuführen. Die statischen Analysetools können diesen Code jedoch hervorragend überprüfen (dies bedeutet jedoch nicht, dass Sie auf Refactoring und insbesondere auf die Reduzierung der Anzahl wiederholter Zeilen verzichten können).

Aus dem obigen und dem folgenden Codeausschnitt können wir annehmen, dass die Autoren dem Kopieren und Einfügen nicht abgeneigt sind. Wie wir alle ... :)

PVS-Studio Warnung : 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); } 

Der Analysator hat ein Fehlercodefragment erkannt, in dem sich rechts und links vom Operator '||' befindet Die if- Anweisung verwendet dieselben Unterausdrücke. Der zweite Unterausdruck hätte eindeutig anders aussehen sollen. Vielleicht sollte anstelle des zweiten RenderSize DesiredSize sein . Oder es sollte überhaupt keinen zweiten Unterausdruck geben. In jedem Fall muss dieser Code repariert werden.

PVS-Studio Warnung : V3001 Links und rechts vom '||' 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; } .... } 

Hier schreibt der Entwickler den im Textfeld eingegebenen Text in eine Variable. Dann wird das erste Zeichen der Zeichenfolge zweimal mit demselben Zeichen '-' verglichen, was eine verdächtige Entscheidung ist. Offensichtlich funktioniert die Textüberprüfung in dieser Funktion nicht wie ursprünglich beabsichtigt.

PVS-Studio Warnung : 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) // <= .... } 

Der Ausdruck newValue.HasValue gibt true zurück , wenn newValue einen Wert enthält, und der Ausdruck newValue! = Null macht dasselbe. Der Analysator achtet darauf, und was zu tun ist, ist, einen der Unterausdrücke zu entfernen oder durch einen anderen zu ersetzen (wenn etwas anderes überprüft werden musste), liegt es an den Entwicklern, zu entscheiden.

PVS-Studio Warnung : 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 sich herausstellt, dass die Variable CurrentAttachedMenu null ist , löst die Auswertung des Ausdrucks CurrentAttachedMenu.IsOpen eine Ausnahme aus. Auf den ersten Blick scheint dies ein einfacher Tippfehler zu sein und bedeutete keinen Vergleich mit null , sondern die inverse Operation - '! ='. In der Bedingung der if-Anweisung tritt jedoch eine Ausnahme auf, wenn die Variable CurrentAttachedMenu null ist .

Weiter im Code gab es weitere 37 der gleichen Warnungen, von denen einige auf Fehler hinweisen. Aber sie im Rahmen eines Artikels zu beschreiben, ist immer noch zu viel, deshalb werde ich sie unbeaufsichtigt lassen.

PVS-Studio Warnung : 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; } .... } 

Es ist sehr wahrscheinlich, dass der Autor die Variablen verwechselt hat. Die Nullungleichung wird nicht durch den Link überprüft, der als Ergebnis der Umwandlung erhalten wurde , sondern durch das Original ( dragDropElement ). Höchstwahrscheinlich sollte der Link uiDragDropElement überprüft werden . Die Vermutung wird auch durch die Tatsache bestätigt, dass der Programmierer uiDragDropElement weiter verwendet hat, ohne nach Null zu suchen .

PVS-Studio Warnung : 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; } .... } 

Der Analysator hat einen Code gefunden, in dem unter zwei Bedingungen dieselbe showIndicatorWhenNoData- Variable erneut überprüft wird. Vielleicht ist die Prüfung einfach redundant, aber es besteht auch die Möglichkeit, dass einer der doppelten Unterausdrücke überhaupt anders sein sollte.

PVS-Studio Warnung : 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); } } 

Dieser Code ist formal nicht fehlerhaft. Der Analysator weist auf eine gewisse Code-Redundanz in der Bedingung hin. Es ist jedoch zu beachten, dass zusätzlicher Code manchmal das Ergebnis eines Fehlers ist, z. B. wenn anstelle einer Variablen eine andere mehrmals überprüft wird.

Sie können diesen Zustand etwas reduzieren und den zusätzlichen Code entfernen. Zum Beispiel so:

 internal class SelectedItemCollection : ObservableCollection<object> { .... private bool CanInsertItem(object item) { return this.suspendLevel == 0 && this.AllowSelect && (this.AllowMultipleSelect || this.Count == 0); } } 

Andere ähnliche Nachrichten:

  • 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

Stellen Sie sich einen anderen Code vor, bei dem der Analysator Folgendes zurückgegeben hat:

PVS-Studio-Warnungen :

  • 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; // <= topMargin = frameworkElementSource.Margin.Top; // <= } if (dragDropElement == null || !dragDropElement.CanStartDrag(trigger, initializeContext)) { return; } var context = dragDropElement .DragStarting(trigger, initializeContext); if (context == null) { return; } var startDragPosition = e .GetCurrentPoint(context.DragSurface.RootElement).Position; var relativeStartDragPosition = e .GetCurrentPoint(uiDragDropElement).Position; var dragPositionMode = DragDrop .GetDragPositionMode(uiDragDropElement); AddOperation(new DragDropOperation( context, dragDropElement, dragPositionMode, e.Pointer, startDragPosition, relativeStartDragPosition)); } 

Der Analysator meldet, dass den Variablen leftMargin und topMargin Werte zugewiesen wurden. Danach werden diese Variablen jedoch erst am Ende der Methode verwendet. Hier liegt wahrscheinlich kein Fehler vor, aber ein solcher Code sieht verdächtig aus. Dies kann auf einen Tippfehler oder ein erfolgloses Refactoring zurückzuführen sein.

Das gleiche Problem wurde an anderer Stelle gefunden: V3137 Die Variable 'currentColumnLength' wird zugewiesen, aber am Ende der Funktion nicht verwendet. WrapLayout.cs 824

PVS-Studio Warnung : 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, // <= valueProvider.GetSortComparer()); return Tuple.Create(aggregateRowGroup, index); } } 

Der Indexparameter der FindGroupAndItemIndex- Methode wird vor der Verwendung überschrieben. Dies weist höchstwahrscheinlich auf einen Programmiererfehler hin.

PVS-Studio Warnung : 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 Programmierer hat bei dieser Methode einen möglicherweise unsicheren Aufruf des Ereignishandlers zugelassen, was zu einer Ausnahme vom Typ NullReferenceException führen kann . Eine Ausnahme wird ausgelöst, sofern dieses Ereignis zwischen der Nullprüfung und dem Aufruf der Ereignishandler nicht verbleibt.

Es gibt weitere 49 ähnliche Probleme im Code. Es wird nicht interessant sein, alle in diesem Artikel zu sehen, und die Autoren können sie mit PVS-Studio leicht selbst finden, sodass wir zu anderen Fehlern übergehen.

PVS-Studio Warnung : V3145 Unsichere Dereferenzierung eines WeakReference-Ziels. Überprüfen Sie 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) // <= { info.Target.Opacity = opacity; } .... } .... } 

Der Analysator warnt vor der Gefahr einer Ausnahme vom Typ NullReferenceException beim Zugriff auf die Eigenschaft info.Target.Opacity . Um das Wesentliche des Problems besser zu verstehen, müssen Sie sich Fragmente 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 weiter Sie diesen Code ausgraben, desto mehr potenzielle Probleme können Sie im Allgemeinen darin finden. Schauen wir uns das vielleicht interessanteste an - das, an das der Analysator eine Warnung ausgegeben hat. Tatsache ist, dass selbst wenn die Ausführung dem damaligen Zweig der if-Anweisung folgt, dies nicht garantiert, dass eine Referenz ungleich Null zurückgegeben wird. Unabhängig von Gesprächen über die Besetzung betrachten wir hier alles, was aufgrund der Initialisierung des Objekts im Konstruktor zulässig ist.

Wie ist das möglich? Tatsache ist, dass this.target.Target null zurückgibt , wenn zwischen der IsAlive- Prüfung und dem Target- Aufruf die Garbage Collection ausgeführt wird, unter die das von WeakReference referenzierte Objekt fällt . Das heißt, die IsAlive- Prüfung garantiert nicht, dass das Objekt beim nächsten Zugriff auf das Ziel weiterhin verfügbar ist.

Übrigens ist die Situation null; fängt eine andere Diagnoseregel ab: V3080 Mögliche Null-Dereferenzierung. Überprüfen Sie 'info.Target'. FadeAnimation.cs 84

Ähnliche Probleme im Code traten mehrmals auf:

  • 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.

Warnung PVS-Studio : V3066 Möglicherweise falsche Reihenfolge der an den Konstruktor 'NotifyCollectionChangedEventArgs' übergebenen Argumente: '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); // <= default: return new NotifyCollectionChangedEventArgs(action); } } } 

Um zu verstehen, was diese Warnung des Analysators bedeutet, sollten Sie sich die Konstruktorparameter NotifyCollectionChangedEventArgs ansehen :

  public NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction action, object newItem, object oldItem, int index); 

Der Analysator warnt dies im Ausdruck
  return new NotifyCollectionChangedEventArgs( action, oldItem, newItem, changeIndex); 

tauschte die Variablen oldItem und newItem aus . In der Konstruktordefinition werden sie in einer anderen Reihenfolge aufgelistet. Ob dies bewusst gemacht wurde oder nicht, kann man nur erraten.

PVS-Studio Warnung : V3102 Verdächtiger Zugriff auf das Element des ' x' -Objekts 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])) // <= { return false; } } return true; } .... } 

Bei jeder Iteration in der Schleife vergleicht der Programmierer x [0] und y [0]. Die Schleife ist in diesem Code jedoch nicht sinnvoll, da nur die ersten Elemente verglichen werden. Dies bedeutete höchstwahrscheinlich einen Vergleich der entsprechenden Elemente von Arrays. Dann lautet der richtige Code wie folgt:

 for (int i = 0; i < x.Length; i++) { if (!object.Equals(x[i], y[i])) { return false; } } 

Warnung PVS-Studio : 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); .... } 

Mit der Verwendung des Operators '?:' Ist eine Warnung verbunden. Es hat eine niedrigere Priorität als ! =, ||, ==. Daher wird ein Ausdruck möglicherweise nicht wie vom Programmierer geplant ausgewertet. Anscheinend ist dies in diesem Fall falsch positiv und der Code funktioniert korrekt. Das Lesen eines solchen Codes ist jedoch sehr schwierig und es gibt nie die Gewissheit, dass er richtig verstanden wird. Es fühlt sich so an, als hätte der Entwickler so geschrieben, dass niemand etwas verstanden hat :) Der beste Weg, dies zu tun, ist besser lesbar - verwenden Sie Klammern oder die if-Anweisung .

PVS-Studio Warnung : V3078 Die ursprüngliche Sortierreihenfolge geht nach wiederholtem Aufruf der 'OrderBy'-Methode 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)); } } 

Der Fehler hängt mit dem erneuten Aufrufen von OrderBy für eine Auflistung vom Typ IOrderedEnumerable zusammen . Hier wird die Sammlung zuerst nach Spalten und dann nach Zeilen sortiert. Darüber hinaus wird zum Zeitpunkt der Sortierung nach Zeilen die vorherige Sortierung nach Spalten nirgendwo berücksichtigt. Verwenden Sie ThenBy , um die Sortierung nach Spalten nicht zu verlieren und die Sammlung nach mehreren Kriterien gleichzeitig zu sortieren :

  this.MergeCellSelectionRegions(selectedItemsInView .OrderBy(c => c.Column.ItemInfo.LayoutInfo.Line) .ThenBy(c => c.RowItemInfo.LayoutInfo.Line)); 

PVS-Studio Warnung : V3008 Der Variablen 'currentColumnLength' werden zweimal hintereinander 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; // <= slotCount++; } this.ColumnSlotsRenderInfo.Update(i, newValue); this.paddingRenderInfo.Add(0); currentColumnLength = 0; // <= slotCount++; continue; } else { .... } .... } 

Dem Analysator erschien es verdächtig, dass der Variablen currentColumnLength zweimal ein Wert zugewiesen wurde. Die Variable wird nicht zwischen Zuweisungen verwendet. Unabhängig von der Bedingung ist diese Variable letztendlich Null. Dieser Code ist entweder falsch oder redundant.

PVS-Studio Warnung : 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) // <= { throw new MissingTemplatePartException( "FilledIconContainer", typeof(Border)); } this.emptyIconContainer = this.GetTemplateChild( "EmptyIconContainer") as Border; if (this.filledIconContainer == null) // <= { throw new MissingTemplatePartException( "EmptyIconContainer", typeof(Border)); } this.Initialize(); } .... } 

Aufgrund eines Tippfehlers wurden im Code zwei identische Bedingungen angezeigt. Gemessen an der generierten Ausnahme sollte die zweite Bedingung folgendermaßen aussehen:

 if (this.emptyIconContainer == null) { throw new MissingTemplatePartException( "EmptyIconContainer", typeof(Border)); } 

PVS-Studio Warnung : 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; } } } 

Der Analysator stellte fest, dass hier die break- Anweisung nicht zur if-Anweisung gehört . Break wird unabhängig vom Wert von pair.IsFrozen ausgeführt. Aus diesem Grund wird in foreach nur eine Iteration ausgeführt.

Damit ist meine Überlegung zu Warnungen abgeschlossen. Damit Telerik-Entwickler eine gründlichere Code-Analyse durchführen und Fehler beheben können, sind wir bereit, ihnen eine temporäre Lizenz zur Verfügung zu stellen. Darüber hinaus können sie die kostenlose Nutzung der PVS-Studio- Option nutzen, die Autoren von Open Source-Projekten zur Verfügung gestellt wird.

Fazit


Obwohl die Entwickler von Telerik UI für UWP großartige Arbeit geleistet haben, war es nicht ohne Tippfehler, wie es normalerweise passiert :). Alle diese Fehler konnten leicht von einem statischen Analysegerät gefunden und korrigiert werden. Das Wichtigste ist, den Analysator korrekt und regelmäßig zu verwenden .



Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Ekaterina Nikiforova. Überprüfen der Telerik-Benutzeroberfläche auf UWP als Einstieg in PVS-Studio .

Source: https://habr.com/ru/post/de470584/


All Articles