SlideShare uma empresa Scribd logo
1 de 16
Baixar para ler offline
Analyzing source code of WPF examples
by the Infragistics Company
Author: Vitaliy Alferov
Date: 10.02.2016
We continue analyzing various C# projects in order to show the abilities of the static code analyzer, PVS-
Studio. In this article, we are providing analysis results of WPF examples by the Infragistics Company.
Infragistics is a major software vendor, founded in 1989. It gained popularity mainly through the
development of enterprise-ready user interface toolsets for developers, which are run on all platforms,
including .NET.
Our tool - PVS-Studio 6.00 static code analyzer - had a number of C# general analysis diagnostics, that
we implemented using our experience of developing the C++ analyzer. Starting with PVS-Studio 6.01, we
are creating diagnostics specifically for the C# language. For a start we have chosen dependency
properties that are used in WPF projects. Such a choice was made for a reason - DependencyProperties
are quite difficult to create. The difficulty is that it is very easy to make a typo in the similar code that
WPF tends to be made up of. We have developed a number of diagnostics [3044, 3045, 3046, 3047,
3048, 3049] specifically for the analysis of dependencies of this type.
As we know, one of peculiarities of DependencyProperty, is that any error during the registration of
DependencyProperty can cause a program to crash during the runtime. The programmers have to fix
these errors by running the program again and again; thus a programmer spends precious minutes and -
in sum total - hours, looking for typos in the template code of DependencyProperty. On top of this, the
WPF analysis showed that not all errors can be detected after the first run of the program.
The first test subject for our diagnostics, was the code of test examples from the Infragistics Company.
The archive was downloaded on the 2nd of February here; there are 11 projects that can be
downloaded as one archive.
The analysis was done with the static code analyzer, PVS-Studio 6.01.
WPF errors
A large part of the projects are written on the basis of pre-used code, and this is where the analyzer
detected the most errors.
Error N1
In the "IGExtensions.Common.WPF" project, in the file "LambertConformalConic.cs" we saw the
following string of "DependencyProperty" registration:
public static readonly DependencyProperty CentralMeridianProperty
= DependencyProperty.Register("CentralMeridianProperty",
typeof(double), typeof(LambertConformalConic),
new PropertyMetadata(0.0,
new PropertyChangedCallback(UpdateConstants)));
V3045 WPF: the names of the registered property 'CentralMeridianProperty', and the property
'CentralMeridian', do not correspond with each other. LambertConformalConic.cs 130
As you can see, during the registration of DependencyProperty, in its name "CentralMeridianProperty"
was written instead of "CentralMeridian". This error of incorrect copying of the variable name occurs
quite often, but it is especially dangerous because of the following fact:
To write/read in the dependency property from the C# code, the programmers create the following
property:
public double CentralMeridian {
get { return (double)GetValue(CentralMeridianProperty); }
set { SetValue(CentralMeridianProperty, value); }
}
When addressing from xaml markup, binding is written for the "CentralMeridian" property. WPF is
smart enough to find the CentralMeridian property and read the original value from there, but the
changes in the CentralMeridian values won't be processed.
Error N2
Continuing the topic of typos in the names of the registered dependency properties, let's have a look at
the following error in the "TransverseMercator.cs" file of the "IGExtensions.Common.WPF"project.
public static readonly DependencyProperty CentralMeridianProperty
= DependencyProperty.Register("LongitudeOrigin", typeof(double),
typeof(TransverseMercator), new PropertyMetadata(0.0,
new PropertyChangedCallback(UpdateConstants)));
public double CentralMeridian { .... }
V3045 WPF: the names of the registered property 'LongitudeOrigin', and of the property
'CentralMeridian', do not correspond with each other. TransverseMercator.cs 95
As the practice shows, several dependency properties are written by copying the same string, and
editing it later. In other words, by using Copy-Paste. Quite often, we see that in the similar code a
variable is omitted and gets a different name, the one that was the closest in the list. Taking into
account that the list is somewhere in the Notepad [Notepad++, Sublime Text and such] in a different
window, you can check only manually if the required objects were created. It's especially hard to detect
such errors because the code is generally working, but in reality - only partially.
Error N3
The situation with the names of the registered properties is quite clear, but where else can a
programmer make an error creating DependencyProperty? Another variant - is in the types of values
that the properties should contain. Here is such an example - "IGExtensions.Common.WPF" project,
"PropertyBrushColorEditor.cs" file.
public static readonly DependencyProperty BrushColorProperty =
DependencyProperty.Register(BrushColorPropertyName,
typeof(Brush), typeof(PropertyBrushColorEditor),
new PropertyMetadata(null, (sender, e) =>
{....})
);
public SolidColorBrush BrushColor
{
get { return (SolidColorBrush)GetValue(BrushColorProperty); }
set { SetValue(BrushColorProperty, value); }
}
V3046 WPF: the type registered for DependencyProperty does not correspond with the type of the
property used to access it.
It's good if you don't have questions, as to why it is not correct to specify the parent class "Brush" during
the registration, and to specify the heir class "SolidColorBrush" addressing through the "BrushColor"
property. If it's not so, let's have a look at a simplified case of such a "game" with the stored types.
Consider a simple case. Let's create a simple WPF project, and add to the class the following
dependence property:
public static DependencyProperty MyIndexProperty =
DependencyProperty.Register("MyIndex", typeof(int),
typeof(MainWindow), new FrameworkPropertyMetadata(1));
int MyIndex
{
get { return (int)GetValue(MyIndexProperty); }
set { SetValue(MyIndexProperty, value); }
}
In xaml markup we'll write the following:
....
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource =
{RelativeSource Mode=Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Path=MyIndex}"/>
<Slider Grid.Row="1" Name="slider1"
Value="{Binding Path=MyIndex}" Maximum="100" />
<Button Grid.Row="2" Click="Button_Click">
Read value
</Button>
</Grid>
And add to the window class the code for pressing the button:
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Title = this.MyIndex.ToString();
}
That's it. As you can see, everything works. We move the slider, the number changes. Click on the
button, and the window title is immediately changed to the current value on the slider. By the way, and
as you probably noticed, the TextBlock displays integer values.
And now let's change the "int" type to the common "object" type in the registered
DependencyProperty.
public static DependencyProperty MyIndexProperty =
DependencyProperty.Register("MyIndex", typeof(object),
typeof(MainWindow), new FrameworkPropertyMetadata(1));
Let's leave the rest unchanged, and rerun the program.
The program started and now when we move the slider, real values are displayed in the TextBlock. But
it's not hard to guess, that if we press the button the program will crash, as it won't be able to convert a
real value in MyIndexProperty into an integer one in the property MyIndex. It seems like a small thing,
but it led to really bad consequences.
Error N4
We have provided some error examples which are common for the majority of projects (so sad, that
they are rarely fixed), but there are some "local" errors - for example in IGEquityTrading project:
public static readonly DependencyProperty
AxisFinancialIndicatorYTemplateProperty =
DependencyProperty.Register("AxisFinancialIndicatorYTemplate",
typeof(DataTemplate),
typeof(DataChartEx),
new PropertyMetadata(default(DataTemplate)));
public DataTemplate AxisCategoryYTemplate{
get { return (DataTemplate)
GetValue(AxisFinancialIndicatorYTemplateProperty); }
set {
SetValue(AxisFinancialIndicatorYTemplateProperty, value); }
}
V3045 WPF: the names of the property registered for DependencyProperty, and of the property used to
access it, do not correspond with each other. DataChartEx.cs 469
Infragistics steps on the same rake by creating a property with the "AxisCategoryYTemplate" name,
instead of the registered name "AxisFinancialIndicatorYTemplate".
Error N5
public static readonly DependencyProperty
FinancialIndicatorSeriesTemplateProperty =
DependencyProperty.Register("FinancialIndicatorTemplate",
typeof(DataTemplate),
typeof(DataChartEx),
new PropertyMetadata(default(DataTemplate)));
public DataTemplate FinancialIndicatorSeriesTemplate {
get { return (DataTemplate)
GetValue(FinancialIndicatorSeriesTemplateProperty); }
set {
SetValue(FinancialIndicatorSeriesTemplateProperty, value); }
}
V3045 WPF: the names of the property registered for DependencyProperty, and of the property used to
access it, do not correspond with each other. DataChartEx.cs 344
In the last case, the error most likely occurred after refactoring, when the variable was specified, and
the word "Series" was inserted in the middle of the phrase "FinancialIndicatorTemplate". What's more
interesting, it was changed everywhere, even in XAML markup and in "#region", but the name of the
registered property remained unchanged.
 ....InfraEquityTradingIGEquityTrading.WPFApp.xaml(123): <DataTemplate
