{"id":28162,"date":"2021-06-30T16:17:45","date_gmt":"2021-06-30T16:17:45","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=28162"},"modified":"2021-06-30T16:17:45","modified_gmt":"2021-06-30T16:17:45","slug":"customized-warning-levels-and-code-analysis-for-external-headers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/customized-warning-levels-and-code-analysis-for-external-headers\/","title":{"rendered":"Customized Warning Levels and Code Analysis for External Headers"},"content":{"rendered":"<p>If you have tried to keep your code clean by selecting strict compiler warning levels or code analysis rulesets, you likely know how frustrating it can be to see these warnings for headers that are not part of your project. To alleviate this, we\u2019ve made it easy to mark headers as external to your project in the latest <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">preview Visual Studio 2019<\/a>. This is something we have been working on for a while with help and feedback from the community. Some of you may remember our previous post, <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/broken-warnings-theory\/\">Broken Warnings Theory<\/a>, when we added experimental external header support to the Microsoft C++ Compiler. I\u2019m happy to announce that, thanks to this feedback, external headers are now officially supported by the compiler, code analysis, and integrated into the IDE.<\/p>\n<p>These external headers can have their own compiler warning level, code analysis, and template diagnostics settings. This leaves you free to choose stricter settings for your project\u2019s code to enforce code quality without getting bogged down with warnings from headers that are beyond your control.<\/p>\n<h2>Adding External Headers to Your Projects<\/h2>\n<p>You can find a new \u201cExternal Include Directories\u201d property for your projects under \u201cVC++ Directories\u201d which can be used to designate any include directory as containing external headers. This external include directory will be added to the include search path as normal, but every header that in that directory or a subdirectory of it will be treated as external. From a compilation standpoint, you won\u2019t notice any differences, but you can choose a different set of warning levels and other analysis settings for headers in these directories.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/VCpp-Directories-External-Includes-Annotated.png\"><img decoding=\"async\" class=\"size-full wp-image-28164 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/VCpp-Directories-External-Includes-Annotated.png\" alt=\"Specify \u201cExternal Include Directories\u201d in the project properties \u201cVC++ Directories\u201d tab.\" width=\"786\" height=\"544\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/VCpp-Directories-External-Includes-Annotated.png 786w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/VCpp-Directories-External-Includes-Annotated-300x208.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/VCpp-Directories-External-Includes-Annotated-768x532.png 768w\" sizes=\"(max-width: 786px) 100vw, 786px\" \/><\/a><\/p>\n<p>By default, all headers from the toolset and the Windows SDK are included as external headers. However, you can add any other include directories (such as 3<sup>rd<\/sup> party libraries) to this new property, separated by a semicolon as well.<\/p>\n<p>Keep in mind that this new property will be ignored by earlier versions of the toolset. If you want to ensure that the project builds properly with earlier versions, you will need to make sure that any \u201cExternal Include Directories\u201d are also listed in the \u201cInclude Directories\u201d property or they will not be found by the compiler. In Visual Studio 2019, we will continue to also include the toolset and Windows SDK headers in the existing \u201cInclude Directories\u201d property for backwards compatibility, but in the next major release of Visual Studio this will be removed.<\/p>\n<h2>Customizing Warning Levels External Headers<\/h2>\n<p>You can customize the way external headers are treated in the project properties \u201cC\/C++ &gt; External Includes\u201d tab.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/Cpp-Settings-External-Inlcudes.png\"><img decoding=\"async\" class=\"size-full wp-image-28165 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/Cpp-Settings-External-Inlcudes.png\" alt=\"Set the warning level, code analysis, and other settings for external header in the project properties \u201cC\/C++ &gt; External Includes\u201d tab.\" width=\"786\" height=\"544\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/Cpp-Settings-External-Inlcudes.png 786w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/Cpp-Settings-External-Inlcudes-300x208.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/Cpp-Settings-External-Inlcudes-768x532.png 768w\" sizes=\"(max-width: 786px) 100vw, 786px\" \/><\/a><\/p>\n<h2>Customizing Code Analysis Settings for External Headers<\/h2>\n<p>Being able to mark certain headers as external to the project will make Code Analysis much easier to use. The examples below show some of the ways you can leverage this new feature to get the most out of Code Analysis.<\/p>\n<h3>Migration from undocumented CAExcludePath to \/external:* and \/analyze:external* options<\/h3>\n<p>To support one of the most common requirements of suppressing code analysis warnings for defects in library headers over which developers have no control, we created a temporary solution to use a special environment variable (\u201cCAExcludePath\u201d), that can be used to specify directories for which code analysis will not report any warnings.<\/p>\n<p>We now have a better solution to control code analysis behavior for external files. While we decided to leave \u201cCAExcludePath\u201d option as is, we strongly recommend to switch to the \/external:* and \/analyze:external* options. With these options, code analysis of external headers can be turned off, or use a separate ruleset from the rest of the codebase. These come with even better usability and maintainability as they are all available through the VS IDE.<\/p>\n<h3>Using \/analyze:external- with \/external:*<\/h3>\n<p>Consider the following header and source files, with no meaningful functionality but intentionally injected bugs:<\/p>\n<p><strong>Header File (externallib.h)<\/strong><\/p>\n<pre class=\"prettyprint\">#pragma once\r\n \r\n#include &lt;Windows.h&gt;\r\n \r\n#pragma warning (disable:26440 26497)\r\nnamespace ExternalLib\r\n{\r\n#pragma warning(disable:4700)\r\n    int GetValue()\r\n    {\r\n        int arr[2];\r\n        return arr[2];\r\n    }\r\n \r\n    template &lt;typename T&gt;\r\n    T GetValue(T, _In_range_(0, sizeof(T) - 1) int)\r\n    {\r\n        T arr[4];\r\n        return arr[sizeof(T)];\r\n    };\r\n}<\/pre>\n<p><strong>Source File (MyApp1.cpp)<\/strong><\/p>\n<pre class=\"prettyprint\">#include &lt;externallib.h&gt;\r\n \r\nusing namespace ExternalLib;\r\n \r\nvoid foo()\r\n{\r\n    auto sum = GetValue(3ll, 4);\r\n    sum += GetValue(3, 3);\r\n    sum += GetValue(L'a', 2);\r\n    sum += GetValue('a', 1);\r\n}<\/pre>\n<p>When analyzed with default options we get code analysis warnings for functions from both the header file and source file:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/1-Errors-without-External.png\"><img decoding=\"async\" class=\"size-full wp-image-28167 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/1-Errors-without-External.png\" alt=\"Errors without \/External\" width=\"1081\" height=\"369\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/1-Errors-without-External.png 1081w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/1-Errors-without-External-300x102.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/1-Errors-without-External-1024x350.png 1024w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/1-Errors-without-External-768x262.png 768w\" sizes=\"(max-width: 1081px) 100vw, 1081px\" \/><\/a><\/p>\n<p>Now, if we add the directory for the externallib.h to the \u201cExternal Include Directories\u201d as follows:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/2-Add-Include-to-External.png\"><img decoding=\"async\" class=\"size-full wp-image-28168 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/2-Add-Include-to-External.png\" alt=\"Add Include to External\" width=\"750\" height=\"519\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/2-Add-Include-to-External.png 750w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/2-Add-Include-to-External-300x208.png 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/a><\/p>\n<p>And then set the \u201cDisable Code Analysis for External Headers\u201d to \u201cYes (\/analyze:external-)\u201d as follows:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/3-Disable-Code-Analysis-for-External.png\"><img decoding=\"async\" class=\"size-full wp-image-28169 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/3-Disable-Code-Analysis-for-External.png\" alt=\"Disable Code Analysis for External\" width=\"750\" height=\"522\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/3-Disable-Code-Analysis-for-External.png 750w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/3-Disable-Code-Analysis-for-External-300x209.png 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/a><\/p>\n<p>Executing \u201cRun Code Analysis\u201d will no longer report any Code Analysis warnings from the external header file:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/4-Internal-Errors-Only.png\"><img decoding=\"async\" class=\"size-full wp-image-28170 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/4-Internal-Errors-Only.png\" alt=\"Errors from Source File Only\" width=\"1100\" height=\"144\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/4-Internal-Errors-Only.png 1100w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/4-Internal-Errors-Only-300x39.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/4-Internal-Errors-Only-1024x134.png 1024w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/4-Internal-Errors-Only-768x101.png 768w\" sizes=\"(max-width: 1100px) 100vw, 1100px\" \/><\/a><\/p>\n<p>Some templates may have bugs depending on the template arguments. If you want to analyze templates even if they are in the external files, you can set the \u201cTemplate Diagnostics in External Headers\u201d option to \u201cYes (\/external:templates-)\u201d. Now, executing \u201cRun Code Analysis\u201d will report Code Analysis warnings for the template functions even if they are in the external header file:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/5-Template-Errors.png\"><img decoding=\"async\" class=\"size-full wp-image-28171 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/5-Template-Errors.png\" alt=\"Errors from External Templates\" width=\"1103\" height=\"234\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/5-Template-Errors.png 1103w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/5-Template-Errors-300x64.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/5-Template-Errors-1024x217.png 1024w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/5-Template-Errors-768x163.png 768w\" sizes=\"(max-width: 1103px) 100vw, 1103px\" \/><\/a><\/p>\n<h3>Using \/analyze:external:ruleset with \/external:*<\/h3>\n<p>Instead of turning off code analysis for external files, it is now possible to analyze external files with a different ruleset from the rest of the codebase by specifying a different ruleset file with the \u201cAnalysis Ruleset for External Headers\u201d option.<\/p>\n<p>For this example, I have created a custom ruleset \u201cExternalHeaderRules\u201d that enables only two rules, C6021 and C6385, as warnings. Then I selected it for the \u201cAnalysis Ruleset for External Headers\u201d option:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/6-Custom-Ruleset.png\"><img decoding=\"async\" class=\"size-full wp-image-28172 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/6-Custom-Ruleset.png\" alt=\"Custom Ruleset for External Headers\" width=\"750\" height=\"522\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/6-Custom-Ruleset.png 750w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/6-Custom-Ruleset-300x209.png 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/a><\/p>\n<p>Please note that the \u201cDisable Code Analysis for External Headers\u201d option is set to \u201cNo\u201d, enabling code analysis on the external headers. With this change, code analysis will now analyze functions from external files using the custom \u201cExternalHeaderRules\u201d ruleset, and report following warnings:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/7-Custom-Ruleset-Errors.png\"><img decoding=\"async\" class=\"size-full wp-image-28173 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/7-Custom-Ruleset-Errors.png\" alt=\"Errors from Custom Ruleset\" width=\"1097\" height=\"226\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/7-Custom-Ruleset-Errors.png 1097w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/7-Custom-Ruleset-Errors-300x62.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/7-Custom-Ruleset-Errors-1024x211.png 1024w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/06\/7-Custom-Ruleset-Errors-768x158.png 768w\" sizes=\"(max-width: 1097px) 100vw, 1097px\" \/><\/a><\/p>\n<p>Currently, the &#8220;Template Diagnostics in External Headers\u201d option is ignored if \u201cAnalysis Ruleset for External Headers\u201d is used. We plan to change the behavior to honor the option and treat templates as non-external and apply the general ruleset instead of the ruleset for external headers.<\/p>\n<h3>Bonus: Even Better Code Analysis Performance<\/h3>\n<p>While we were working on this feature, we realized some of the built-in checkers were not really skipping functions from the files that are excluded through \u201cCAExcludePath\u201d environment variable. Instead, they were analyzed just like others and the resultant warnings from those functions were simply filtered out. As we add support for the \/external:* option, we updated them to honor \u201cCAExcludePath\u201d as well as \/external:* and \/analyze:external- options, and to skip analysis of functions from excluded or external files. This resulted in observed performance improvements in our production codebase, ranging from 25% to 30%. Actual performance improvements will vary depending on how much of the codebase is from excluded or external header files, and how much of the project uses PCH, etc.<\/p>\n<h2>External Headers and the Microsoft C++ Compiler<\/h2>\n<p>Several new flags have been added to the Microsoft C++ Compiler to specify external include directories and their warning and code analysis settings. You can learn more about the behavior of these flags on our <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/build\/reference\/external-external-headers-diagnostics?view=msvc-160\">compiler documentation pages<\/a>.<\/p>\n<h2>Send Us Feedback<\/h2>\n<p>Please grab a copy of the\u00a0<a href=\"https:\/\/visualstudio.microsoft.com\/downloads\/\">latest Visual Studio 2019 preview<\/a>\u00a0and try it out. We would love to hear your feedback about Visual Studio. If you have feedback, suggestions, or any other comments please submit them to <a href=\"https:\/\/developercommunity.visualstudio.com\/\">Developer Community<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you have tried to keep your code clean by selecting strict compiler warning levels or code analysis rulesets, you likely know how frustrating it can be to see these warnings for headers that are not part of your project. To alleviate this, we\u2019ve made it easy to mark headers as external to your project [&hellip;]<\/p>\n","protected":false},"author":326,"featured_media":28164,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-28162","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>If you have tried to keep your code clean by selecting strict compiler warning levels or code analysis rulesets, you likely know how frustrating it can be to see these warnings for headers that are not part of your project. To alleviate this, we\u2019ve made it easy to mark headers as external to your project [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/28162","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\/326"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=28162"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/28162\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/28164"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=28162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=28162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=28162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}