{"id":393855,"date":"2024-06-29T11:15:59","date_gmt":"2024-06-29T11:15:59","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=393855"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=393855","title":{"rendered":"<span>A variety of errors in C# code by the example of CMS DotNetNuke: 40 questions about the quality<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/e12\/351\/790\/e12351790900ad3143e2529b47446743.png\" alt=\"0890_DNN\/image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e12\/351\/790\/e12351790900ad3143e2529b47446743.png\"\/><\/p>\n<p>  <\/p>\n<p>Today, we discuss C# code quality and a variety of errors by the example of CMS DotNetNuke. We&#8217;re going to dig into its source code. You&#8217;re going to need a cup of coffee&#8230;<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"dotnetnuke\">DotNetNuke<\/h2>\n<p>  <\/p>\n<p>DotNetNuke is an open-source content management system (CMS) written mainly in C#. The source code is available on <a href=\"https:\/\/github.com\/dnnsoftware\/Dnn.Platform\">GitHub<\/a>. The project is part of <a href=\"https:\/\/dotnetfoundation.org\/\">the .NET Foundation<\/a>.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/594\/8e3\/043\/5948e3043798c5cc16173b439be6fb94.png\" alt=\"0890_DNN\/image2.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/594\/8e3\/043\/5948e3043798c5cc16173b439be6fb94.png\"\/><\/p>\n<p>  <\/p>\n<p>The project has its <a href=\"https:\/\/www.dnnsoftware.com\/\">website<\/a>, <a href=\"https:\/\/twitter.com\/dnn\">Twitter<\/a>, <a href=\"https:\/\/www.youtube.com\/c\/dotnetnuke\/videos\">YouTube channel<\/a>. <\/p>\n<p>  <\/p>\n<p>However, I still don&#8217;t understand the project status. The GitHub repository is updated from time to time. They have new releases. Though, it&#8217;s been a while since they post something on Twitter or YouTube channel.<\/p>\n<p>  <\/p>\n<p>At the same time, they have a <a href=\"https:\/\/dnncommunity.org\/\">community website<\/a> where you can find information about some events.<\/p>\n<p>  <\/p>\n<p>Anyway, we are interested in the code especially. The code and its quality.<\/p>\n<p>  <\/p>\n<p>By the way, the <a href=\"https:\/\/github.com\/dnnsoftware\/Dnn.Platform\">project web page<\/a> (see a screenshot below) shows that the developers use the <a href=\"https:\/\/www.ndepend.com\/\">NDepend<\/a> static analyzer to monitor code quality.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/e27\/d30\/b57\/e27d30b5756e596cd71dc5b80fb397c6.png\" alt=\"0890_DNN\/image3.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e27\/d30\/b57\/e27d30b5756e596cd71dc5b80fb397c6.png\"\/><\/p>\n<p>  <\/p>\n<p>I don&#8217;t know how the project developers configured the analyzer, whether warnings are handled, and so on. But I&#8217;d like to remind you that it&#8217;s better to use static analysis tools regularly in your development process. You can find lots of articles on this topic \u2013 visit <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/\">our blog<\/a> to read some.<\/p>\n<p>  <\/p>\n<h2 id=\"about-the-check\">About the check<\/h2>\n<p>  <\/p>\n<p>To check the project, I used the source code from <a href=\"https:\/\/github.com\/dnnsoftware\/Dnn.Platform\">GitHub<\/a> from the 22nd of October 2021. Take into account that we published \/ you read this article after a while. The code may be different by now.<\/p>\n<p>  <\/p>\n<p>I use <a href=\"https:\/\/pvs-studio.com\/en\/pvs-studio\/\">PVS-Studio<\/a> 7.15 to perform the analysis. Want to try the analyzer on your project? Click <a href=\"https:\/\/pvs-studio.com\/en\/pvs-studio\/try-free\/\">here<\/a> to open the page with all the necessary steps. Have any questions? Don&#8217;t understand something? Feel free to <a href=\"https:\/\/pvs-studio.com\/en\/about-feedback\/?is_question_form_open=true\">contact us<\/a>.<\/p>\n<p>  <\/p>\n<p>Today, I&#8217;d like to start with one of the new features of PVS-Studio 7.15 \u2013 the best warnings list. The feature is brand-new, and we will enhance it in the future. However, you can (and should) use it right now.<\/p>\n<p>  <\/p>\n<h2 id=\"best-warnings\">Best warnings<\/h2>\n<p>  <\/p>\n<p>Let&#8217;s say you decide to try a static analyzer on your project. You downloaded it, analyzed the project, and\u2026 got a bunch of warnings. Tens, hundreds, thousands, maybe even tens of thousands. Wow, &#171;cool&#187;\u2026 It would be great to magically select, for example, the Top 10 most interesting warnings. Enough to look at and think: &#171;Yeah, that code is rubbish, definitely!&#187;. Well, now PVS-Studio has such a mechanism. It is called <a href=\"https:\/\/pvs-studio.com\/en\/docs\/manual\/6532\/\">best warnings<\/a>.<\/p>\n<p>  <\/p>\n<p>So far, you can use the feature only in the PVS-Studio plugin for Visual Studio. But we plan to add the best warnings to other IDE plugins later. With the best warnings mechanism, the analyzer selects the most interesting and plausible warnings from the log.<\/p>\n<p>  <\/p>\n<p>Ready to see the best warnings list for the DNN project?<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 1<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public string NavigateURL(int tabID,                            bool isSuperTab,                            IPortalSettings settings,                            ....) {   ....   if (isSuperTab)   {     url += \"&amp;portalid=\" + settings.PortalId;   }    TabInfo tab = null;   if (settings != null)   {     tab = TabController.Instance.GetTab(tabID,              isSuperTab ? Null.NullInteger : settings.PortalId, false);   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a> The &#8216;settings&#8217; object was used before it was verified against null. Check lines: 190, 195. DotNetNuke.Library NavigationManager.cs 190<\/p>\n<p>  <\/p>\n<p>I wonder why at first we access the <em>settings.PortalId<\/em> instance property, and then we check <em>settings<\/em> for <em>null<\/em> inequality. Thus, if <em>settings<\/em> \u2013 <em>null<\/em> and <em>isSuperTab<\/em> \u2013 <em>true<\/em>, we get <em>NullReferenceException<\/em>.<\/p>\n<p>  <\/p>\n<p>Surprisingly, this code fragment has a second contract that links <em>isSuperTab<\/em> and <em>settings<\/em> parameters \u2013 the ternary operator: <em>isSuperTab? Null.NullInteger: settings.PortalId<\/em>. Note that in this case, unlike <em>if<\/em>, <em>settings.PortalId<\/em> is used when <em>isSuperTab<\/em> is <em>false<\/em>.<\/p>\n<p>  <\/p>\n<p>If <em>isSuperTab<\/em> is <em>true<\/em>, the <em>settings.PortalId<\/em> value is not processed. You may think that it&#8217;s just an implicit contract, and everything is fine.<\/p>\n<p>  <\/p>\n<p>Nope.<\/p>\n<p>  <\/p>\n<p>The code must be easy to read and understandable \u2013 you don&#8217;t have to think like Sherlock. If you intend to create this contract, write it explicitly in the code. Thus, the developers, the static analyzer, and you will not be confused. \ud83d\ude09<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 2<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static string GetTableName(Type objType) {   string tableName = string.Empty;    \/\/ If no attrubute then use Type Name   if (string.IsNullOrEmpty(tableName))   {     tableName = objType.Name;     if (tableName.EndsWith(\"Info\"))     {       \/\/ Remove Info ending       tableName.Replace(\"Info\", string.Empty);     }   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3010\/\">V3010<\/a> The return value of function &#8216;Replace&#8217; is required to be utilized. DotNetNuke.Library CBO.cs 1038<\/p>\n<p>  <\/p>\n<p>Here we have several curious cases:<\/p>\n<p>  <\/p>\n<ul>\n<li>the developers wanted to remove the <em>&#171;Info&#187;<\/em> substring from <em>tableName<\/em> but forgot that C# strings are immutable. <em>tableName<\/em> remains the same. The replaced string is lost, since the result of the <em>Replace<\/em> method call is not stored anywhere;<\/li>\n<li>the <em>tableName<\/em> variable initialized with an empty string is declared in the code. Right after, the developers check whether <em>tableName<\/em> is an empty string.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>The analyzer issues the warning for the first case. By the way, the analyzer also detects the second case. However, the best warnings list does not include this warning. Here it is: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;string.IsNullOrEmpty(tableName)&#8217; is always true. DotNetNuke.Library CBO.cs 1032<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 3<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static ArrayList GetFileList(...., string strExtensions, ....) {   ....   if (   strExtensions.IndexOf(            strExtension,             StringComparison.InvariantCultureIgnoreCase) != -1       || string.IsNullOrEmpty(strExtensions))   {     arrFileList.Add(new FileItem(fileName, fileName));   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3027\/\">V3027<\/a> The variable &#8216;strExtensions&#8217; was utilized in the logical expression before it was verified against null in the same logical expression. DotNetNuke.Library Globals.cs 3783<\/p>\n<p>  <\/p>\n<p>In the <em>strExtensions<\/em> string, the developers try to find the <em>strExtension<\/em> substring. If the substring is not found, they check whether <em>strExtensions<\/em> is empty or <em>null<\/em>. But if <em>strExtensions<\/em> is <em>null<\/em>, the <em>IndexOf<\/em> call leads to <em>NullReferenceException<\/em>.<\/p>\n<p>  <\/p>\n<p>If <em>strExtension<\/em> is implied to be an empty string but never has a <em>null<\/em> value, we can more explicitly express the intentions: <em>strExtensions.Length == 0<\/em>.<\/p>\n<p>  <\/p>\n<p>In any case, it&#8217;s better to fix this code fragment because it raises questions \u2013 as in <strong>Issue 1<\/strong>.<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 4<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static void KeepAlive(Page page) {   ....   var scriptBlock = string.Format(     \"(function($){{setInterval(       function(){{$.get(location.href)}}, {1});}}(jQuery));\",     Globals.ApplicationPath,      seconds);   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3025\/\">V3025<\/a> Incorrect format. A different number of format items is expected while calling &#8216;Format&#8217; function. Arguments not used: Globals.ApplicationPath. DotNetNuke.Library jQuery.cs 402<\/p>\n<p>  <\/p>\n<p>Suspicious operations with formatted strings \u2013 the value of the <em>seconds<\/em> variable is substituted into the resulting string. But there was no place for <em>Globals.ApplicationPath<\/em> due to the absence of <em>{0}<\/em> in the format string.<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 5<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void ProcessRequest(....) {   ....   if (!result.RewritePath.ToLowerInvariant().Contains(\"tabId=\"))   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3122\/\">V3122<\/a> The &#8216;result.RewritePath.ToLowerInvariant()&#8217; lowercase string is compared with the &#8216;&#187;tabId=&#187;&#8216; mixed case string. DotNetNuke.Library AdvancedUrlRewriter.cs 2252<\/p>\n<p>  <\/p>\n<p>Guess I&#8217;ve never seen warnings of this diagnostic in projects. Well, a first time for everything. \ud83d\ude42<\/p>\n<p>  <\/p>\n<p>The developers lowercase the string from <em>RewritePath<\/em> and check whether it has the <em>&#171;tabId=&#187;<\/em> substring. But there&#8217;s a problem \u2013 the source string is lowercased, but the string that they check contains uppercase characters.<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 6<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">protected override void RenderEditMode(HtmlTextWriter writer) {   ....   \/\/ Add the Not Specified Option   if (this.ValueField == ListBoundField.Text)   {     writer.AddAttribute(HtmlTextWriterAttribute.Value, Null.NullString);   }   else   {     writer.AddAttribute(HtmlTextWriterAttribute.Value, Null.NullString);   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3004\/\">V3004<\/a> The &#8216;then&#8217; statement is equivalent to the &#8216;else&#8217; statement. DotNetNuke.Library DNNListEditControl.cs 380<\/p>\n<p>  <\/p>\n<p>Classic copy-paste: <em>then<\/em> and <em>else<\/em> branches of the <em>if<\/em> statement are identical.<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 7<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static string LocalResourceDirectory {   get   {     return \"App_LocalResources\";   } } private static bool HasLocalResources(string path) {   var folderInfo = new DirectoryInfo(path);    if (path.ToLowerInvariant().EndsWith(Localization.LocalResourceDirectory))   {     return true;   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3122\/\">V3122<\/a> The &#8216;path.ToLowerInvariant()&#8217; lowercase string is compared with the &#8216;Localization.LocalResourceDirectory&#8217; mixed case string. Dnn.PersonaBar.Extensions LanguagesController.cs 644<\/p>\n<p>  <\/p>\n<p>Here we go again. But this time, the error is less obvious. The developers convert the <em>path<\/em> value to lowercase. Then, they check whether it ends in a string that contains uppercase characters \u2013 <em>&#171;App_LocalResources&#187;<\/em> (the literal returned from the <em>LocalResourceDirectory<\/em> property).<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 8<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">internal static IEnumerable&lt;PropertyInfo> GetEditorConfigProperties() {   return     typeof(EditorConfig).GetProperties()       .Where(         info => !info.Name.Equals(\"Magicline_KeystrokeNext\")               &amp;&amp; !info.Name.Equals(\"Magicline_KeystrokePrevious\")              &amp;&amp; !info.Name.Equals(\"Plugins\")               &amp;&amp; !info.Name.Equals(\"Codemirror_Theme\")              &amp;&amp; !info.Name.Equals(\"Width\")               &amp;&amp; !info.Name.Equals(\"Height\")               &amp;&amp; !info.Name.Equals(\"ContentsCss\")              &amp;&amp; !info.Name.Equals(\"Templates_Files\")               &amp;&amp; !info.Name.Equals(\"CustomConfig\")              &amp;&amp; !info.Name.Equals(\"Skin\")               &amp;&amp; !info.Name.Equals(\"Templates_Files\")              &amp;&amp; !info.Name.Equals(\"Toolbar\")               &amp;&amp; !info.Name.Equals(\"Language\")              &amp;&amp; !info.Name.Equals(\"FileBrowserWindowWidth\")               &amp;&amp; !info.Name.Equals(\"FileBrowserWindowHeight\")              &amp;&amp; !info.Name.Equals(\"FileBrowserWindowWidth\")               &amp;&amp; !info.Name.Equals(\"FileBrowserWindowHeight\")              &amp;&amp; !info.Name.Equals(\"FileBrowserUploadUrl\")               &amp;&amp; !info.Name.Equals(\"FileBrowserImageUploadUrl\")              &amp;&amp; !info.Name.Equals(\"FilebrowserImageBrowseLinkUrl\")              &amp;&amp; !info.Name.Equals(\"FileBrowserImageBrowseUrl\")              &amp;&amp; !info.Name.Equals(\"FileBrowserFlashUploadUrl\")              &amp;&amp; !info.Name.Equals(\"FileBrowserFlashBrowseUrl\")              &amp;&amp; !info.Name.Equals(\"FileBrowserBrowseUrl\")              &amp;&amp; !info.Name.Equals(\"DefaultLinkProtocol\")); }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3001\/\">V3001<\/a> There are identical sub-expressions &#8216;!info.Name.Equals(&#171;Templates_Files&#187;)&#8217; to the left and to the right of the &#8216;&amp;&amp;&#8217; operator. DNNConnect.CKEditorProvider SettingsUtil.cs 1451<\/p>\n<p>  <\/p>\n<p>I&#8217;ve formatted this code to make it clearer. The analyzer detected a suspicious duplicate of checks: <em>!info.Name.Equals(&#171;Templates_Files&#187;)<\/em>. Perhaps this code is redundant. Or some necessary check got lost here.<\/p>\n<p>  <\/p>\n<p>In fact, we also have other duplicates here. For some reason, the analyzer did not report about them (we&#8217;ll check it later). Also, the following expressions occur twice:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>!info.Name.Equals(&#171;FileBrowserWindowWidth&#187;)<\/em><\/li>\n<li><em>!info.Name.Equals(&#171;FileBrowserWindowHeight&#187;)<\/em><\/li>\n<\/ul>\n<p>  <\/p>\n<p>Three duplicate checks within the same expression \u2013 not bad. I guess that&#8217;s a record!<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 9<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void ProcessContentPane() {   ....   string moduleEditRoles      = this.ModuleConfiguration.ModulePermissions.ToString(\"EDIT\");   ....   moduleEditRoles      = moduleEditRoles.Replace(\";\", string.Empty).Trim().ToLowerInvariant();   ....   if (    viewRoles.Equals(this.PortalSettings.AdministratorRoleName,                             StringComparison.InvariantCultureIgnoreCase)       &amp;&amp; (moduleEditRoles.Equals(this.PortalSettings.AdministratorRoleName,                                   StringComparison.InvariantCultureIgnoreCase)           || string.IsNullOrEmpty(moduleEditRoles))       &amp;&amp; pageEditRoles.Equals(this.PortalSettings.AdministratorRoleName,                                StringComparison.InvariantCultureIgnoreCase))   {     adminMessage = Localization.GetString(\"ModuleVisibleAdministrator.Text\");     showMessage =    !this.ModuleConfiguration.HideAdminBorder                    &amp;&amp; !Globals.IsAdminControl();   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3027\/\">V3027<\/a> The variable &#8216;moduleEditRoles&#8217; was utilized in the logical expression before it was verified against null in the same logical expression. DotNetNuke.Library Container.cs 273<\/p>\n<p>  <\/p>\n<p>Hmm, too much code\u2026 Let&#8217;s reduce it.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">   moduleEditRoles.Equals(this.PortalSettings.AdministratorRoleName,                            StringComparison.InvariantCultureIgnoreCase) || string.IsNullOrEmpty(moduleEditRoles)<\/code><\/pre>\n<p>  <\/p>\n<p>So much better now! I guess we&#8217;ve already discussed something similar today\u2026 Again, at first, the developers check whether <em>moduleEditRoles<\/em> equals another string. Then they check whether <em>moduleEditRoles<\/em> is an empty string or a <em>null<\/em> value.<\/p>\n<p>  <\/p>\n<p>However, at this stage, the variable cannot store a <em>null<\/em> value because it contains the result of the <em>ToLowerInvariant<\/em> method. Therefore, it can be an empty string at most. We could lower the warning level of the analyzer here.<\/p>\n<p>  <\/p>\n<p>Though, I would fix the code by moving the <em>IsNullOrEmpty<\/em> check in the beginning.<\/p>\n<p>  <\/p>\n<p><strong>Best warnings. Issue 10<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static void Handle404OrException(....) {   ....   string errRV;   ....   if (result != null &amp;&amp; result.Action != ActionType.Output404)   {     ....     \/\/ line 552     errRV = \"500 Rewritten to {0} : {1}\";   }   else \/\/ output 404 error   {     ....     \/\/ line 593     errRV = \"404 Rewritten to {0} : {1} : Reason {2}\";     ....   }   ....   \/\/ line 623   response.AppendHeader(errRH,                          string.Format(                           errRV,                            \"DNN Tab\",                           errTab.TabName                              + \"(Tabid:\" + errTabId.ToString() + \")\",                           reason));   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3025\/\">V3025<\/a> Incorrect format. A different number of format items is expected while calling &#8216;Format&#8217; function. Arguments not used: reason. DotNetNuke.Library AdvancedUrlRewriter.cs 623<\/p>\n<p>  <\/p>\n<p>False positive. Obviously, the programmer intended to write the code this way. So, we must fix this at the analyzer level.<\/p>\n<p>  <\/p>\n<p><strong>Summary<\/strong><\/p>\n<p>  <\/p>\n<p>Not bad, I guess! Yeah, we have 1 false positive. But other issues in the code must be fixed.<\/p>\n<p>  <\/p>\n<p>However, you are free to create your list of the best warnings. For that, I describe other warnings below. \ud83d\ude42<\/p>\n<p>  <\/p>\n<h2 id=\"other-warnings\">Other warnings<\/h2>\n<p>  <\/p>\n<p>As you see, that&#8217;s not all we have today! The analyzer found lots of worthy cases to consider.<\/p>\n<p>  <\/p>\n<p><strong>Issue 11<\/strong><\/p>\n<p>  <\/p>\n<p>In the best warnings section, we&#8217;ve already discussed a copy-paste of then\/else branches of the <em>if<\/em> statement. Unfortunately, this is not the only place:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">protected void ExecuteSearch(string searchText, string searchType) {   ....   if (Host.UseFriendlyUrls)   {     this.Response.Redirect(this._navigationManager.NavigateURL(searchTabId));   }   else   {     this.Response.Redirect(this._navigationManager.NavigateURL(searchTabId));   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3004\/\">V3004<\/a> The &#8216;then&#8217; statement is equivalent to the &#8216;else&#8217; statement. DotNetNuke.Website Search.ascx.cs 432<\/p>\n<p>  <\/p>\n<p><strong>Issues 12, 13<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static void LoadProviders() {   ....   foreach (KeyValuePair&lt;string, SitemapProvider> comp in              ComponentFactory.GetComponents&lt;SitemapProvider>())   {     comp.Value.Name = comp.Key;     comp.Value.Description = comp.Value.Description;     _providers.Add(comp.Value);   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3005\/\">V3005<\/a> The &#8216;comp.Value.Description&#8217; variable is assigned to itself. DotNetNuke.Library SitemapBuilder.cs 231<\/p>\n<p>  <\/p>\n<p>Sometimes you can encounter the code where a variable is assigned to itself. This code can be redundant or may contain a more serious error \u2013 perhaps the developers mixed something up. I guess the above code fragment is exactly the case.<\/p>\n<p>  <\/p>\n<p><em>Description<\/em> is an auto-implemented property:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public string Description { get; set; }<\/code><\/pre>\n<p>  <\/p>\n<p>Here&#8217;s one more fragment that contains the variable assigned to itself:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public SendTokenizedBulkEmail(List&lt;string> addressedRoles,                                List&lt;UserInfo> addressedUsers,                                bool removeDuplicates,                                string subject,                                string body) {   this.ReportRecipients = true;   this.AddressMethod = AddressMethods.Send_TO;   this.BodyFormat = MailFormat.Text;   this.Priority = MailPriority.Normal;   this._addressedRoles = addressedRoles;   this._addressedUsers = addressedUsers;   this.RemoveDuplicates = removeDuplicates;   this.Subject = subject;   this.Body = body;   this.SuppressTokenReplace = this.SuppressTokenReplace;   this.Initialize(); }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3005\/\">V3005<\/a> The &#8216;this.SuppressTokenReplace&#8217; variable is assigned to itself. DotNetNuke.Library SendTokenizedBulkEmail.cs 109<\/p>\n<p>  <\/p>\n<p>This code is not as suspicious as the previous one but still looks strange. The <em>SuppressTokenReplace<\/em> property is assigned to itself. The corresponding parameter is absent. I don&#8217;t know what value must be assigned. Maybe the default value described in the comments (that is, <em>false<\/em>):<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">\/\/\/ &lt;summary>Gets or sets a value indicating whether               shall automatic TokenReplace be prohibited?.&lt;\/summary> \/\/\/ &lt;remarks>default value: false.&lt;\/remarks> public bool SuppressTokenReplace { get; set; }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>Issues 14, 15<\/strong><\/p>\n<p>  <\/p>\n<p>In the best warnings section, we discussed that the developers forgot about strings&#8217; immutability. Well, they forgot about it more than once. \ud83d\ude42<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static string BuildPermissions(IList Permissions, string PermissionKey) {   ....   \/\/ get string   string permissionsString = permissionsBuilder.ToString();    \/\/ ensure leading delimiter   if (!permissionsString.StartsWith(\";\"))   {     permissionsString.Insert(0, \";\");   }    .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3010\/\">V3010<\/a> The return value of function &#8216;Insert&#8217; is required to be utilized. DotNetNuke.Library PermissionController.cs 64<\/p>\n<p>  <\/p>\n<p>If <em>permissionsString<\/em> does not start with &#8216;;&#8217;, the developers want to fix this by adding &#8216;;&#8217; in the beginning. However, <em>Insert<\/em> does not change the source string, it returns the modified one.<\/p>\n<p>  <\/p>\n<p>Another case:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public override void Install() {   ....   skinFile.Replace(Globals.HostMapPath + \"\\\\\", \"[G]\");   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3010\/\">V3010<\/a> The return value of function &#8216;Replace&#8217; is required to be utilized. DotNetNuke.Library SkinInstaller.cs 230<\/p>\n<p>  <\/p>\n<p><strong>Issue 16<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public int Page { get; set; } = 1; public override IConsoleResultModel Run() {   ....   var pageIndex = (this.Page > 0 ? this.Page - 1 : 0);   pageIndex = pageIndex &lt; 0 ? 0 : pageIndex;   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;pageIndex &lt; 0&#8217; is always false. DotNetNuke.Library ListModules.cs 61<\/p>\n<p>  <\/p>\n<p>When the <em>pageIndex &lt; 0<\/em> expression is evaluated, the <em>pageIndex<\/em> value will be always non-negative, since:<\/p>\n<p>  <\/p>\n<ul>\n<li>if <em>this.Page<\/em> is in the [1; <em>int.MaxValue<\/em>] range, <em>pageIndex<\/em> will be in the [0; <em>int.MaxValue \u2014 1<\/em>] range<\/li>\n<li>if <em>this.Page<\/em> is in the [<em>int.MinValue<\/em>; 0] range, <em>pageIndex<\/em> will have the 0 value.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>Therefore, the <em>pageIndex &lt; 0<\/em> check will always be <em>false<\/em>.<\/p>\n<p>  <\/p>\n<p><strong>Issue 17<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private CacheDependency GetTabsCacheDependency(IEnumerable&lt;int> portalIds) {   ....   \/\/ get the portals list dependency   var portalKeys = new List&lt;string>();   if (portalKeys.Count > 0)   {     keys.AddRange(portalKeys);   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;portalKeys.Count > 0&#8217; is always false. DotNetNuke.Library CacheController.cs 968<\/p>\n<p>  <\/p>\n<p>The developers created an empty list and then checked that it is non-empty. Just in case \ud83d\ude42<\/p>\n<p>  <\/p>\n<p><strong>Issue 18<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public JournalEntity(string entityXML) {   ....   XmlDocument xDoc = new XmlDocument { XmlResolver = null };   xDoc.LoadXml(entityXML);   if (xDoc != null)   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;xDoc != null&#8217; is always true. DotNetNuke.Library JournalEntity.cs 30<\/p>\n<p>  <\/p>\n<p>Called the constructor, wrote the reference to a variable. After that, called the <em>LoadXml<\/em> instance method. Then, the developers check the same link for <em>null<\/em> inequality. Just in case. (2)<\/p>\n<p>  <\/p>\n<p><strong>Issue 19<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public enum ActionType {   ....   Redirect302Now = 2,   ....   Redirect302 = 5,   .... } public ActionType Action { get; set; } private static bool CheckForRedirects(....) {   ....   if (   result.Action != ActionType.Redirect302Now        || result.Action != ActionType.Redirect302)   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression is always true. Probably the &#8216;&amp;&amp;&#8217; operator should be used here. DotNetNuke.Library AdvancedUrlRewriter.cs 1695<\/p>\n<p>  <\/p>\n<p>This expression will be false only if the result of both operands is <em>false<\/em>. In this case, the following conditions must be met:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>result.Action == ActionType.Redirect302Now<\/em><\/li>\n<li><em>result.Action == ActionType.Redirect302<\/em><\/li>\n<\/ul>\n<p>  <\/p>\n<p>Since <em>result.Action<\/em> cannot have two different values, the described condition is impossible. Therefore, the expression is always true.<\/p>\n<p>  <\/p>\n<p><strong>Issue 20<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public Route MapRoute(string moduleFolderName,                        string routeName,                        string url,                        object defaults,                        object constraints,                        string[] namespaces) {   if (   namespaces == null        || namespaces.Length == 0        || string.IsNullOrEmpty(namespaces[0]))   {     throw new ArgumentException(Localization.GetExceptionMessage(       \"ArgumentCannotBeNullOrEmpty\",       \"The argument '{0}' cannot be null or empty.\",       \"namespaces\"));   }    Requires.NotNullOrEmpty(\"moduleFolderName\", moduleFolderName);    url = url.Trim('\/', '\\\\');    var prefixCounts = this.portalAliasMvcRouteManager.GetRoutePrefixCounts();   Route route = null;    if (url == null)   {     throw new ArgumentNullException(nameof(url));   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;url == null&#8217; is always false. DotNetNuke.Web.Mvc MvcRoutingManager.cs 66<\/p>\n<p>  <\/p>\n<p>What a curious case we have with the <em>url<\/em> parameter. If <em>url<\/em> is <em>null<\/em>, the developers want to throw <em>ArgumentNullException<\/em>. The exception unambiguously hints that this parameter should be non-null. But before this, for <em>url<\/em>, the developers call an instance method \u2013 <em>Trim<\/em>\u2026 As a result, if <em>url<\/em> is <em>null<\/em>, <em>NullReferenceException<\/em> is thrown.<\/p>\n<p>  <\/p>\n<p><strong>Issue 21<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public Hashtable Settings {   get   {     return this.ModuleContext.Settings;   } } public string UploadRoles {   get   {     ....     if (Convert.ToString(this.Settings[\"uploadroles\"]) != null)     {       this._UploadRoles = Convert.ToString(this.Settings[\"uploadroles\"]);     }     ....   } }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;Convert.ToString(this.Settings[&#171;uploadroles&#187;]) != null&#8217; is always true. DotNetNuke.Website.Deprecated WebUpload.ascx.cs 151<\/p>\n<p>  <\/p>\n<p><em>Convert.ToString<\/em> may return the result of a successful converting or <em>String.Empty<\/em>, but not <em>null<\/em>. Eventually, this check makes no sense.<\/p>\n<p>  <\/p>\n<p>Believed it? This is <a href=\"https:\/\/pvs-studio.com\/en\/blog\/terms\/6461\/\">false positive<\/a>.<\/p>\n<p>  <\/p>\n<p>Let&#8217;s start with the <em>Convert.ToString<\/em> method overloading: <em>Convert.ToString(String value)<\/em>. It returns <em>value<\/em> as is. Thus, if the input is <em>null<\/em>, the outputis also<em> null<\/em>.<\/p>\n<p>  <\/p>\n<p>The above code snippet contains another overloading \u2013 <em>Convert.ToString(Object value)<\/em>. The return value of this method has the following comment:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">\/\/ Returns: \/\/     The string representation of value,  \/\/     or System.String.Empty if value is null.<\/code><\/pre>\n<p>  <\/p>\n<p>You may think that the method will always return some string. However, the string representation of the object may have a <em>null<\/em> value. As a result, the method will return <em>null<\/em>.<\/p>\n<p>  <\/p>\n<p>Here&#8217;s the simplest example:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/6f9\/24d\/b4c\/6f924db4c4bc2e02ccf4985b2b6d7ce4.png\" alt=\"0890_DNN\/image4.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/6f9\/24d\/b4c\/6f924db4c4bc2e02ccf4985b2b6d7ce4.png\"\/><\/p>\n<p>  <\/p>\n<p>By the way, it turns out that:<\/p>\n<p>  <\/p>\n<ul>\n<li>if <em>obj == null<\/em>, <em>stringRepresentation != null<\/em> (an empty string);<\/li>\n<li>if <em>obj != null<\/em>, <em>stringRepresentation == null<\/em>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>Hmm, that&#8217;s a bit tangled&#8230;<\/p>\n<p>  <\/p>\n<p>You could say that this is a synthetic example. Who returns <em>null<\/em> from the <em>ToString<\/em> method? Well, I know that Microsoft had <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/csharp\/0656\/\">a few cases<\/a> (follow the link and take a look at Issue 14).<\/p>\n<p>  <\/p>\n<p>And here&#8217;s the question! Did the code authors know about this peculiarity? Did they take this into account or not? What about you? Did you know about this?<\/p>\n<p>  <\/p>\n<p>By the way, nullable reference types can help here. The method&#8217;s signature indicates that the method may return the <em>null<\/em> value. As a result, possible misunderstanding is gone:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static string? ToString(object? value)<\/code><\/pre>\n<p>  <\/p>\n<p>Now it&#8217;s time for a break. Pour some more coffee and take a few cookies. It&#8217;s coffee break!<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/d29\/2ab\/daa\/d292abdaa1dc75ca2b1df941f6eed2ba.png\" alt=\"0890_DNN\/image5.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/d29\/2ab\/daa\/d292abdaa1dc75ca2b1df941f6eed2ba.png\"\/><\/p>\n<p>  <\/p>\n<p>Grabbed a snack? We&#8217;re proceeding to the next issue.<\/p>\n<p>  <\/p>\n<p><strong>Issues 22, 23<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static ModuleItem ConvertToModuleItem(ModuleInfo module)    => new ModuleItem {   Id = module.ModuleID,   Title = module.ModuleTitle,   FriendlyName = module.DesktopModule.FriendlyName,   EditContentUrl = GetModuleEditContentUrl(module),   EditSettingUrl = GetModuleEditSettingUrl(module),   IsPortable = module.DesktopModule?.IsPortable,   AllTabs = module.AllTabs, };<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3042\/\">V3042<\/a> Possible NullReferenceException. The &#8216;?.&#8217; and &#8216;.&#8217; operators are used for accessing members of the &#8216;module.DesktopModule&#8217; object Dnn.PersonaBar.Extensions Converters.cs 67<\/p>\n<p>  <\/p>\n<p>Take a look at <em>FriendlyName<\/em> and <em>IsPortable<\/em> initialization. The developers use <em>module.DesktopModule.FriendlyName<\/em> and <em>module.DesktopModule?.IsPortable<\/em> as values for initialization. You might ask \u2013 can <em>module.DesktopModule<\/em> be <em>null<\/em>? If it is <em>null<\/em>, <em>?.<\/em> won&#8217;t protect the code because <em>module.DesktopModule.FriendlyName<\/em> does not contain null checking. If it is not <em>null<\/em>, <em>?.<\/em> is redundant and misleading.<\/p>\n<p>  <\/p>\n<p>Here&#8217;s a strikingly similar code fragment.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public IDictionary&lt;string, object> GetSettings(MenuItem menuItem) {   var settings = new Dictionary&lt;string, object>   {     { \"canSeePagesList\",        this.securityService.CanViewPageList(menuItem.MenuId) },      { \"portalName\",        PortalSettings.Current.PortalName },                               { \"currentPagePermissions\",        this.securityService.GetCurrentPagePermissions() },      { \"currentPageName\",        PortalSettings.Current?.ActiveTab?.TabName },                 { \"productSKU\",        DotNetNukeContext.Current.Application.SKU },      { \"isAdmin\",        this.securityService.IsPageAdminUser() },      { \"currentParentHasChildren\",        PortalSettings.Current?.ActiveTab?.HasChildren },      { \"isAdminHostSystemPage\",        this.securityService.IsAdminHostSystemPage() },   };    return settings; }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3042\/\">V3042<\/a> Possible NullReferenceException. The &#8216;?.&#8217; and &#8216;.&#8217; operators are used for accessing members of the &#8216;PortalSettings.Current&#8217; object Dnn.PersonaBar.Extensions PagesMenuController.cs 47<\/p>\n<p>  <\/p>\n<p>The same happens here. When developers initialize the dictionary, they use <em>PortalSettings.Current<\/em> several times. In some cases, they check it for <em>null<\/em>, in other cases, they don&#8217;t:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">var settings = new Dictionary&lt;string, object> {   ....   { \"portalName\",      PortalSettings.Current.PortalName },                            ....   { \"currentPageName\",      PortalSettings.Current?.ActiveTab?.TabName },              ....   { \"currentParentHasChildren\",      PortalSettings.Current?.ActiveTab?.HasChildren },   .... };<\/code><\/pre>\n<p>  <\/p>\n<p><strong>Issues 24, 25, 26<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static void HydrateObject(object hydratedObject, IDataReader dr) {   ....   \/\/ Get the Data Value's type   objDataType = coloumnValue.GetType();   if (coloumnValue == null || coloumnValue == DBNull.Value)   {     \/\/ set property value to Null     objPropertyInfo.SetValue(hydratedObject,                               Null.SetNull(objPropertyInfo),                               null);   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a> The &#8216;coloumnValue&#8217; object was used before it was verified against null. Check lines: 902, 903. DotNetNuke.Library CBO.cs 902<\/p>\n<p>  <\/p>\n<p>The <em>GetType<\/em> method is called for the <em>coloumnValue<\/em> variable. Then, <em>coloumnValue != null<\/em> is checked. This looks strange.<\/p>\n<p>  <\/p>\n<p>Unfortunately, we have another similar case. Here it is:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void DeleteLanguage() {   ....   \/\/ Attempt to get the Locale   Locale language = LocaleController.Instance                                     .GetLocale(tempLanguagePack.LanguageID);   if (tempLanguagePack != null)   {     LanguagePackController.DeleteLanguagePack(tempLanguagePack);   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a> The &#8216;tempLanguagePack&#8217; object was used before it was verified against null. Check lines: 235, 236. DotNetNuke.Library LanguageInstaller.cs 235<\/p>\n<p>  <\/p>\n<p>The same story \u2013 at first, the <em>LanguageId<\/em> property (<em>tempLanguagePack.LanguageID<\/em>) is accessed. On the next line, the <em>tempLanguagePack != null<\/em> is checked.<\/p>\n<p>  <\/p>\n<p>And more&#8230;<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static void AddLanguageHttpAlias(int portalId, Locale locale) {   ....   var portalAliasInfos =    portalAliasses as IList&lt;PortalAliasInfo>                           ?? portalAliasses.ToList();    if (portalAliasses != null &amp;&amp; portalAliasInfos.Any())   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a> The &#8216;portalAliasses&#8217; object was used before it was verified against null. Check lines: 1834, 1835. DotNetNuke.Library Localization.cs 1834<\/p>\n<p>  <\/p>\n<p>That&#8217;s all for this pattern. Although, the analyzer issued similar warnings for other code fragments. Let&#8217;s take a look at another way to refer to members before checking for <em>null<\/em>.<\/p>\n<p>  <\/p>\n<p><strong>Issues 27, 28, 29, 30<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static void WatcherOnChanged(object sender, FileSystemEventArgs e) {   if (Logger.IsInfoEnabled &amp;&amp; !e.FullPath.EndsWith(\".log.resources\"))   {     Logger.Info($\"Watcher Activity: {e.ChangeType}. Path: {e.FullPath}\");   }    if (   _handleShutdowns        &amp;&amp; !_shutdownInprogress        &amp;&amp; (e.FullPath ?? string.Empty)             .StartsWith(_binFolder,                          StringComparison.InvariantCultureIgnoreCase))   {     ShceduleShutdown();   } }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a> The &#8216;e.FullPath&#8217; object was used before it was verified against null. Check lines: 147, 152. DotNetNuke.Web DotNetNukeShutdownOverload.cs 147<\/p>\n<p>  <\/p>\n<p>Notice <em>e.FullPath<\/em>. At first, <em>e.FullPath.EndsWith(&#171;.log.resources&#187;)<\/em> is accessed. Then, the <em>??<\/em> operator is used: <em>e.FullPath ?? string.Empty<\/em>.<\/p>\n<p>  <\/p>\n<p>This code is successfully multiplied via copy-paste:<\/p>\n<p>  <\/p>\n<ul>\n<li>V3095 The &#8216;e.FullPath&#8217; object was used before it was verified against null. Check lines: 160, 165. DotNetNuke.Web DotNetNukeShutdownOverload.cs 160<\/li>\n<li>V3095 The &#8216;e.FullPath&#8217; object was used before it was verified against null. Check lines: 173, 178. DotNetNuke.Web DotNetNukeShutdownOverload.cs 173<\/li>\n<li>V3095 The &#8216;e.FullPath&#8217; object was used before it was verified against null. Check lines: 186, 191. DotNetNuke.Web DotNetNukeShutdownOverload.cs 186<\/li>\n<\/ul>\n<p>  <\/p>\n<p>I think that&#8217;s enough for <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a>. And I guess you don&#8217;t want to read about it anymore. So, let&#8217;s move on.<\/p>\n<p>  <\/p>\n<p><strong>Issue 31<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">internal FolderInfoBuilder() {   this.portalId = Constants.CONTENT_ValidPortalId;   this.folderPath = Constants.FOLDER_ValidFolderRelativePath;   this.physicalPath = Constants.FOLDER_ValidFolderPath;   this.folderMappingID = Constants.FOLDER_ValidFolderMappingID;   this.folderId = Constants.FOLDER_ValidFolderId;   this.physicalPath = string.Empty; }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3008\/\">V3008<\/a> The &#8216;this.physicalPath&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 29, 26. DotNetNuke.Tests.Core FolderInfoBuilder.cs 29<\/p>\n<p>  <\/p>\n<p>The <em>Constants.FOLDER_ValidFolderPath<\/em> value is initially written in the <em>physicalPath<\/em> field. Then, <em>string.Empty<\/em> is assigned to the same field. Note that these values are different. That&#8217;s why this code looks even more suspicious:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public const string FOLDER_ValidFolderPath = \"C:\\\\folder\";<\/code><\/pre>\n<p>  <\/p>\n<p><strong>Issue 32<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public int SeekCountry(int offset, long ipNum, short depth) {   ....   var buffer = new byte[6];   byte y;    ....   if (y &lt; 0)   {     y = Convert.ToByte(y + 256);   }    .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3022\/\">V3022<\/a> Expression &#8216;y &lt; 0&#8217; is always false. Unsigned type value is always >= 0. CountryListBox CountryLookup.cs 210<\/p>\n<p>  <\/p>\n<p><em>byte<\/em> type values are in the [0; 255] range. Hence, the <em>y &lt; 0<\/em> check will always give <em>false<\/em>, and <em>then<\/em> branch will never be executed.<\/p>\n<p>  <\/p>\n<p><strong>Issue 33<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void ParseTemplateInternal(...., string templatePath, ....) {   ....   string path = Path.Combine(templatePath, \"admin.template\");   if (!File.Exists(path))   {     \/\/ if the template is a merged copy of a localized templte the     \/\/ admin.template may be one director up     path = Path.Combine(templatePath, \"..\\admin.template\");   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3057\/\">V3057<\/a> The &#8216;Combine&#8217; function is expected to receive a valid path string. Inspect the second argument. DotNetNuke.Library PortalController.cs 3538<\/p>\n<p>  <\/p>\n<p>Hmm. An interesting error. Here we have two operations to construct a path (the <em>Path.Combine<\/em> call). The first one is clear, but the second one is not. Apparently, in the second case, the developers wanted to take the admin.template file not from the <em>templatePath<\/em> directory, but from the parent one. Unfortunately, after they added ..\\, the path became invalid since an escape sequence was formed: <em>..<strong>\\a<\/strong>dmin.template<\/em>.<\/p>\n<p>  <\/p>\n<p><strong>Issue 34<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">internal override string GetMethodInformation(MethodItem method) {   ....   string param = string.Empty;   string[] names = method.Parameters;   StringBuilder sb = new StringBuilder();   if (names != null &amp;&amp; names.GetUpperBound(0) > 0)   {     for (int i = 0; i &lt;= names.GetUpperBound(0); i++)     {       sb.AppendFormat(\"{0}, \", names[i]);     }   }     if (sb.Length > 0)   {     sb.Remove(sb.Length - 2, 2);     param = sb.ToString();   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3057\/\">V3057<\/a> The &#8216;Remove&#8217; function could receive the &#8216;-1&#8217; value while non-negative value is expected. Inspect the first argument. DotNetNuke.Log4Net StackTraceDetailPatternConverter.cs 67<\/p>\n<p>  <\/p>\n<p>Now, this code runs without any errors, but looking at it, I have a sneaking suspicion that something is wrong. In the then branch of the <em>if<\/em> statement, the value of <em>sb.Length<\/em> is >= 1. When the <em>Remove<\/em> method is called, we subtract 2 from this value. So, if <em>sb.Length == 1<\/em>, the call will be as follows: <em>sb.Remove(-1, 2)<\/em>. This will cause an exception.<\/p>\n<p>  <\/p>\n<p>Right now, this code runs because, in <em>StringBuilder<\/em>, strings are added via the <em>&#171;{0}, &#171;<\/em> format. Therefore, these lines consist of 2 characters. A check like that is ambiguous and causes concerns.<\/p>\n<p>  <\/p>\n<p><strong>Issues 35, 36<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public void SaveJournalItem(JournalItem journalItem, int tabId, int moduleId) {   ....   journalItem.JournalId = this._dataService.Journal_Save(     journalItem.PortalId,     journalItem.UserId,     journalItem.ProfileId,     journalItem.SocialGroupId,     journalItem.JournalId,     journalItem.JournalTypeId,     journalItem.Title,     journalItem.Summary,     journalItem.Body,     journalData,     xml,     journalItem.ObjectKey,     journalItem.AccessKey,     journalItem.SecuritySet,     journalItem.CommentsDisabled,     journalItem.CommentsHidden);   .... } public void UpdateJournalItem(JournalItem journalItem, int tabId, int moduleId) {   ....   journalItem.JournalId = this._dataService.Journal_Update(     journalItem.PortalId,     journalItem.UserId,     journalItem.ProfileId,     journalItem.SocialGroupId,     journalItem.JournalId,     journalItem.JournalTypeId,     journalItem.Title,     journalItem.Summary,     journalItem.Body,     journalData,     xml,     journalItem.ObjectKey,     journalItem.AccessKey,     journalItem.SecuritySet,     journalItem.CommentsDisabled,     journalItem.CommentsHidden);   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>Here we have 2 issues. Looks as if they are multiplied by copy-paste. Try to find them! The answer is behind this picture.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/c10\/544\/407\/c10544407f66df700ae9c8816cd32a63.png\" alt=\"0890_DNN\/image6.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/c10\/544\/407\/c10544407f66df700ae9c8816cd32a63.png\"\/><\/p>\n<p>  <\/p>\n<p>Whoops, my bad! I forgot to give you a clue\u2026 Here you are:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">int Journal_Update(int portalId,                     int currentUserId,                     int profileId,                     int groupId,                     int journalId,                     int journalTypeId,                     string title,                     string summary,                    string body,                     string itemData,                     string xml,                     string objectKey,                     Guid accessKey,                     string securitySet,                     bool commentsHidden,                     bool commentsDisabled);<\/code><\/pre>\n<p>  <\/p>\n<p>Hope it&#8217;s clear now. Found a problem? If not (or you don&#8217;t want to do that), take a look at the analyzer warnings:<\/p>\n<p>  <\/p>\n<ul>\n<li>V3066 Possible incorrect order of arguments passed to &#8216;Journal_Save&#8217; method: &#8216;journalItem.CommentsDisabled&#8217; and &#8216;journalItem.CommentsHidden&#8217;. DotNetNuke.Library JournalControllerImpl.cs 125<\/li>\n<li>V3066 Possible incorrect order of arguments passed to &#8216;Journal_Update&#8217; method: &#8216;journalItem.CommentsDisabled&#8217; and &#8216;journalItem.CommentsHidden&#8217;. DotNetNuke.Library JournalControllerImpl.cs 253<\/li>\n<\/ul>\n<p>  <\/p>\n<p>Notice the last parameters and arguments. In both calls, <em>journalItem.CommentsDisabled<\/em> comes before <em>journalItem.CommentsHidden<\/em>. However, the <em>commentsHidden<\/em> parameter comes before <em>commentsDisabled<\/em>. Yeah, that&#8217;s suspicious.<\/p>\n<p>  <\/p>\n<p><strong>Issue 37<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static DateTime LastPurge {   get   {     var lastPurge = DateTime.Now;     if (File.Exists(CachePath + \"_lastpurge\"))     {       var fi = new FileInfo(CachePath + \"_lastpurge\");       lastPurge = fi.LastWriteTime;     }     else     {       File.WriteAllText(CachePath + \"_lastpurge\", string.Empty);     }      return lastPurge;   }    set   {     File.WriteAllText(CachePath + \"_lastpurge\", string.Empty);   } }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3077\/\">V3077<\/a> The setter of &#8216;LastPurge&#8217; property does not utilize its &#8216;value&#8217; parameter. DotNetNuke.Library IPCount.cs 96<\/p>\n<p>  <\/p>\n<p>The fact that <em>set<\/em>-accessor does not use the <em>value<\/em> parameter is suspicious. So, it&#8217;s possible to write something to this property, but the assigned value is\u2026 ignored. I found one place in the code, where the following property is assigned:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static bool CheckIp(string ipAddress) {   ....   LastPurge = DateTime.Now;   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>As a result, in this case, <em>DateTime.Now<\/em> will not be stored anywhere.<\/p>\n<p>  <\/p>\n<p><strong>Issue 38<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void DisplayNewRows() {   this.divTabName.Visible = this.optMode.SelectedIndex == 0;   this.divParentTab.Visible = this.optMode.SelectedIndex == 0;   this.divInsertPositionRow.Visible = this.optMode.SelectedIndex == 0;   this.divInsertPositionRow.Visible = this.optMode.SelectedIndex == 0; }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3008\/\">V3008<\/a> The &#8216;this.divInsertPositionRow.Visible&#8217; variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 349, 348. DotNetNuke.Website Import.ascx.cs 349<\/p>\n<p>  <\/p>\n<p>Again, the variable is assigned twice \u2013 the whole expression is duplicated. Perhaps it&#8217;s redundant. But maybe developers copied the expression and forgot to change it. Hmm\u2026 <a href=\"https:\/\/pvs-studio.com\/en\/blog\/posts\/cpp\/0260\/\">The last line effect<\/a>?<\/p>\n<p>  <\/p>\n<p><strong>Issue 39<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public enum AddressType {   IPv4 = 0,   IPv6 = 1, }  private static void FilterRequest(object sender, EventArgs e) {   ....     switch (varArray[1])   {     case \"IPv4\":       varVal = NetworkUtils.GetAddress(varVal, AddressType.IPv4);       break;     case \"IPv6\":       varVal = NetworkUtils.GetAddress(varVal, AddressType.IPv4);       break;   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3139\/\">V3139<\/a> Two or more case-branches perform the same actions. DotNetNuke.HttpModules RequestFilterModule.cs 81<\/p>\n<p>  <\/p>\n<p>I guess these <em>case<\/em> branches should not be identical. In the second case, <em>AddressType.IPv6<\/em> should be used.<\/p>\n<p>  <\/p>\n<p><strong>Issue 40<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static DateTime CalculateTime(int lapse, string measurement) {   var nextTime = new DateTime();   switch (measurement)   {     case \"s\":       nextTime = DateTime.Now.AddSeconds(lapse);       break;     case \"m\":       nextTime = DateTime.Now.AddMinutes(lapse);       break;     case \"h\":       nextTime = DateTime.Now.AddHours(lapse);       break;     case \"d\":       nextTime = DateTime.Now.AddDays(lapse);       break;     case \"w\":       nextTime = DateTime.Now.AddDays(lapse);       break;     case \"mo\":       nextTime = DateTime.Now.AddMonths(lapse);       break;     case \"y\":       nextTime = DateTime.Now.AddYears(lapse);       break;   }   return nextTime; }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3139\/\">V3139<\/a> Two or more case-branches perform the same actions. DotNetNuke.Tests.Core PropertyAccessTests.cs 118<\/p>\n<p>  <\/p>\n<p>Pay attention to <em>&#171;d&#187;<\/em> and <em>&#171;w&#187; <\/em>\u2013 the bodies of the <em>case<\/em> branches. They duplicate each other. Copy-paste\u2026 Copy-paste never changes. The <em>DateTime<\/em> type doesn&#8217;t contain the <em>AddWeeks<\/em> method, however, the <em>case<\/em> branch &#171;w&#187; obviously must work with weeks.<\/p>\n<p>  <\/p>\n<p><strong>Issue 41<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private static int AddTabToTabDict(....) {   ....   if (customAliasUsedAndNotCurrent &amp;&amp; settings.RedirectUnfriendly)   {     \/\/ add in the standard page, but it's a redirect to the customAlias     rewritePath = RedirectTokens.AddRedirectReasonToRewritePath(                     rewritePath,                     ActionType.Redirect301,                     RedirectReason.Custom_Tab_Alias);     AddToTabDict(tabIndex,                  dupCheck,                  httpAlias,                  tabPath,                  rewritePath,                  tab.TabID,                  UrlEnums.TabKeyPreference.TabRedirected,                  ref tabPathDepth,                  settings.CheckForDuplicateUrls,                  isDeleted);   }   else   {     if (customAliasUsedAndNotCurrent &amp;&amp; settings.RedirectUnfriendly)     {       \/\/ add in the standard page, but it's a redirect to the customAlias       rewritePath = RedirectTokens.AddRedirectReasonToRewritePath(                       rewritePath,                       ActionType.Redirect301,                       RedirectReason.Custom_Tab_Alias);       AddToTabDict(tabIndex,                    dupCheck,                    httpAlias,                    tabPath,                    rewritePath,                    tab.TabID,                    UrlEnums.TabKeyPreference.TabRedirected,                    ref tabPathDepth,                    settings.CheckForDuplicateUrls,                    isDeleted);     }     else       ....   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3030\/\">V3030<\/a> Recurring check. The &#8216;customAliasUsedAndNotCurrent &amp;&amp; settings.RedirectUnfriendly&#8217; condition was already verified in line 1095. DotNetNuke.Library TabIndexController.cs 1097<\/p>\n<p>  <\/p>\n<p>The analyzer detects the following pattern:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">if (a &amp;&amp; b)   .... else {   if (a &amp;&amp; b)     .... }<\/code><\/pre>\n<p>  <\/p>\n<p>In this code fragment, the second condition will be false \u2013 the variables have not changed between calls.<\/p>\n<p>  <\/p>\n<p>However, here we hit the big jackpot! Besides the conditions, the blocks of code are duplicated. <em>if<\/em> with its <em>then<\/em> branch was entirely copied.<\/p>\n<p>  <\/p>\n<p><strong>Issue 42<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private IEnumerable&lt;TabDto> GetDescendantsForTabs(   IEnumerable&lt;int> tabIds,    IEnumerable&lt;TabDto> tabs,   int selectedTabId,   int portalId,    string cultureCode,    bool isMultiLanguage) {   var enumerable = tabIds as int[] ?? tabIds.ToArray();   if (tabs == null || tabIds == null || !enumerable.Any())   {     return tabs;   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3095\/\">V3095<\/a> The &#8216;tabIds&#8217; object was used before it was verified against null. Check lines: 356, 357. Dnn.PersonaBar.Library TabsController.cs 356<\/p>\n<p>  <\/p>\n<p>We&#8217;ve discussed a similar case before, but I decided to do this again and analyze it in more detail.<\/p>\n<p>  <\/p>\n<p>The <em>tabIds<\/em> parameter is expected to have a <em>null<\/em> value. Otherwise, why do we check <em>tabIds == null<\/em>? But something is messed up here again&#8230;<\/p>\n<p>  <\/p>\n<p>Suppose <em>tabIds<\/em> is <em>null<\/em>, then:<\/p>\n<p>  <\/p>\n<ul>\n<li>the left operand of the ?? operator is evaluated (<em>tabIds as int[]<\/em>);<\/li>\n<li><em>tabIds as int[]<\/em> results in <em>null<\/em>;<\/li>\n<li>the right operand of the ?? operator is evaluated (<em>tabIds.ToArray()<\/em>);<\/li>\n<li>the <em>ToArray<\/em> method call leads to an exception because <em>tabIds<\/em> is <em>null<\/em>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>Turns out that the check failed.<\/p>\n<p>  <\/p>\n<p><strong>Issue 43<\/strong><\/p>\n<p>  <\/p>\n<p>And now take a chance to find an error yourself! I simplified the task for you. Below is a shortened method, I cut almost everything unnecessary. The original method contained 500 lines \u2013 doubt that you would find the error. Although, if you want, take a look at it \u2013 here&#8217;s <a href=\"https:\/\/github.com\/dnnsoftware\/Dnn.Platform\/blob\/05544c719981842c341ec40583be2e149aeb64a9\/DNN%20Platform\/Providers\/HtmlEditorProviders\/DNNConnect.CKE\/CKEditorOptions.ascx.cs\">a link on GitHub<\/a>.<\/p>\n<p>  <\/p>\n<p>If you figure out what&#8217;s wrong, you&#8217;ll definitely get endorphins rush. \ud83d\ude42<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void SaveModuleSettings() {   ....   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.SKIN}\",      this.ddlSkin.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.CODEMIRRORTHEME}\",      this.CodeMirrorTheme.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.BROWSER}\",      this.ddlBrowser.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.IMAGEBUTTON}\",      this.ddlImageButton.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.FILELISTVIEWMODE}\",      this.FileListViewMode.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.DEFAULTLINKMODE}\",       this.DefaultLinkMode.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.USEANCHORSELECTOR}\",      this.UseAnchorSelector.Checked.ToString());   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.SHOWPAGELINKSTABFIRST}\",      this.ShowPageLinksTabFirst.Checked.ToString());   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.OVERRIDEFILEONUPLOAD}\",      this.OverrideFileOnUpload.Checked.ToString());   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.SUBDIRS}\",      this.cbBrowserDirs.Checked.ToString());   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.BROWSERROOTDIRID}\",      this.BrowserRootDir.SelectedValue);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.UPLOADDIRID}\",      this.UploadDir.SelectedValue);    if (Utility.IsNumeric(this.FileListPageSize.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.FILELISTPAGESIZE}\",        this.FileListPageSize.Text);   }    if (Utility.IsNumeric(this.txtResizeWidth.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.RESIZEWIDTH}\",        this.txtResizeWidth.Text);   }    if (Utility.IsNumeric(this.txtResizeHeight.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.RESIZEHEIGHT}\",        this.txtResizeHeight.Text);   }    moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.INJECTJS}\",      this.InjectSyntaxJs.Checked.ToString());    if (Utility.IsUnit(this.txtWidth.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.WIDTH}\",        this.txtWidth.Text);   }    if (Utility.IsUnit(this.txtHeight.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.HEIGHT}\",        this.txtWidth.Text);   }    moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.BLANKTEXT}\",      this.txtBlanktext.Text);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.CSS}\",      this.CssUrl.Url);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.TEMPLATEFILES}\",      this.TemplUrl.Url);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.CUSTOMJSFILE}\",      this.CustomJsFile.Url);   moduleController.UpdateModuleSetting(this.ModuleId,      $\"{key}{SettingConstants.CONFIG}\",      this.ConfigUrl.Url);   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>Here&#8217;s a picture to hide the answer. You&#8217;ll find it right behind the unicorn.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/6bc\/0ae\/3da\/6bc0ae3dacd5c442ddbd6e45bccad356.png\" alt=\"0890_DNN\/image7.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/6bc\/0ae\/3da\/6bc0ae3dacd5c442ddbd6e45bccad356.png\"\/><\/p>\n<p>  <\/p>\n<p>Now, it&#8217;s time to check yourself! <\/p>\n<p>  <\/p>\n<p>The PVS-Studio warning: <a href=\"https:\/\/pvs-studio.com\/en\/w\/v3127\/\">V3127<\/a> Two similar code fragments were found. Perhaps, this is a typo and &#8216;txtHeight&#8217; variable should be used instead of &#8216;txtWidth&#8217; DNNConnect.CKEditorProvider CKEditorOptions.ascx.cs 2477<\/p>\n<p>  <\/p>\n<p>Wow, the analyzer is very attentive! Here&#8217;s the shortened code.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">private void SaveModuleSettings() {   ....   if (Utility.IsUnit(this.txtWidth.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.WIDTH}\",        this.txtWidth.Text);               \/\/ &lt;=   }    if (Utility.IsUnit(this.txtHeight.Text))   {     moduleController.UpdateModuleSetting(this.ModuleId,        $\"{key}{SettingConstants.HEIGHT}\",        this.txtWidth.Text);               \/\/ &lt;=   }   .... }<\/code><\/pre>\n<p>  <\/p>\n<p>Note that in the second case, we process &#8216;height&#8217; variables, not &#8216;width&#8217;. However, when we call the <em>UpdateModuleSetting<\/em> method, <em>this.txtWidth.Text<\/em> is passed instead of <em>this.txtHeight.Text<\/em>.<\/p>\n<p>  <\/p>\n<p><strong>Issue N<\/strong><\/p>\n<p>  <\/p>\n<p>Of course, these are not all warnings the analyzer found. I tried to select the most interesting and concise. The analyzer also issued interprocedural warnings and lots of others similar to those that we discussed. I guess the project developers are interested in warnings more than the readers.<\/p>\n<p>  <\/p>\n<p>Also, the analyzer issued false positives. We discussed some of them. I guess the analyzer developers are interested in other false positives more than the readers. So, I didn&#8217;t write about them all.<\/p>\n<p>  <\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>  <\/p>\n<p>In my opinion, the issues are diverse. You may say: &#171;I would never make such errors!&#187; But humans tend to make mistakes \u2013 this is totally normal! There are lots of reasons for this. That&#8217;s why we regularly find <a href=\"https:\/\/pvs-studio.com\/en\/blog\/inspections\/\">new errors<\/a>.<\/p>\n<p>  <\/p>\n<p>We also make mistakes. And sometimes false positives happen \u2013 we admit those issues and fix them. \ud83d\ude42<\/p>\n<p>  <\/p>\n<p>As for code quality, is it enough to have a team of experts? I don&#8217;t think so. You have to adopt a complex approach and use various tools\/techniques to control code and product quality.<\/p>\n<p>  <\/p>\n<p>Let&#8217;s sum it up:<\/p>\n<p>  <\/p>\n<ul>\n<li>be careful with copy-paste;<\/li>\n<li><a href=\"https:\/\/pvs-studio.com\/en\/\">use static analysis<\/a>;<\/li>\n<li>follow <a href=\"https:\/\/twitter.com\/_SergVasiliev_\">me on Twitter<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><strong>P.S.<\/strong> By the way, what&#8217;s your Top 10 warnings from this article? \ud83d\ude09<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/591165\/\"> https:\/\/habr.com\/ru\/articles\/591165\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/e12\/351\/790\/e12351790900ad3143e2529b47446743.png\" alt=\"0890_DNN\/image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e12\/351\/790\/e12351790900ad3143e2529b47446743.png\"\/><\/p>\n<p>  <\/p>\n<p>Today, we discuss C# code quality and a variety of errors by the example of CMS DotNetNuke. We&#8217;re going to dig into its source code. You&#8217;re going to need a cup of coffee&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-393855","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/393855","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=393855"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/393855\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=393855"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=393855"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=393855"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}