Repository: conan-io/conan
Pull request: Feature: detect VS2022 as msvc
closes: #9501 

Changelog: Feature: Detect Visual Studio 2022 as `msvc`.
Docs: omit

- [ ] Refer to the issue that supports this Pull Request.
- [ ] If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
- [ ] I've read the [Contributing guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [ ] I've followed the PEP8 style guides for Python code.
- [ ] I've opened another PR in the Conan docs repo to the ``develop`` branch, documenting this one. 

<sup>**Note:** By default this PR will skip the slower tests and will use a limited set of python versions. Check [here](https://github.com/conan-io/conan/blob/develop/.github/PR_INCREASE_TESTING.md) how to increase the testing level by writing some tags in the current PR body text.</sup>


Problem statement:
Make VS2022 use ``msvc`` as the default detected compiler in the profile
We can add as it is experimental, the detection of VS 2022 as ``msvc`` compiler instead of ``Visual Studio``. That might help in improving this new setting, and its support, specially in the new integrations.

Hints from issue discussion:

Commit message: - detect VS2022 as msvc

Signed-off-by: SSE4 <tomskside@gmail.com>

Patch to review:
diff --git a/conans/client/conf/compiler_id.py b/conans/client/conf/compiler_id.py
index 9fa32e50036..da9adee0591 100644
--- a/conans/client/conf/compiler_id.py
+++ b/conans/client/conf/compiler_id.py
@@ -11,10 +11,11 @@
 CLANG = "clang"
 APPLE_CLANG = "apple-clang"
 SUNCC = "suncc"
-MSVC = "Visual Studio"
+VISUAL_STUDIO = "Visual Studio"
 INTEL = "intel"
 QCC = "qcc"
 MCST_LCC = "mcst-lcc"
+MSVC = "msvc"
 
 
 class CompilerId(object):
@@ -135,21 +136,28 @@ def _parse_compiler_version(defines):
             patch = version & 0xF
         # MSVC goes after Clang and Intel, as they may define _MSC_VER
         elif '_MSC_VER' in defines:
-            compiler = MSVC
             version = int(defines['_MSC_VER'])
-            # map _MSC_VER into conan-friendly Visual Studio version
-            # currently, conan uses major only, but here we store minor for the future as well
-            # https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019
-            major, minor = MSVC_TO_VS_VERSION.get(version)
-            # special cases 19.8 and 19.9, 19.10 and 19.11
             full_version = 0
             if '_MSC_FULL_VER' in defines:
                 full_version = int(defines['_MSC_FULL_VER'])
-            if (major, minor) == (16, 8) and full_version >= 192829500:
-                major, minor = 16, 9
-            if (major, minor) == (16, 10) and full_version >= 192930100:
-                major, minor = 16, 11
-            patch = 0
+            # Visual Studio 2022 onwards, detect as a new compiler "msvc"
+            if version >= 1930:
+                compiler = MSVC
+                major = int(version / 100)
+                minor = int(version % 100)
+                patch = int(full_version % 100000)
+            else:
+                compiler = VISUAL_STUDIO
+                # map _MSC_VER into conan-friendly Visual Studio version
+                # currently, conan uses major only, but here we store minor for the future as well
+                # https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019
+                major, minor = MSVC_TO_VS_VERSION.get(version)
+                # special cases 19.8 and 19.9, 19.10 and 19.11
+                if (major, minor) == (16, 8) and full_version >= 192829500:
+                    major, minor = 16, 9
+                if (major, minor) == (16, 10) and full_version >= 192930100:
+                    major, minor = 16, 11
+                patch = 0
         # GCC must be the last try, as other compilers may define __GNUC__ for compatibility
         elif '__GNUC__' in defines:
             if '__llvm__' in defines:
diff --git a/conans/client/conf/detect.py b/conans/client/conf/detect.py
index 71f54a8a703..0aebfdc5e82 100644
--- a/conans/client/conf/detect.py
+++ b/conans/client/conf/detect.py
@@ -160,6 +160,10 @@ def _get_profile_compiler_version(compiler, version, output):
         return major
     elif compiler == "intel" and (int(major) < 19 or (int(major) == 19 and int(minor) == 0)):
         return major
+    elif compiler == "msvc":
+        # by default, drop the last digit of the minor (19.30 -> 19.3)
+        if len(minor) == 2:
+            version = version[:len(version) - 1]
     return version
 
 
@@ -224,6 +228,13 @@ def _detect_compiler_version(result, output, profile_path):
         output.error("Unable to find a working compiler")
         return
 
+    # Visual Studio 2022 onwards, detect as a new compiler "msvc"
+    if compiler == "Visual Studio":
+        version = Version(version)
+        if version == "17":
+            compiler = "msvc"
+            version = "19.3"
+
     result.append(("compiler", compiler))
     result.append(("compiler.version", _get_profile_compiler_version(compiler, version, output)))
 
diff --git a/conans/test/unittests/client/build/compiler_id_test.py b/conans/test/unittests/client/build/compiler_id_test.py
index 34dabe8ce02..ea01fcbdb33 100644
--- a/conans/test/unittests/client/build/compiler_id_test.py
+++ b/conans/test/unittests/client/build/compiler_id_test.py
@@ -2,7 +2,7 @@
 from parameterized import parameterized
 
 from conans.client.conf.compiler_id import detect_compiler_id, CompilerId, UNKNOWN_COMPILER, \
-    GCC, LLVM_GCC, CLANG, APPLE_CLANG, SUNCC, MSVC, INTEL, QCC, MCST_LCC
+    GCC, LLVM_GCC, CLANG, APPLE_CLANG, SUNCC, VISUAL_STUDIO, MSVC, INTEL, QCC, MCST_LCC
 from conans.test.unittests.util.tools_test import RunnerMock
 
 
@@ -105,13 +105,18 @@ def test_suncc(self):
                            ("MSC_CMD_FLAGS=-D_MSC_VER=1928 -D_MSC_FULL_VER=192829500", 16, 9, 0),
                            ("MSC_CMD_FLAGS=-D_MSC_VER=1929", 16, 10, 0),
                            ("MSC_CMD_FLAGS=-D_MSC_VER=1929 -D_MSC_FULL_VER=192930100", 16, 11, 0),
-                           ("MSC_CMD_FLAGS=-D_MSC_VER=1930", 17, 0, 0),
                            ])
