Coverage Report

Created: 2026-06-15 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmCMakePolicyCommand.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmCMakePolicyCommand.h"
4
5
#include <cmext/string_view>
6
7
#include "cmArgumentParser.h"
8
#include "cmArgumentParserTypes.h"
9
#include "cmExecutionStatus.h"
10
#include "cmMakefile.h"
11
#include "cmPolicies.h"
12
#include "cmRange.h"
13
#include "cmStringAlgorithms.h"
14
15
namespace {
16
bool HandleSetMode(std::vector<std::string> const& args,
17
                   cmExecutionStatus& status);
18
bool HandleGetMode(std::vector<std::string> const& args,
19
                   cmExecutionStatus& status);
20
bool HandleVersionMode(std::vector<std::string> const& args,
21
                       cmExecutionStatus& status);
22
bool HandleGetWarningMode(std::vector<std::string> const& args,
23
                          cmExecutionStatus& status);
24
bool HandleIssueWarningMode(std::vector<std::string> const& args,
25
                            cmExecutionStatus& status);
26
}
27
28
// cmCMakePolicyCommand
29
bool cmCMakePolicyCommand(std::vector<std::string> const& args,
30
                          cmExecutionStatus& status)
31
0
{
32
0
  if (args.empty()) {
33
0
    status.SetError("requires at least one argument.");
34
0
    return false;
35
0
  }
36
37
0
  if (args[0] == "SET") {
38
0
    return HandleSetMode(args, status);
39
0
  }
40
0
  if (args[0] == "GET") {
41
0
    return HandleGetMode(args, status);
42
0
  }
43
0
  if (args[0] == "PUSH") {
44
0
    if (args.size() > 1) {
45
0
      status.SetError("PUSH may not be given additional arguments.");
46
0
      return false;
47
0
    }
48
0
    status.GetMakefile().PushPolicy();
49
0
    return true;
50
0
  }
51
0
  if (args[0] == "POP") {
52
0
    if (args.size() > 1) {
53
0
      status.SetError("POP may not be given additional arguments.");
54
0
      return false;
55
0
    }
56
0
    status.GetMakefile().PopPolicy();
57
0
    return true;
58
0
  }
59
0
  if (args[0] == "VERSION") {
60
0
    return HandleVersionMode(args, status);
61
0
  }
62
0
  if (args[0] == "GET_WARNING") {
63
0
    return HandleGetWarningMode(args, status);
64
0
  }
65
0
  if (args[0] == "ISSUE_WARNING") {
66
0
    return HandleIssueWarningMode(args, status);
67
0
  }
68
69
0
  status.SetError(cmStrCat("given unknown first argument \"", args[0], '"'));
70
0
  return false;
71
0
}
72
73
namespace {
74
75
bool HandleSetMode(std::vector<std::string> const& args,
76
                   cmExecutionStatus& status)
77
0
{
78
0
  if (args.size() != 3) {
79
0
    status.SetError("SET must be given exactly 2 additional arguments.");
80
0
    return false;
81
0
  }
82
83
0
  cmPolicies::PolicyStatus policyStatus;
84
0
  if (args[2] == "OLD") {
85
0
    policyStatus = cmPolicies::OLD;
86
0
  } else if (args[2] == "NEW") {
87
0
    policyStatus = cmPolicies::NEW;
88
0
  } else {
89
0
    status.SetError(
90
0
      cmStrCat("SET given unrecognized policy status \"", args[2], '"'));
91
0
    return false;
92
0
  }
93
94
0
  if (!status.GetMakefile().SetPolicy(args[1].c_str(), policyStatus)) {
95
0
    status.SetError("SET failed to set policy.");
96
0
    return false;
97
0
  }
98
0
  return true;
99
0
}
100
101
bool HandleGetMode(std::vector<std::string> const& args,
102
                   cmExecutionStatus& status)
103
0
{
104
0
  bool parent_scope = false;
105
0
  if (args.size() == 4 && args[3] == "PARENT_SCOPE") {
106
    // Undocumented PARENT_SCOPE option for use within CMake.
107
0
    parent_scope = true;
108
0
  } else if (args.size() != 3) {
109
0
    status.SetError("GET must be given exactly 2 additional arguments.");
110
0
    return false;
111
0
  }
112
113
  // Get arguments.
114
0
  std::string const& id = args[1];
115
0
  std::string const& var = args[2];
116
117
  // Lookup the policy number.
118
0
  cmPolicies::PolicyID pid;
119
0
  if (!cmPolicies::GetPolicyID(id.c_str(), pid)) {
120
0
    status.SetError(
121
0
      cmStrCat("GET given policy \"", id,
122
0
               "\" which is not known to this version of CMake."));
123
0
    return false;
124
0
  }
125
126
  // Lookup the policy setting.
127
0
  cmPolicies::PolicyStatus policyStatus =
128
0
    status.GetMakefile().GetPolicyStatus(pid, parent_scope);
129
0
  switch (policyStatus) {
130
0
    case cmPolicies::OLD:
131
      // Report that the policy is set to OLD.
132
0
      status.GetMakefile().AddDefinition(var, "OLD");
133
0
      break;
134
0
    case cmPolicies::WARN:
135
      // Report that the policy is not set.
136
0
      status.GetMakefile().AddDefinition(var, "");
137
0
      break;
138
0
    case cmPolicies::NEW:
139
      // Report that the policy is set to NEW.
140
0
      status.GetMakefile().AddDefinition(var, "NEW");
141
0
      break;
142
0
  }
143
144
0
  return true;
145
0
}
146
147
bool HandleVersionMode(std::vector<std::string> const& args,
148
                       cmExecutionStatus& status)
149
0
{
150
0
  if (args.size() <= 1) {
151
0
    status.SetError("VERSION not given an argument");
152
0
    return false;
153
0
  }
154
0
  if (args.size() >= 3) {
155
0
    status.SetError("VERSION given too many arguments");
156
0
    return false;
157
0
  }
158
0
  std::string const& version_string = args[1];
159
160
  // Separate the <min> version and any trailing ...<max> component.
161
0
  std::string::size_type const dd = version_string.find("...");
162
0
  std::string const version_min = version_string.substr(0, dd);
163
0
  std::string const version_max = dd != std::string::npos
164
0
    ? version_string.substr(dd + 3, std::string::npos)
165
0
    : std::string();
166
0
  if (dd != std::string::npos &&
167
0
      (version_min.empty() || version_max.empty())) {
168
0
    status.SetError(
169
0
      cmStrCat("VERSION \"", version_string,
170
0
               R"(" does not have a version on both sides of "...".)"));
171
0
    return false;
172
0
  }
173
174
0
  return status.GetMakefile().SetPolicyVersion(version_min, version_max);
175
0
}
176
177
bool HandleGetWarningMode(std::vector<std::string> const& args,
178
                          cmExecutionStatus& status)
179
0
{
180
0
  if (args.size() != 3) {
181
0
    status.SetError(
182
0
      "GET_WARNING must be given exactly 2 additional arguments.");
183
0
    return false;
184
0
  }
185
186
  // Get arguments.
187
0
  std::string const& id = args[1];
188
0
  std::string const& var = args[2];
189
190
  // Lookup the policy number.
191
0
  cmPolicies::PolicyID pid;
192
0
  if (!cmPolicies::GetPolicyID(id.c_str(), pid)) {
193
0
    status.SetError(
194
0
      cmStrCat("GET_WARNING given policy \"", id,
195
0
               "\" which is not known to this version of CMake."));
196
0
    return false;
197
0
  }
198
199
  // Lookup the policy warning.
200
0
  status.GetMakefile().AddDefinition(var, cmPolicies::GetPolicyWarning(pid));
201
202
0
  return true;
203
0
}
204
205
bool HandleIssueWarningMode(std::vector<std::string> const& args,
206
                            cmExecutionStatus& status)
207
0
{
208
0
  if (args.size() < 2) {
209
0
    status.SetError(
210
0
      "ISSUE_WARNING must be given at least one additional argument.");
211
0
    return false;
212
0
  }
213
214
  // Get arguments.
215
0
  std::string const& id = args[1];
216
217
0
  struct Arguments
218
0
  {
219
0
    ArgumentParser::MaybeEmpty<std::vector<std::string>> PreArgs;
220
0
    ArgumentParser::MaybeEmpty<std::vector<std::string>> PostArgs;
221
0
  };
222
223
0
  static auto const parser = cmArgumentParser<Arguments>{}
224
0
                               .Bind("PRE"_s, &Arguments::PreArgs)
225
0
                               .Bind("POST"_s, &Arguments::PostArgs);
226
227
0
  Arguments const arguments = parser.Parse(cmMakeRange(args).advance(2),
228
0
                                           /*unparsedArguments=*/nullptr);
229
230
  // Lookup the policy number.
231
0
  cmPolicies::PolicyID pid;
232
0
  if (!cmPolicies::GetPolicyID(id.c_str(), pid)) {
233
0
    status.SetError(
234
0
      cmStrCat("ISSUE_WARNING given policy \"", id,
235
0
               "\" which is not known to this version of CMake."));
236
0
    return false;
237
0
  }
238
239
  // Issue the policy warning.
240
0
  status.GetMakefile().IssuePolicyWarning(pid, cmJoin(arguments.PreArgs, {}),
241
0
                                          cmJoin(arguments.PostArgs, {}));
242
243
0
  return true;
244
0
}
245
}