x:Key="FinancialIndicatorSeriesTemplate">
 ....InfraEquityTradingIGEquityTrading.WPFApp.xaml(214):
FinancialIndicatorSeriesTemplate="{StaticResource FinancialIndicatorSeriesTemplate}"
 ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(189): var
financialIndicator = FinancialIndicatorSeriesTemplate.LoadContent() as Series;
 ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(330): #region
FinancialIndicatorSeriesTemplate (DependencyProperty)
 ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(336): public
DataTemplate FinancialIndicatorSeriesTemplate
 ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(349): #endregion
FinancialIndicatorSeriesTemplate (DependencyProperty)
 ....InfraEquityTradingIGEquityTrading.WPFControlsStockHistoryChart.xaml(646):
FinancialIndicatorSeriesTemplate="{StaticResource FinancialIndicatorSeriesTemplate}"
At the same time, the registered name "FinancialIndicatorTemplate" isn't used anywhere. We already
know what this can lead to.
Miscellaneous C# errors
We didn't see any other WPF errors in these builds from the Infragistics Company. As was already
mentioned, the majority of WPF diagnostics are designed to find bugs before compiling and running the
project. These projects with the examples have already been checked by programmers and QA
specialists. Additionally, these projects were also viewed by the users who could judge the quality and
operability of the tool, working with the test examples. I guess if they noticed an error, they notified the
developers.
Of course, there are other errors in these builds besides the WPF ones. The analyzer issued several
hundred warnings in total. Not all of the messages indicate a real error. Many warnings (for example,
comparing double type with constant), are simply not relevant for this type of project. It's not a big
problem, because the analyzer provides several mechanisms to suppress uninteresting messages.
In any case, there are a lot of warnings, and most of them show the anomalies in the code. These are
real mistakes or code "smell". Therefore we recommend that developers do the analysis themselves,
and examine all the analyzer warnings. In this article we'll have a look at the most interesting ones:
public bool IsValid
{
get {
var valid =
double.IsNaN(Latitude) || double.IsNaN(Latitude) ||
this.Weather.DateTime == Weather.DateTimeInitial;
return valid;
}
}
V3001 There are identical sub-expressions 'double.IsNaN(Latitude)' to the left and to the right of the '||'
operator. WeatherStation.cs 25
Programmers have a hard life. They must understand not only the programming, but also the areas in
which the program should work. It turns out that they must understand the subject area, and know
some specific words "Credit", "Debit", Latitude", "Longitude", for example, and so it just adds
complexity, especially if the concepts are similar in spelling. It turns out that we mistakenly write checks
of the same variable: double.IsNaN(Latitude) || double.IsNaN(Latitude).
Next error:
private static int clipSegment(....)
{
if (xmax > rc.Right && xmax > rc.Right)
{
return -1;
}
}
V3001 There are identical sub-expressions 'xmax > rc.Right' to the left and to the right of the '&&'
operator. Geometry. Geometry.CubicSpline.cs 529
It's quite a common thing - to check the limits of a variable, but it's quite easy to make an error writing
symbols after, and in, the variable. To avoid such errors you should stick to the following pattern: The
common variable is written from different sides in the expressions.
if (xmin < rc.Right && rc.Right < xmax)
It's harder to make a mistake, and it becomes more readable.
P.S. The same trick, however, won't work in Entity Framework; the program will crash during the
conversion of LINQ code to SQL. So here's the case :)
Infragistics developers put too much thought into these checks. Besides the error given above, the same
error repeated in the following strings:
private static int clipSegment(....)
{
....
if (ymin < rc.Top && ymin < rc.Top) //<= here
....
if (ymax > rc.Bottom && ymax > rc.Bottom) //<= and here
....
}
For the diagnostic V3001 it is still not enough, and it continues the expansion. Here is another example
of its work:
private static bool IsInDesignModeStatic(this Application app)
{
....
if (_isInDesignMode != null && _isInDesignMode.HasValue)
return _isInDesignMode.Value;
....
}
V3001 There are identical sub-expressions '_isInDesignMode != null' to the left and to the right of the
'&&' operator. NavigationApp.cs 415
In this case we have redundant code, not an error. This was enough:
if (_isInDesignMode.HasValue)
Another warning of V3001
void ParagraphSettingsPreviewAdapter_PropertyChanged(
object sender, PropertyChangedEventArgs e) {
....
if (LineSpacingType == Infrastructure.LineSpacingTypes.Exactly
|| LineSpacingType == Infrastructure.LineSpacingTypes.Exactly){
....
}
V3001 There are identical sub-expressions 'LineSpacingType == Infrastructure.LineSpacingTypes.Exactly'
to the left and to the right of the '||' operator. ParagraphSettingsPreviewAdapter.cs 268
It's not quite clear what the programmer meant here, but not what is really written.
Let's move on from V3001 to V3010.
There are a couple of function calls in the "IGEarthQuake.WPF" project.
public MapViewModel() {
....
WeakPropertyChangedListener.CreateIfNecessary(_service, this);
....
}
V3010 The return value of function 'CreateIfNecessary' is required to be utilized. MapViewModel.cs 42
public TimeLineViewModel(){
....
WeakPropertyChangedListener.CreateIfNecessary(_service, this);
....
}
V3010 The return value of function 'CreateIfNecessary' is required to be utilized. TimeLineViewModel.cs
50
The same rather simple function is called in both cases. Let's look at its implementation:
public static
WeakPropertyChangedListener CreateIfNecessary(object source,
IPropertyChangedListener listener){
INotifyPropertyChanged inpc = source as INotifyPropertyChanged;
return inpc != null ?
new WeakPropertyChangedListener(inpc, listener) : null;
}
As you can see, this feature does not bring any global changes, and its result is also not used. So here is
the question - why was it called at all? Looks very suspicious...
A similar example is in the "IGHospitalFloorPlan.WPF" project:
private void ParseAllShapefiles() {
....
this.ShapeFilesMaxBounds.Expand(new Thickness(10, 10, 10, 10));
....
}
V3010 The return value of function 'Expand' is required to be utilized. HospitalView.xaml.cs 52
Its implementation is slightly trickier, but ultimately it just returns a new object that is never used.
We've reached the middle of the article. Have a look at this picture; relax, and then we'll continue.
One of the most common types of error, is a bad Copy-Paste:
public static EsriMapImageryView
GetImageryView(EsriMapImageryStyle imageryStyle){
....
if (imageryStyle ==
EsriMapImageryStyle.UsaPopulationChange2010Overlay)
return EsriMapImageryViews.UsaPopulationChange2010Overlay;
if (imageryStyle ==
EsriMapImageryStyle.UsaPopulationChange2010Overlay)
return EsriMapImageryViews.UsaPopulationChange2010Overlay;
....
}
V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement
contains method return. This means that the second 'if' statement is senseless EsriMapImageryView.cs
97
In this case, the same code is under the same condition. At this stage, the error is a bad (redundant)
Copy-Paste method. But after refactoring, it may happen that the programmer changes the body of the
inferior if function, that is never executed, and an error occurs in the program logic.
Let's see other errors that occurred in the code of Infragistics company.
Warning V3022 was issued for the following string:
public static double GenerateTemperature(GeoLocation location){
....
else if (location.Latitude > 10 || location.Latitude < 25)
....
else if (location.Latitude > -40 || location.Latitude < 10)
....
}
public static WeatherCondition GenerateWeatherCondition(....){
....
else if (location.Latitude > 10 || location.Latitude < 25)
....
else if (location.Latitude > -40 || location.Latitude < 10)
....
}
All errors are detected by this diagnostic:
V3022 Expression 'location.Latitude > -40 || location.Latitude < 10' is always true. Probably the '&&'
operator should be used here.
What else can we say? Probably the same thing as in the description of one of the errors, found by
V3001. It's useful to use this pattern when the same variable is written from both sides of the
expression:
if (xmin < rc.Right && rc.Right < xmax)
At this point we'll stop examining errors of the first level, and move on to the second and third level,
because the same message number, depending on the situation, has a different priority.
The analyzer issues diagnostic warnings of the third level, when it's not quite sure of its correctness. Also
third level is for those diagnostics which are not relevant for all projects.
In practice, the warnings of the third level are very rarely the signs of real bugs. Often these are false
positives or messages that show some smell code, which is still working quite correctly. In any case, if
there's time, these diagnostic messages should be explored, and code refactoring done.
Let's start with the code that has two identical functions:
// 0 reference
public static double Ramp(double a) {
return a - Math.Floor(a);
}
// 1 reference
public static double Frac(double a) {
return a - Math.Floor(a);
}
V3013 It is odd that the body of 'Ramp' function is fully equivalent to the body of 'Frac' function (28, line
33). Math.cs 28
If Frac function has some meaning, then only in Pascal language; while Ramp has no analogues, or I just
haven't found them. The counters of the fragments where this function is used speak for themselves
(see the comments).
Let's have a look at a case when this error appeared on the second level.
public void StartCurrent()
{
StartTask("Current");
}
public void StopCurrent()
{
StartTask("Current");
}
V3013 It is odd that the body of 'StartCurrent' function is fully equivalent to the body of 'StopCurrent'
function (503, line 507). DataViewModel.cs 503
Apparently, in the second case, the function "StartTask" was confused with "StopTask; both of these
functions are present in the code, and they act quite clearly according to their names.
Now let's look at a series of messages related to the following code:
{
IsUpdating = true;
....
IsUpdating = false;
}
The similar code can be seen in 4 fragments (in every build).
 V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake.
Check lines: 201, 195. GeoRegion.cs 201
 V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake.
Check lines: 212, 205. GeoRegion.cs 212
 V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake.
Check lines: 226, 216. GeoRegion.cs 226
 V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake.
Check lines: 244, 236. GeoRegion.cs 244
Initially it seems that this variable is used for cross-thread communication. But as it turned out, in
practice, this variable is nowhere to be found, except in strings which the diagnostic message was issued
for.
Well, suppose you decide to use this variable for cross-thread synchronization. And then this nasty
surprise waiting for us. Variable declaration looks as follows:
protected bool IsUpdating = false;
As you can see, there is no "volatile" keyword, and as a result, the compiler optimizes it successfully, and
it will work in completely the wrong way.
What else was found in the code? For example, some extra evaluations:
Example 1:
public static void Normalize(....)
{
var x = rect.X < boundingRect.X ? boundingRect.X : rect.X;
x = (rect.X + rect.Width) > boundingRect.Right ?
boundingRect.X : rect.X;
}
V3008 The 'x' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 96,
95. RectEx.cs
Example 2:
private static GradientStopCollection fromInterpolation(....){
....
Color color=ColorTool.FromAHSV(ahsv[0],
ahsv[1],
ahsv[2],
ahsv[3]);
color = ColorTool.FromARGBInterpolation(min, p, max[i].Color);
....
}
V3008 The 'color' variable is assigned values twice successively. Perhaps this is a mistake. Check lines:
165, 163. BrushTool.cs
Sometimes we come across very amusing code fragments:
private void UpdateAutoSavedState() {
AutoSaved = true;
AutoSaved = false;
}
V3008 The 'AutoSaved' variable is assigned values twice successively. Perhaps this is a mistake. Check
lines: 691, 690. ShellViewModel.cs 691
For those who are still in doubt, I provide property declaration:
private bool autoSaved;
public bool AutoSaved
{
get { return autoSaved; }
set { autoSaved = value; }
}
And again there is no "volatile", or something of this kind, that would speak about the hidden meaning
of this action.
Let's move on to another group of strings with error V3029:
public void OnPropertyChanged(PropertyChangedEventArgs ea) {
....
var index = this.SelectedBrushCollectionIndex;
....
if (index >= 0)
DebugManager.LogData(this.BrushCollectionList[index].ToText());
if (index >= 0)
this.SelectedBrushCollectionIndex = index;
....
}
V3029 The conditional expressions of the 'if' operators situated alongside each other are identical.
Check lines: 338, 339.
public static void EnableSeriesMouseDoubleClick(
this XamGeographicMap geoMap, bool isEnabled = true){
....
if (geoMap != null) geoMap.SeriesMouseLeftButtonDown +=
OnSeriesMouseLeftButtomDown;
if (geoMap != null) geoMap.SeriesMouseLeftButtonUp +=
OnSeriesMouseLeftButtonUp;
....
if (geoMap != null) geoMap.SeriesMouseLeftButtonDown -=
OnSeriesMouseLeftButtomDown;
if (geoMap != null) geoMap.SeriesMouseLeftButtonUp -=
OnSeriesMouseLeftButtonUp;
....
}
V3029 The conditional expressions of the 'if' operators situated alongside each other are identical.
Check lines: 92, 93. GeoMapAdapter.cs 92
V3029 The conditional expressions of the 'if' operators situated alongside each other are identical.
Check lines: 100, 101. GeoMapAdapter.cs 100
public void SyncSeriesViewPropertyChanges() {
if (this.SeriesView != null)
this.SeriesView.PropertyUpdated += OnSeriesViewPropertyUpdated;
if (this.SeriesView != null)
this.SeriesView.PropertyChanged += OnSeriesViewPropertyChanged;
}
V3029 The conditional expressions of the 'if' operators situated alongside each other, are identical.
Check lines: 342, 343. GeoSeriesLayer.cs 342
As it is often said - "just in case"....
Although these are not errors, repeated checking clutters up your code, and makes it difficult to
understand.
And here is redundant code, which most likely appeared during refactoring.
public Frame NavigationTarget
{
get { return (Frame)this.GetValue(NavigationTargetProperty); }
set {
var targetFrame = value as Frame;
if (targetFrame != null)
this.SetValue(NavigationTargetProperty, value);
}
}
"value" already has the Frame type, casting is pointless. But in this case, it is necessary to consider the
situation in a broader sense. Infragistics does the check against null when writing to a
DependencyProperty. The developers provided a callback function "ValidateValueCallback" for checks of
this kind. This function is set when you register a dependency property, and it checks the values that are
written into DependencyProperty .
Conclusion
Once again our Rainbow Unicorn in shining armor detected a considerable number of problem areas
(the article does not list all errors we found). The developers can now fix the code, and make it better
than it was... Than it was when it was being written ... When it was being tested... Than when it was
rewritten, run, and when it crashed again and again, or worked in ways other than it should ...
In my practice on my previous job, there were really tough times at the weekends and nights, several
days before the deadline, when we had to do a lot of work in a very short period of time. The whole
team knew what to do, but because of haste and tiredness it took more time to debug the code. I.e. we
write code, run it, and it does not work as intended. We stop everything, put a breakpoint and run it
again. Perform all actions repeatedly, set the breakpoint, and check string by string what is happening.
Jumping back and forth along code, and reviewing values in variables. But in the end it turns out that we
misplaced a variable or a character in the condition... That's how 15 minutes are spent looking for a
simple typo during the Copy-Paste.
Project analysis is just the tip of the huge iceberg of problems which occur during the creation of code.
No one is immune to errors. Even writing the code that should be exemplary in the company, it is
impossible to avoid errors.
My sincere advice to you-use PVS-Studio analyzer on a regular basis. It has all sorts of useful features.
For example, there is a mode in which the changed files are rechecked - you don't have to run it - the
analyzer checks itself what is necessary, and issues warnings where it is needed.

Mais conteúdo relacionado

Mais procurados

Zend Studio Tips and Tricks
Zend Studio Tips and TricksZend Studio Tips and Tricks
Zend Studio Tips and Tricks
Roy Ganor
 
Jug Guice Presentation
Jug Guice PresentationJug Guice Presentation
Jug Guice Presentation
Dmitry Buzdin
 
Dependency Injection або Don’t call me, I’ll call you
Dependency Injection або Don’t call me, I’ll call youDependency Injection або Don’t call me, I’ll call you
Dependency Injection або Don’t call me, I’ll call you
Dmytro Mindra
 

Mais procurados (20)

Dependency injection with unity 2.0 Dmytro Mindra Lohika
Dependency injection with unity 2.0 Dmytro Mindra LohikaDependency injection with unity 2.0 Dmytro Mindra Lohika
Dependency injection with unity 2.0 Dmytro Mindra Lohika
 
Overview of CSharp MVC3 and EF4
Overview of CSharp MVC3 and EF4Overview of CSharp MVC3 and EF4
Overview of CSharp MVC3 and EF4
 
Zend Studio Tips and Tricks
Zend Studio Tips and TricksZend Studio Tips and Tricks
Zend Studio Tips and Tricks
 
Jug Guice Presentation
Jug Guice PresentationJug Guice Presentation
Jug Guice Presentation
 
Dependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony ContainerDependency Injection, Zend Framework and Symfony Container
Dependency Injection, Zend Framework and Symfony Container
 
Create Your Own Framework by Fabien Potencier
Create Your Own Framework by Fabien PotencierCreate Your Own Framework by Fabien Potencier
Create Your Own Framework by Fabien Potencier
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right way
 
Studying the impact of Social Structures on Software Quality
Studying the impact of Social Structures on Software QualityStudying the impact of Social Structures on Software Quality
Studying the impact of Social Structures on Software Quality
 
Introduction to Google Guice
Introduction to Google GuiceIntroduction to Google Guice
Introduction to Google Guice
 
Google Guice
Google GuiceGoogle Guice
Google Guice
 
Swift 2.0: Apple’s Advanced Programming Platform for Developers
Swift 2.0: Apple’s Advanced Programming Platform for DevelopersSwift 2.0: Apple’s Advanced Programming Platform for Developers
Swift 2.0: Apple’s Advanced Programming Platform for Developers
 
nullcon 2011 - Reversing MicroSoft patches to reveal vulnerable code
nullcon 2011 - Reversing MicroSoft patches to reveal vulnerable codenullcon 2011 - Reversing MicroSoft patches to reveal vulnerable code
nullcon 2011 - Reversing MicroSoft patches to reveal vulnerable code
 
Factory pattern in Java
Factory pattern in JavaFactory pattern in Java
Factory pattern in Java
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Functional Dependency Injection in C#
Functional Dependency Injection in C#Functional Dependency Injection in C#
Functional Dependency Injection in C#
 
Java Hurdling: Obstacles and Techniques in Java Client Penetration-Testing
Java Hurdling: Obstacles and Techniques in Java Client Penetration-TestingJava Hurdling: Obstacles and Techniques in Java Client Penetration-Testing
Java Hurdling: Obstacles and Techniques in Java Client Penetration-Testing
 
C# Security Testing and Debugging
C# Security Testing and DebuggingC# Security Testing and Debugging
C# Security Testing and Debugging
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
 
Dependency Injection або Don’t call me, I’ll call you
Dependency Injection або Don’t call me, I’ll call youDependency Injection або Don’t call me, I’ll call you
Dependency Injection або Don’t call me, I’ll call you
 
Lecture17 ie321 dr_atifshahzad_js
Lecture17 ie321 dr_atifshahzad_jsLecture17 ie321 dr_atifshahzad_js
Lecture17 ie321 dr_atifshahzad_js
 

Destaque

Titulo doctor ingles
Titulo doctor inglesTitulo doctor ingles
Titulo doctor ingles
Juan Blanco
 
Uses and grats magazine
Uses and grats magazineUses and grats magazine
Uses and grats magazine
chloreadx
 

Destaque (18)

Sony C#/.NET component set analysis
Sony C#/.NET component set analysisSony C#/.NET component set analysis
Sony C#/.NET component set analysis
 
An Ideal Way to Integrate a Static Code Analyzer into a Project
An Ideal Way to Integrate a Static Code Analyzer into a ProjectAn Ideal Way to Integrate a Static Code Analyzer into a Project
An Ideal Way to Integrate a Static Code Analyzer into a Project
 
Chapter 4 computer language
Chapter 4 computer languageChapter 4 computer language
Chapter 4 computer language
 
The tyranny of averages
The tyranny of averagesThe tyranny of averages
The tyranny of averages
 
Cardio renalanemiahf clinics
Cardio renalanemiahf clinicsCardio renalanemiahf clinics
Cardio renalanemiahf clinics
 
Судова реформа
Судова реформаСудова реформа
Судова реформа
 
Exa6to bim3 2015
Exa6to bim3 2015Exa6to bim3 2015
Exa6to bim3 2015
 
The Emerging Role of BIomarkers and Bio-Impedance
The Emerging Role of BIomarkers and Bio-ImpedanceThe Emerging Role of BIomarkers and Bio-Impedance
The Emerging Role of BIomarkers and Bio-Impedance
 
Mi vida en tres minutos
Mi vida en tres minutosMi vida en tres minutos
Mi vida en tres minutos
 
Circulation heart failure
Circulation heart failureCirculation heart failure
Circulation heart failure
 
DevNexus 2016: Wait! Wait! Don't pwn me!
DevNexus 2016: Wait! Wait! Don't pwn me!DevNexus 2016: Wait! Wait! Don't pwn me!
DevNexus 2016: Wait! Wait! Don't pwn me!
 
Sample project management
Sample project managementSample project management
Sample project management
 
O Rosário
O RosárioO Rosário
O Rosário
 
Titulo doctor ingles
Titulo doctor inglesTitulo doctor ingles
Titulo doctor ingles
 
Traffic sanctions in Spain
Traffic sanctions in SpainTraffic sanctions in Spain
Traffic sanctions in Spain
 
Uses and grats magazine
Uses and grats magazineUses and grats magazine
Uses and grats magazine
 
Clinical outcome endpoints in hf trials
Clinical outcome endpoints in hf trialsClinical outcome endpoints in hf trials
Clinical outcome endpoints in hf trials
 
Clinical trials in ahf
Clinical trials in ahfClinical trials in ahf
Clinical trials in ahf
 

Semelhante a Analyzing source code of WPF examples by the Infragistics Company

.NET Portfolio
.NET Portfolio.NET Portfolio
.NET Portfolio
mwillmer
 

Semelhante a Analyzing source code of WPF examples by the Infragistics Company (20)

Looking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelopLooking for Bugs in MonoDevelop
Looking for Bugs in MonoDevelop
 
The First C# Project Analyzed
The First C# Project AnalyzedThe First C# Project Analyzed
The First C# Project Analyzed
 
.NET Portfolio
.NET Portfolio.NET Portfolio
.NET Portfolio
 
Documenting Bugs in Doxygen
Documenting Bugs in DoxygenDocumenting Bugs in Doxygen
Documenting Bugs in Doxygen
 
Checking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-StudioChecking Clang 11 with PVS-Studio
Checking Clang 11 with PVS-Studio
 
Source code of WPF samples by Microsoft was checked
Source code of WPF samples by Microsoft was checkedSource code of WPF samples by Microsoft was checked
Source code of WPF samples by Microsoft was checked
 
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
 
Accord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
Accord.Net: Looking for a Bug that Could Help Machines Conquer HumankindAccord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
Accord.Net: Looking for a Bug that Could Help Machines Conquer Humankind
 
Errors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 librariesErrors detected in the Visual C++ 2012 libraries
Errors detected in the Visual C++ 2012 libraries
 
PVS-Studio in the Clouds: Azure DevOps
PVS-Studio in the Clouds: Azure DevOpsPVS-Studio in the Clouds: Azure DevOps
PVS-Studio in the Clouds: Azure DevOps
 
Poco Es Mucho: WCF, EF, and Class Design
Poco Es Mucho: WCF, EF, and Class DesignPoco Es Mucho: WCF, EF, and Class Design
Poco Es Mucho: WCF, EF, and Class Design
 
Writing enterprise software error checking
Writing enterprise software error checkingWriting enterprise software error checking
Writing enterprise software error checking
 
We continue checking Microsoft projects: analysis of PowerShell
We continue checking Microsoft projects: analysis of PowerShellWe continue checking Microsoft projects: analysis of PowerShell
We continue checking Microsoft projects: analysis of PowerShell
 
ptu3-harvey-m-deitel-paul-j-deitel-tem-r-nieto-contributor-paul-j-deitel.pdf
ptu3-harvey-m-deitel-paul-j-deitel-tem-r-nieto-contributor-paul-j-deitel.pdfptu3-harvey-m-deitel-paul-j-deitel-tem-r-nieto-contributor-paul-j-deitel.pdf
ptu3-harvey-m-deitel-paul-j-deitel-tem-r-nieto-contributor-paul-j-deitel.pdf
 
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
Microsoft opened the source code of Xamarin.Forms. We couldn't miss a chance ...
 
descriptive programming
descriptive programmingdescriptive programming
descriptive programming
 
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
 
Tdd,Ioc
Tdd,IocTdd,Ioc
Tdd,Ioc
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?
 
PVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's codePVS-Studio: analyzing ReactOS's code
PVS-Studio: analyzing ReactOS's code
 

Último

Último (20)

%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 

Analyzing source code of WPF examples by the Infragistics Company