-    def test_msvc(self, line, major, minor, patch):
+    def test_visual_studio(self, line, major, minor, patch):
         runner = RunnerMock()
         runner.output = line
         compiler_id = detect_compiler_id("cl", runner=runner)
-        self.assertEqual(CompilerId(MSVC, major, minor, patch), compiler_id)
+        self.assertEqual(CompilerId(VISUAL_STUDIO, major, minor, patch), compiler_id)
+
+    def test_msvc(self):
+        runner = RunnerMock()
+        runner.output = "MSC_CMD_FLAGS=-D_MSC_VER=1930"
+        compiler_id = detect_compiler_id("cl", runner=runner)
+        self.assertEqual(CompilerId(MSVC, 19, 30, 0), compiler_id)
 
     def test_intel(self):
         runner = RunnerMock()
diff --git a/conans/test/unittests/util/detect_test.py b/conans/test/unittests/util/detect_test.py
index b65203a070d..07d23670c7f 100644
--- a/conans/test/unittests/util/detect_test.py
+++ b/conans/test/unittests/util/detect_test.py
@@ -93,3 +93,12 @@ def test_detect_clang_gcc_toolchain(self, _):
         with tools.environment_append({"CC": "clang-9 --gcc-toolchain=/usr/lib/gcc/x86_64-linux-gnu/9"}):
             detect_defaults_settings(output, profile_path="./MyProfile")
             self.assertIn("CC and CXX: clang-9 --gcc-toolchain", output)
+
+    def test_vs2022(self):
+        with mock.patch("conans.client.conf.detect._get_default_compiler",
+                        mock.MagicMock(return_value=("Visual Studio", "17"))):
+            result = detect_defaults_settings(output=Mock(),
+                                              profile_path=DEFAULT_PROFILE_NAME)
+            result = dict(result)
+            self.assertEqual('msvc', result['compiler'])
+            self.assertEqual('19.3', result['compiler.version'])


Code review comments:
diff_hunk: @@ -160,6 +160,10 @@ def _get_profile_compiler_version(compiler, version, output):
         return major
     elif compiler == "intel" and (int(major) < 19 or (int(major) == 19 and int(minor) == 0)):
         return major
+    elif compiler == "msvc":
+        # by default, drop the last digit of the minor (19.30 -> 19.3)
+        if len(minor) == 2:
+            version = version[:len(version) - 1]
path: conans/client/conf/detect.py
text: @user1:
```suggestion
            version = version[:-1]
```