{"id":31902,"date":"2023-03-03T16:00:07","date_gmt":"2023-03-03T16:00:07","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=31902"},"modified":"2023-03-03T09:05:26","modified_gmt":"2023-03-03T09:05:26","slug":"code-analysis-improvements-in-visual-studio-17-6","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/code-analysis-improvements-in-visual-studio-17-6\/","title":{"rendered":"Code Analysis Improvements in Visual Studio 17.6"},"content":{"rendered":"<p>The C++ team is committed to making your C++ coding experience as safe as possible. We are adding richer code safety checks and addressing high impact customer feedback bugs posted on the <a href=\"https:\/\/developercommunity.visualstudio.com\/cpp\">C++ Developer Community<\/a>\u202fpage. Thank you for engaging with us and giving us great feedback on the past releases and early previews leading to this point. Below is the detailed overview of the improvements we made to our code analysis tools.<\/p>\n<h2>Improvements to existing checks<\/h2>\n<p>We improved many checks to find more errors and emit fewer false positives. This section contains some highlights of the work we did over the past months.<\/p>\n<h3>Unwrapping empty std::optionals<\/h3>\n<p>The initial version of <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26830\">C26830<\/a>, which checks for the safe unwrapping of <code>std::optional<\/code>, did not support the <code>operator==<\/code> free function and reported a false C26830 for the code below:<\/p>\n<pre><code class=\"language-cpp\">int f(std::optional&lt;int&gt; o) {\r\n  if (o == std::nullopt)\r\n      return 42;\r\n  \/\/ Previously, C26830 was emitted below.\r\n  return *o;\r\n}<\/code><\/pre>\n<p>After our improvements the analyzer no longer warns on the code above. This addition can also help finding more problems when a condition is accidentally inverted:<\/p>\n<pre><code class=\"language-cpp\">int f(std::optional&lt;int&gt; o) {\r\n  if (o != std::nullopt)\r\n    return 42;\r\n  return *o; \/\/ C26829 emitted.\r\n}<\/code><\/pre>\n<p>We relaxed <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26829\">C26829<\/a> and <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26830\">C26830<\/a> to not warn when the <code>value<\/code> method is invoked on a potentially empty <code>std::optional<\/code>. Calling <code>value<\/code> on an empty optional will raise an exception, which some users prefer to catch instead of checking for emptiness upfront. When this exception is unacceptable, we introduced <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26859\">C26859<\/a> and <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26860\">C26860<\/a>, which forces an explicit null-check, guaranteeing that no exception is thrown. This was a request from this <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/MSVC-emits-incorrect-C26829-warning-in-v\/10205240\">DevCom ticket<\/a>.<\/p>\n<h3>Support conditional moves<\/h3>\n<p>Some APIs in the STL will consume an argument in some cases but leave it unchanged in others. Previously, the use <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26800\">use after move check<\/a> assumed that these select APIs will <em>always<\/em> consume the argument. We improved the check to better understand some commonly used APIs in the STL and avoid emitting false positives. For example, the following code snippet will no longer trigger any warnings:<\/p>\n<pre><code class=\"language-cpp\">int f() {\r\n  std::map&lt;int, MyType&gt; myMap;\r\n  MyType val;\r\n  auto emplaceResult = myMap.try_emplace(1, std::move(val));\r\n  if (!emplaceResult.second) { \/\/ val was not inserted into the map\r\n    val.method(); \/\/ Previously, C26800 was emitted.\r\n  }\r\n}<\/code><\/pre>\n<p>In this code snippet, when the second element of the returned pair is false, <code>val<\/code> was not consumed by <code>try_emplace<\/code>. In that scenario, it is safe to use <code>val<\/code>. This problem was reported in a <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/False-positive-on-code-analysis:-Warning\/10117317\">DevCom ticket<\/a>.<\/p>\n<h3>Other improvements<\/h3>\n<p>We also made many smaller improvements to other existing checks including:<\/p>\n<ul>\n<li>Improvements to the lifetime analysis<\/li>\n<li>Fixed false positives in <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26440\">C26440<\/a><\/li>\n<li>Fixed some missed warnings in <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26481\">C26481<\/a><\/li>\n<li>Fixed some false positives in <a href=\"https:\/\/aka.ms\/cpp\/warnings\/C26813\">C26813<\/a> <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/analyze-false-positive-C26813-warning-f\/10150977\">reported on DevCom<\/a><\/li>\n<\/ul>\n<h2>Improvements to the code analysis engine<\/h2>\n<h3>Better modeling for std::pair and std::swap<\/h3>\n<p>Our engine analyzes every function in isolation. Consequently, the analyzer does not always have the necessary information about other functions in order to deduce certain facts. Doing function-local analysis was a deliberate design decision to ensure good performance and scalability in our checks. To mitigate the loss of precision, we often add explicit modeling to widely used constructs like <code>pair<\/code>, rely on type information like <code>gsl::not_null<\/code>, or annotations like SAL. Consider the following code:<\/p>\n<pre><code class=\"language-cpp\">void f(std::optional&lt;int&gt; opt) {\r\n  auto p = std::make_pair(opt, opt.has_value());\r\n  if (!p.second)\r\n    *p.first = 42; \/\/ dereferencing an empty optional! C26829 emitted.\r\n}<\/code><\/pre>\n<p>Since the analyzer does not look into the definition of <code>std::make_pair<\/code>, it previously did not understand that this function will store its second argument into the <code>second<\/code> field of the returned object. As a result, a high-confidence warning was never emitted when <code>p<\/code> is dereferenced. As of 17.6, we have added explicit modeling of <code>std::pair<\/code> and its related methods, so that the analyzer will be able catch more bugs such as in the example above, and emit fewer false positives, all while maintaining local static analysis.<\/p>\n<p>The <code>std::swap<\/code> function received similar treatment. We will correctly diagnose the problem in the code snippet below:<\/p>\n<pre><code class=\"language-cpp\">void f() {\r\n  std::optional&lt;int&gt; opt{2};\r\n  std::optional&lt;int&gt; opt2{};\r\n  std::swap(opt, opt2);\r\n  *opt = 42;  \/\/ C26829 emitted.\r\n}<\/code><\/pre>\n<h3>Better support for suppression attributes<\/h3>\n<p>Previously <code>[[gsl::suppress]]<\/code> did not work on declarations. This is now fixed so the following code works as expected:<\/p>\n<pre><code class=\"language-cpp\">void f(std::optional&lt;int&gt; o) {\r\n  if (o)\r\n    return;\r\n  [[gsl::suppress(26829)]]\r\n  int v = *o; \/\/ No longer raise C26829 for unwrapping the empty optional\r\n}<\/code><\/pre>\n<h3>Other fixes<\/h3>\n<p>We worked on many other fixes, including:<\/p>\n<ul>\n<li>Better support for <code>if constexpr<\/code><\/li>\n<li>Fixed a problem with modeling while loops reported in <a href=\"https:\/\/developercommunity.visualstudio.com\/t\/False-positive-on-code-analysis:-Warning\/10116339\">this DevCom ticket<\/a><\/li>\n<li>More precise modeling for temporary objects<\/li>\n<li>The engine now understand that the standard throwing operator new will not return null pointers<\/li>\n<li>Better modeling for initializer expressions<\/li>\n<li>Made the source locations of some warnings more precise<\/li>\n<\/ul>\n<h2>Conclusion<\/h2>\n<p>Visual Studio 2022 17.6 features many improvements to our code analysis tools. Give it a try and let us know what you think.\nThe work that we do is heavily influenced by feedback we receive on the\u202f<a href=\"https:\/\/developercommunity.visualstudio.com\/search?space=62\">Developer Community<\/a>\u202fso thank you again for your participation. Please continue to file feedback and let us know if there is a checker or rule that you would like to see added to C++ Core Check. Stay tuned for more C++ static analysis blogs. In the meanwhile, do not hesitate to reach out to us. We can be reached via the comments below or\u202f<a href=\"https:\/\/twitter.com\/visualc\">@VisualC<\/a>\u202fon Twitter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Code Analysis Improvements in VS 17.6<\/p>\n","protected":false},"author":58008,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,239],"tags":[],"class_list":["post-31902","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus","category-diagnostics"],"acf":[],"blog_post_summary":"<p>Code Analysis Improvements in VS 17.6<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/31902","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/58008"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=31902"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/31902\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=31902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=31902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=31902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}