  • 1. Analyzing source code of WPF examples by the Infragistics Company Author: Vitaliy Alferov Date: 10.02.2016 We continue analyzing various C# projects in order to show the abilities of the static code analyzer, PVS- Studio. In this article, we are providing analysis results of WPF examples by the Infragistics Company. Infragistics is a major software vendor, founded in 1989. It gained popularity mainly through the development of enterprise-ready user interface toolsets for developers, which are run on all platforms, including .NET. Our tool - PVS-Studio 6.00 static code analyzer - had a number of C# general analysis diagnostics, that we implemented using our experience of developing the C++ analyzer. Starting with PVS-Studio 6.01, we are creating diagnostics specifically for the C# language. For a start we have chosen dependency properties that are used in WPF projects. Such a choice was made for a reason - DependencyProperties are quite difficult to create. The difficulty is that it is very easy to make a typo in the similar code that WPF tends to be made up of. We have developed a number of diagnostics [3044, 3045, 3046, 3047, 3048, 3049] specifically for the analysis of dependencies of this type. As we know, one of peculiarities of DependencyProperty, is that any error during the registration of DependencyProperty can cause a program to crash during the runtime. The programmers have to fix these errors by running the program again and again; thus a programmer spends precious minutes and - in sum total - hours, looking for typos in the template code of DependencyProperty. On top of this, the WPF analysis showed that not all errors can be detected after the first run of the program.
  • 2. The first test subject for our diagnostics, was the code of test examples from the Infragistics Company. The archive was downloaded on the 2nd of February here; there are 11 projects that can be downloaded as one archive. The analysis was done with the static code analyzer, PVS-Studio 6.01. WPF errors A large part of the projects are written on the basis of pre-used code, and this is where the analyzer detected the most errors. Error N1 In the "IGExtensions.Common.WPF" project, in the file "LambertConformalConic.cs" we saw the following string of "DependencyProperty" registration: public static readonly DependencyProperty CentralMeridianProperty = DependencyProperty.Register("CentralMeridianProperty", typeof(double), typeof(LambertConformalConic), new PropertyMetadata(0.0, new PropertyChangedCallback(UpdateConstants))); V3045 WPF: the names of the registered property 'CentralMeridianProperty', and the property 'CentralMeridian', do not correspond with each other. LambertConformalConic.cs 130 As you can see, during the registration of DependencyProperty, in its name "CentralMeridianProperty" was written instead of "CentralMeridian". This error of incorrect copying of the variable name occurs quite often, but it is especially dangerous because of the following fact: To write/read in the dependency property from the C# code, the programmers create the following property: public double CentralMeridian { get { return (double)GetValue(CentralMeridianProperty); } set { SetValue(CentralMeridianProperty, value); } } When addressing from xaml markup, binding is written for the "CentralMeridian" property. WPF is smart enough to find the CentralMeridian property and read the original value from there, but the changes in the CentralMeridian values won't be processed. Error N2 Continuing the topic of typos in the names of the registered dependency properties, let's have a look at the following error in the "TransverseMercator.cs" file of the "IGExtensions.Common.WPF"project. public static readonly DependencyProperty CentralMeridianProperty = DependencyProperty.Register("LongitudeOrigin", typeof(double), typeof(TransverseMercator), new PropertyMetadata(0.0, new PropertyChangedCallback(UpdateConstants)));
  • 3. public double CentralMeridian { .... } V3045 WPF: the names of the registered property 'LongitudeOrigin', and of the property 'CentralMeridian', do not correspond with each other. TransverseMercator.cs 95 As the practice shows, several dependency properties are written by copying the same string, and editing it later. In other words, by using Copy-Paste. Quite often, we see that in the similar code a variable is omitted and gets a different name, the one that was the closest in the list. Taking into account that the list is somewhere in the Notepad [Notepad++, Sublime Text and such] in a different window, you can check only manually if the required objects were created. It's especially hard to detect such errors because the code is generally working, but in reality - only partially. Error N3 The situation with the names of the registered properties is quite clear, but where else can a programmer make an error creating DependencyProperty? Another variant - is in the types of values that the properties should contain. Here is such an example - "IGExtensions.Common.WPF" project, "PropertyBrushColorEditor.cs" file. public static readonly DependencyProperty BrushColorProperty = DependencyProperty.Register(BrushColorPropertyName, typeof(Brush), typeof(PropertyBrushColorEditor), new PropertyMetadata(null, (sender, e) => {....}) ); public SolidColorBrush BrushColor { get { return (SolidColorBrush)GetValue(BrushColorProperty); } set { SetValue(BrushColorProperty, value); } } V3046 WPF: the type registered for DependencyProperty does not correspond with the type of the property used to access it. It's good if you don't have questions, as to why it is not correct to specify the parent class "Brush" during the registration, and to specify the heir class "SolidColorBrush" addressing through the "BrushColor" property. If it's not so, let's have a look at a simplified case of such a "game" with the stored types. Consider a simple case. Let's create a simple WPF project, and add to the class the following dependence property: public static DependencyProperty MyIndexProperty = DependencyProperty.Register("MyIndex", typeof(int), typeof(MainWindow), new FrameworkPropertyMetadata(1)); int MyIndex
  • 4. { get { return (int)GetValue(MyIndexProperty); } set { SetValue(MyIndexProperty, value); } } In xaml markup we'll write the following: .... Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource = {RelativeSource Mode=Self}}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="{Binding Path=MyIndex}"/> <Slider Grid.Row="1" Name="slider1" Value="{Binding Path=MyIndex}" Maximum="100" /> <Button Grid.Row="2" Click="Button_Click"> Read value </Button> </Grid> And add to the window class the code for pressing the button: private void Button_Click(object sender, RoutedEventArgs e) { this.Title = this.MyIndex.ToString(); } That's it. As you can see, everything works. We move the slider, the number changes. Click on the button, and the window title is immediately changed to the current value on the slider. By the way, and as you probably noticed, the TextBlock displays integer values. And now let's change the "int" type to the common "object" type in the registered DependencyProperty. public static DependencyProperty MyIndexProperty = DependencyProperty.Register("MyIndex", typeof(object), typeof(MainWindow), new FrameworkPropertyMetadata(1)); Let's leave the rest unchanged, and rerun the program.
  • 5. The program started and now when we move the slider, real values are displayed in the TextBlock. But it's not hard to guess, that if we press the button the program will crash, as it won't be able to convert a real value in MyIndexProperty into an integer one in the property MyIndex. It seems like a small thing, but it led to really bad consequences. Error N4 We have provided some error examples which are common for the majority of projects (so sad, that they are rarely fixed), but there are some "local" errors - for example in IGEquityTrading project: public static readonly DependencyProperty AxisFinancialIndicatorYTemplateProperty = DependencyProperty.Register("AxisFinancialIndicatorYTemplate", typeof(DataTemplate), typeof(DataChartEx), new PropertyMetadata(default(DataTemplate))); public DataTemplate AxisCategoryYTemplate{ get { return (DataTemplate) GetValue(AxisFinancialIndicatorYTemplateProperty); } set { SetValue(AxisFinancialIndicatorYTemplateProperty, value); } } V3045 WPF: the names of the property registered for DependencyProperty, and of the property used to access it, do not correspond with each other. DataChartEx.cs 469 Infragistics steps on the same rake by creating a property with the "AxisCategoryYTemplate" name, instead of the registered name "AxisFinancialIndicatorYTemplate". Error N5 public static readonly DependencyProperty FinancialIndicatorSeriesTemplateProperty = DependencyProperty.Register("FinancialIndicatorTemplate", typeof(DataTemplate), typeof(DataChartEx), new PropertyMetadata(default(DataTemplate))); public DataTemplate FinancialIndicatorSeriesTemplate { get { return (DataTemplate) GetValue(FinancialIndicatorSeriesTemplateProperty); } set { SetValue(FinancialIndicatorSeriesTemplateProperty, value); }
  • 6. } V3045 WPF: the names of the property registered for DependencyProperty, and of the property used to access it, do not correspond with each other. DataChartEx.cs 344 In the last case, the error most likely occurred after refactoring, when the variable was specified, and the word "Series" was inserted in the middle of the phrase "FinancialIndicatorTemplate". What's more interesting, it was changed everywhere, even in XAML markup and in "#region", but the name of the registered property remained unchanged.  ....InfraEquityTradingIGEquityTrading.WPFApp.xaml(123): <DataTemplate x:Key="FinancialIndicatorSeriesTemplate">  ....InfraEquityTradingIGEquityTrading.WPFApp.xaml(214): FinancialIndicatorSeriesTemplate="{StaticResource FinancialIndicatorSeriesTemplate}"  ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(189): var financialIndicator = FinancialIndicatorSeriesTemplate.LoadContent() as Series;  ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(330): #region FinancialIndicatorSeriesTemplate (DependencyProperty)  ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(336): public DataTemplate FinancialIndicatorSeriesTemplate  ....InfraEquityTradingIGEquityTrading.WPFControlsDataChartEx.cs(349): #endregion FinancialIndicatorSeriesTemplate (DependencyProperty)  ....InfraEquityTradingIGEquityTrading.WPFControlsStockHistoryChart.xaml(646): FinancialIndicatorSeriesTemplate="{StaticResource FinancialIndicatorSeriesTemplate}" At the same time, the registered name "FinancialIndicatorTemplate" isn't used anywhere. We already know what this can lead to. Miscellaneous C# errors We didn't see any other WPF errors in these builds from the Infragistics Company. As was already mentioned, the majority of WPF diagnostics are designed to find bugs before compiling and running the project. These projects with the examples have already been checked by programmers and QA specialists. Additionally, these projects were also viewed by the users who could judge the quality and operability of the tool, working with the test examples. I guess if they noticed an error, they notified the developers. Of course, there are other errors in these builds besides the WPF ones. The analyzer issued several hundred warnings in total. Not all of the messages indicate a real error. Many warnings (for example, comparing double type with constant), are simply not relevant for this type of project. It's not a big problem, because the analyzer provides several mechanisms to suppress uninteresting messages. In any case, there are a lot of warnings, and most of them show the anomalies in the code. These are real mistakes or code "smell". Therefore we recommend that developers do the analysis themselves, and examine all the analyzer warnings. In this article we'll have a look at the most interesting ones: public bool IsValid { get { var valid = double.IsNaN(Latitude) || double.IsNaN(Latitude) ||
  • 7. this.Weather.DateTime == Weather.DateTimeInitial; return valid; } } V3001 There are identical sub-expressions 'double.IsNaN(Latitude)' to the left and to the right of the '||' operator. WeatherStation.cs 25 Programmers have a hard life. They must understand not only the programming, but also the areas in which the program should work. It turns out that they must understand the subject area, and know some specific words "Credit", "Debit", Latitude", "Longitude", for example, and so it just adds complexity, especially if the concepts are similar in spelling. It turns out that we mistakenly write checks of the same variable: double.IsNaN(Latitude) || double.IsNaN(Latitude). Next error: private static int clipSegment(....) { if (xmax > rc.Right && xmax > rc.Right) { return -1; } } V3001 There are identical sub-expressions 'xmax > rc.Right' to the left and to the right of the '&&' operator. Geometry. Geometry.CubicSpline.cs 529 It's quite a common thing - to check the limits of a variable, but it's quite easy to make an error writing symbols after, and in, the variable. To avoid such errors you should stick to the following pattern: The common variable is written from different sides in the expressions. if (xmin < rc.Right && rc.Right < xmax) It's harder to make a mistake, and it becomes more readable. P.S. The same trick, however, won't work in Entity Framework; the program will crash during the conversion of LINQ code to SQL. So here's the case :) Infragistics developers put too much thought into these checks. Besides the error given above, the same error repeated in the following strings: private static int clipSegment(....) { .... if (ymin < rc.Top && ymin < rc.Top) //<= here .... if (ymax > rc.Bottom && ymax > rc.Bottom) //<= and here ....
  • 8. } For the diagnostic V3001 it is still not enough, and it continues the expansion. Here is another example of its work: private static bool IsInDesignModeStatic(this Application app) { .... if (_isInDesignMode != null && _isInDesignMode.HasValue) return _isInDesignMode.Value; .... } V3001 There are identical sub-expressions '_isInDesignMode != null' to the left and to the right of the '&&' operator. NavigationApp.cs 415 In this case we have redundant code, not an error. This was enough: if (_isInDesignMode.HasValue) Another warning of V3001 void ParagraphSettingsPreviewAdapter_PropertyChanged( object sender, PropertyChangedEventArgs e) { .... if (LineSpacingType == Infrastructure.LineSpacingTypes.Exactly || LineSpacingType == Infrastructure.LineSpacingTypes.Exactly){ .... } V3001 There are identical sub-expressions 'LineSpacingType == Infrastructure.LineSpacingTypes.Exactly' to the left and to the right of the '||' operator. ParagraphSettingsPreviewAdapter.cs 268 It's not quite clear what the programmer meant here, but not what is really written. Let's move on from V3001 to V3010. There are a couple of function calls in the "IGEarthQuake.WPF" project. public MapViewModel() { .... WeakPropertyChangedListener.CreateIfNecessary(_service, this); .... } V3010 The return value of function 'CreateIfNecessary' is required to be utilized. MapViewModel.cs 42 public TimeLineViewModel(){
  • 9. .... WeakPropertyChangedListener.CreateIfNecessary(_service, this); .... } V3010 The return value of function 'CreateIfNecessary' is required to be utilized. TimeLineViewModel.cs 50 The same rather simple function is called in both cases. Let's look at its implementation: public static WeakPropertyChangedListener CreateIfNecessary(object source, IPropertyChangedListener listener){ INotifyPropertyChanged inpc = source as INotifyPropertyChanged; return inpc != null ? new WeakPropertyChangedListener(inpc, listener) : null; } As you can see, this feature does not bring any global changes, and its result is also not used. So here is the question - why was it called at all? Looks very suspicious... A similar example is in the "IGHospitalFloorPlan.WPF" project: private void ParseAllShapefiles() { .... this.ShapeFilesMaxBounds.Expand(new Thickness(10, 10, 10, 10)); .... } V3010 The return value of function 'Expand' is required to be utilized. HospitalView.xaml.cs 52 Its implementation is slightly trickier, but ultimately it just returns a new object that is never used. We've reached the middle of the article. Have a look at this picture; relax, and then we'll continue.
  • 10. One of the most common types of error, is a bad Copy-Paste: public static EsriMapImageryView GetImageryView(EsriMapImageryStyle imageryStyle){ .... if (imageryStyle == EsriMapImageryStyle.UsaPopulationChange2010Overlay) return EsriMapImageryViews.UsaPopulationChange2010Overlay; if (imageryStyle == EsriMapImageryStyle.UsaPopulationChange2010Overlay) return EsriMapImageryViews.UsaPopulationChange2010Overlay; .... } V3021 There are two 'if' statements with identical conditional expressions. The first 'if' statement contains method return. This means that the second 'if' statement is senseless EsriMapImageryView.cs 97 In this case, the same code is under the same condition. At this stage, the error is a bad (redundant) Copy-Paste method. But after refactoring, it may happen that the programmer changes the body of the inferior if function, that is never executed, and an error occurs in the program logic. Let's see other errors that occurred in the code of Infragistics company. Warning V3022 was issued for the following string:
  • 11. public static double GenerateTemperature(GeoLocation location){ .... else if (location.Latitude > 10 || location.Latitude < 25) .... else if (location.Latitude > -40 || location.Latitude < 10) .... } public static WeatherCondition GenerateWeatherCondition(....){ .... else if (location.Latitude > 10 || location.Latitude < 25) .... else if (location.Latitude > -40 || location.Latitude < 10) .... } All errors are detected by this diagnostic: V3022 Expression 'location.Latitude > -40 || location.Latitude < 10' is always true. Probably the '&&' operator should be used here. What else can we say? Probably the same thing as in the description of one of the errors, found by V3001. It's useful to use this pattern when the same variable is written from both sides of the expression: if (xmin < rc.Right && rc.Right < xmax) At this point we'll stop examining errors of the first level, and move on to the second and third level, because the same message number, depending on the situation, has a different priority. The analyzer issues diagnostic warnings of the third level, when it's not quite sure of its correctness. Also third level is for those diagnostics which are not relevant for all projects. In practice, the warnings of the third level are very rarely the signs of real bugs. Often these are false positives or messages that show some smell code, which is still working quite correctly. In any case, if there's time, these diagnostic messages should be explored, and code refactoring done. Let's start with the code that has two identical functions: // 0 reference public static double Ramp(double a) { return a - Math.Floor(a); } // 1 reference public static double Frac(double a) {
  • 12. return a - Math.Floor(a); } V3013 It is odd that the body of 'Ramp' function is fully equivalent to the body of 'Frac' function (28, line 33). Math.cs 28 If Frac function has some meaning, then only in Pascal language; while Ramp has no analogues, or I just haven't found them. The counters of the fragments where this function is used speak for themselves (see the comments). Let's have a look at a case when this error appeared on the second level. public void StartCurrent() { StartTask("Current"); } public void StopCurrent() { StartTask("Current"); } V3013 It is odd that the body of 'StartCurrent' function is fully equivalent to the body of 'StopCurrent' function (503, line 507). DataViewModel.cs 503 Apparently, in the second case, the function "StartTask" was confused with "StopTask; both of these functions are present in the code, and they act quite clearly according to their names. Now let's look at a series of messages related to the following code: { IsUpdating = true; .... IsUpdating = false; } The similar code can be seen in 4 fragments (in every build).  V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 201, 195. GeoRegion.cs 201  V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 212, 205. GeoRegion.cs 212  V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 226, 216. GeoRegion.cs 226  V3008 The 'IsUpdating' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 244, 236. GeoRegion.cs 244 Initially it seems that this variable is used for cross-thread communication. But as it turned out, in practice, this variable is nowhere to be found, except in strings which the diagnostic message was issued for.
  • 13. Well, suppose you decide to use this variable for cross-thread synchronization. And then this nasty surprise waiting for us. Variable declaration looks as follows: protected bool IsUpdating = false; As you can see, there is no "volatile" keyword, and as a result, the compiler optimizes it successfully, and it will work in completely the wrong way. What else was found in the code? For example, some extra evaluations: Example 1: public static void Normalize(....) { var x = rect.X < boundingRect.X ? boundingRect.X : rect.X; x = (rect.X + rect.Width) > boundingRect.Right ? boundingRect.X : rect.X; } V3008 The 'x' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 96, 95. RectEx.cs Example 2: private static GradientStopCollection fromInterpolation(....){ .... Color color=ColorTool.FromAHSV(ahsv[0], ahsv[1], ahsv[2], ahsv[3]); color = ColorTool.FromARGBInterpolation(min, p, max[i].Color); .... } V3008 The 'color' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 165, 163. BrushTool.cs Sometimes we come across very amusing code fragments: private void UpdateAutoSavedState() { AutoSaved = true; AutoSaved = false; } V3008 The 'AutoSaved' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 691, 690. ShellViewModel.cs 691 For those who are still in doubt, I provide property declaration: private bool autoSaved;
  • 14. public bool AutoSaved { get { return autoSaved; } set { autoSaved = value; } } And again there is no "volatile", or something of this kind, that would speak about the hidden meaning of this action. Let's move on to another group of strings with error V3029: public void OnPropertyChanged(PropertyChangedEventArgs ea) { .... var index = this.SelectedBrushCollectionIndex; .... if (index >= 0) DebugManager.LogData(this.BrushCollectionList[index].ToText()); if (index >= 0) this.SelectedBrushCollectionIndex = index; .... } V3029 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 338, 339. public static void EnableSeriesMouseDoubleClick( this XamGeographicMap geoMap, bool isEnabled = true){ .... if (geoMap != null) geoMap.SeriesMouseLeftButtonDown += OnSeriesMouseLeftButtomDown; if (geoMap != null) geoMap.SeriesMouseLeftButtonUp += OnSeriesMouseLeftButtonUp; .... if (geoMap != null) geoMap.SeriesMouseLeftButtonDown -= OnSeriesMouseLeftButtomDown; if (geoMap != null) geoMap.SeriesMouseLeftButtonUp -= OnSeriesMouseLeftButtonUp; .... } V3029 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 92, 93. GeoMapAdapter.cs 92
  • 15. V3029 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 100, 101. GeoMapAdapter.cs 100 public void SyncSeriesViewPropertyChanges() { if (this.SeriesView != null) this.SeriesView.PropertyUpdated += OnSeriesViewPropertyUpdated; if (this.SeriesView != null) this.SeriesView.PropertyChanged += OnSeriesViewPropertyChanged; } V3029 The conditional expressions of the 'if' operators situated alongside each other, are identical. Check lines: 342, 343. GeoSeriesLayer.cs 342 As it is often said - "just in case".... Although these are not errors, repeated checking clutters up your code, and makes it difficult to understand. And here is redundant code, which most likely appeared during refactoring. public Frame NavigationTarget { get { return (Frame)this.GetValue(NavigationTargetProperty); } set { var targetFrame = value as Frame; if (targetFrame != null) this.SetValue(NavigationTargetProperty, value); } } "value" already has the Frame type, casting is pointless. But in this case, it is necessary to consider the situation in a broader sense. Infragistics does the check against null when writing to a DependencyProperty. The developers provided a callback function "ValidateValueCallback" for checks of this kind. This function is set when you register a dependency property, and it checks the values that are written into DependencyProperty . Conclusion Once again our Rainbow Unicorn in shining armor detected a considerable number of problem areas (the article does not list all errors we found). The developers can now fix the code, and make it better than it was... Than it was when it was being written ... When it was being tested... Than when it was rewritten, run, and when it crashed again and again, or worked in ways other than it should ... In my practice on my previous job, there were really tough times at the weekends and nights, several days before the deadline, when we had to do a lot of work in a very short period of time. The whole team knew what to do, but because of haste and tiredness it took more time to debug the code. I.e. we write code, run it, and it does not work as intended. We stop everything, put a breakpoint and run it again. Perform all actions repeatedly, set the breakpoint, and check string by string what is happening. Jumping back and forth along code, and reviewing values in variables. But in the end it turns out that we
  • 16. misplaced a variable or a character in the condition... That's how 15 minutes are spent looking for a simple typo during the Copy-Paste. Project analysis is just the tip of the huge iceberg of problems which occur during the creation of code. No one is immune to errors. Even writing the code that should be exemplary in the company, it is impossible to avoid errors. My sincere advice to you-use PVS-Studio analyzer on a regular basis. It has all sorts of useful features. For example, there is a mode in which the changed files are rechecked - you don't have to run it - the analyzer checks itself what is necessary, and issues warnings where it is needed.