From 4d6334824d81086af205fe06b6fc4c4fda5224b4 Mon Sep 17 00:00:00 2001
From: Justin Goshi <jgoshi@microsoft.com>
Date: Wed, 11 Sep 2019 11:37:48 -0700
Subject: fileapi: add backtraces for LINK_PATH and LINK_DIRECTORIES

---
 Source/cmFileAPICodemodel.cxx                | 20 ++++++++------
 Source/cmLocalGenerator.cxx                  | 16 ++++++-----
 Source/cmLocalGenerator.h                    | 11 ++++----
 Tests/RunCMake/FileAPI/codemodel-v2-check.py | 40 ++++++++++++++++++++++++++--
 Tests/RunCMake/FileAPI/cxx/CMakeLists.txt    |  1 +
 5 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 805da81..3cf929f 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -1270,8 +1270,8 @@ Json::Value Target::DumpLinkCommandFragments()
   std::string linkLanguageFlags;
   std::vector<BT<std::string>> linkFlags;
   std::string frameworkPath;
-  std::string linkPath;
-  std::string linkLibs;
+  std::vector<BT<std::string>> linkPath;
+  std::vector<BT<std::string>> linkLibs;
   cmLocalGenerator* lg = this->GT->GetLocalGenerator();
   cmLinkLineComputer linkLineComputer(lg,
                                       lg->GetStateSnapshot().GetDirectory());
@@ -1280,8 +1280,6 @@ Json::Value Target::DumpLinkCommandFragments()
                      this->GT);
   linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
   frameworkPath = cmTrimWhitespace(frameworkPath);
-  linkPath = cmTrimWhitespace(linkPath);
-  linkLibs = cmTrimWhitespace(linkLibs);
 
   if (!linkLanguageFlags.empty()) {
     linkFragments.append(
@@ -1302,13 +1300,19 @@ Json::Value Target::DumpLinkCommandFragments()
   }
 
   if (!linkPath.empty()) {
-    linkFragments.append(
-      this->DumpCommandFragment(std::move(linkPath), "libraryPath"));
+    for (BT<std::string> frag : linkPath) {
+      frag.Value = cmTrimWhitespace(frag.Value);
+      linkFragments.append(
+        this->DumpCommandFragment(this->ToJBT(frag), "libraryPath"));
+    }
   }
 
   if (!linkLibs.empty()) {
-    linkFragments.append(
-      this->DumpCommandFragment(std::move(linkLibs), "libraries"));
+    for (BT<std::string> frag : linkLibs) {
+      frag.Value = cmTrimWhitespace(frag.Value);
+      linkFragments.append(
+        this->DumpCommandFragment(this->ToJBT(frag), "libraries"));
+    }
   }
 
   return linkFragments;
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index a4b482c..214e92c 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1198,17 +1198,21 @@ void cmLocalGenerator::GetTargetFlags(
   std::string& linkLibs, std::string& flags, std::string& linkFlags,
   std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target)
 {
-  std::vector<BT<std::string>> tmpLinkFlags;
-  this->GetTargetFlags(linkLineComputer, config, linkLibs, flags, tmpLinkFlags,
-                       frameworkPath, linkPath, target);
-  this->AppendFlags(linkFlags, tmpLinkFlags);
+  std::vector<BT<std::string>> linkFlagsList;
+  std::vector<BT<std::string>> linkPathList;
+  std::vector<BT<std::string>> linkLibsList;
+  this->GetTargetFlags(linkLineComputer, config, linkLibsList, flags,
+                       linkFlagsList, frameworkPath, linkPathList, target);
+  this->AppendFlags(linkFlags, linkFlagsList);
+  this->AppendFlags(linkPath, linkPathList);
+  this->AppendFlags(linkLibs, linkLibsList);
 }
 
 void cmLocalGenerator::GetTargetFlags(
   cmLinkLineComputer* linkLineComputer, const std::string& config,
-  std::string& linkLibs, std::string& flags,
+  std::vector<BT<std::string>>& linkLibs, std::string& flags,
   std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath,
-  std::string& linkPath, cmGeneratorTarget* target)
+  std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target)
 {
   const std::string buildType = cmSystemTools::UpperCase(config);
   cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index f04f391..512df26 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -382,12 +382,11 @@ public:
                       std::string& flags, std::string& linkFlags,
                       std::string& frameworkPath, std::string& linkPath,
                       cmGeneratorTarget* target);
-  void GetTargetFlags(cmLinkLineComputer* linkLineComputer,
-                      const std::string& config, std::string& linkLibs,
-                      std::string& flags,
-                      std::vector<BT<std::string>>& linkFlags,
-                      std::string& frameworkPath, std::string& linkPath,
-                      cmGeneratorTarget* target);
+  void GetTargetFlags(
+    cmLinkLineComputer* linkLineComputer, const std::string& config,
+    std::vector<BT<std::string>>& linkLibs, std::string& flags,
+    std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath,
+    std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target);
   void GetTargetDefines(cmGeneratorTarget const* target,
                         std::string const& config, std::string const& lang,
                         std::set<std::string>& defines) const;
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index 2a24421..52934f2 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -249,13 +249,13 @@ def check_target(c):
 
                     if expected["backtrace"] is not None:
                         expected_keys.append("backtrace")
-                        assert actual["fragment"] == expected["fragment"]
+                        assert matches(actual["fragment"], expected["fragment"])
                         assert actual["role"] == expected["role"]
                         check_backtrace(obj, actual["backtrace"], expected["backtrace"])
 
                     assert sorted(actual.keys()) == sorted(expected_keys)
 
-                check_list_match(lambda a, e: is_string(a["fragment"], e["fragment"]),
+                check_list_match(lambda a, e: matches(a["fragment"], e["fragment"]),
                                  obj["link"]["commandFragments"], expected["link"]["commandFragments"],
                                  check=check_link_command_fragments,
                                  check_exception=lambda a, e: "Link fragment: %s" % a["fragment"],
@@ -2218,6 +2218,42 @@ def gen_check_targets(c, g, inSource):
                             },
                         ],
                     },
+                    {
+                        "fragment" : ".*TargetLinkDir\\\"?$",
+                        "role" : "libraryPath",
+                        "backtrace": [
+                            {
+                                "file": "^cxx/CMakeLists\\.txt$",
+                                "line": 19,
+                                "command": "target_link_directories",
+                                "hasParent": True,
+                            },
+                            {
+                                "file" : "^cxx/CMakeLists\\.txt$",
+                                "line": None,
+                                "command": None,
+                                "hasParent": False,
+                            },
+                        ],
+                    },
+                    {
+                        "fragment" : ".*cxx_lib.*",
+                        "role" : "libraries",
+                        "backtrace": [
+                            {
+                                "file": "^cxx/CMakeLists\\.txt$",
+                                "line": 6,
+                                "command": "target_link_libraries",
+                                "hasParent": True,
+                            },
+                            {
+                                "file" : "^cxx/CMakeLists\\.txt$",
+                                "line": None,
+                                "command": None,
+                                "hasParent": False,
+                            },
+                        ],
+                    },
                 ],
             },
             "archive": None,
diff --git a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
index 17ff455..b0564f5 100644
--- a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
@@ -16,3 +16,4 @@ target_link_libraries(cxx_static_exe PRIVATE cxx_static_lib)
 
 target_compile_options(cxx_exe PUBLIC TargetCompileOptions)
 target_link_options(cxx_exe PUBLIC TargetLinkOptions)
+target_link_directories(cxx_exe PUBLIC "${CMAKE_BINARY_DIR}/TargetLinkDir")
-- 
cgit v0.12