Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmFileSet.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 "cmFileSet.h"
4
5
#include <string>
6
#include <unordered_map>
7
#include <utility>
8
#include <vector>
9
10
#include <cm/optional>
11
#include <cmext/algorithm>
12
#include <cmext/string_view>
13
14
#include "cmList.h"
15
#include "cmListFileCache.h"
16
#include "cmMakefile.h"
17
#include "cmMessageType.h"
18
#include "cmPolicies.h"
19
#include "cmStringAlgorithms.h"
20
#include "cmTarget.h"
21
22
namespace Metadata = cm::FileSetMetadata;
23
24
cmFileSet::cmFileSet(cmMakefile* makefile, cmTarget* target, std::string name,
25
                     std::string type, Metadata::Visibility visibility)
26
0
  : Makefile(makefile)
27
0
  , Target(target)
28
0
  , Name(std::move(name))
29
0
  , Type(std::move(type))
30
0
  , Visibility(visibility)
31
0
{
32
0
}
33
34
void cmFileSet::CopyEntries(cmFileSet const* fs)
35
0
{
36
0
  cm::append(this->DirectoryEntries, fs->DirectoryEntries);
37
0
  cm::append(this->FileEntries, fs->FileEntries);
38
0
}
39
40
void cmFileSet::ClearDirectoryEntries()
41
0
{
42
0
  this->DirectoryEntries.clear();
43
0
}
44
45
void cmFileSet::AddDirectoryEntry(BT<std::string> directories)
46
0
{
47
0
  this->DirectoryEntries.push_back(std::move(directories));
48
0
}
49
50
void cmFileSet::ClearFileEntries()
51
0
{
52
0
  this->FileEntries.clear();
53
0
}
54
55
void cmFileSet::AddFileEntry(BT<std::string> files)
56
0
{
57
0
  this->FileEntries.push_back(std::move(files));
58
0
}
59
60
namespace {
61
enum class ReadOnlyCondition
62
{
63
  All,
64
  Imported,
65
  NonImported,
66
};
67
68
struct ReadOnlyProperty
69
{
70
  ReadOnlyProperty(ReadOnlyCondition cond)
71
0
    : Condition{ cond }
72
0
  {
73
0
  }
74
  // ReadOnlyProperty(ReadOnlyCondition cond, cmPolicies::PolicyID id)
75
  //   : Condition{ cond }
76
  //   , Policy{ id }
77
  // {
78
  // }
79
80
  ReadOnlyCondition Condition;
81
  cm::optional<cmPolicies::PolicyID> Policy;
82
83
  std::string message(std::string const& prop, cmTarget* target,
84
                      cmFileSet* fileSet) const
85
0
  {
86
0
    std::string msg;
87
0
    if (this->Condition == ReadOnlyCondition::All) {
88
0
      msg = cmStrCat(" property is read-only for the file set \"",
89
0
                     fileSet->GetName(), " of the target \"");
90
0
    } else if (this->Condition == ReadOnlyCondition::Imported) {
91
0
      msg = " property can't be set on a file set attached to the imported "
92
0
            "target \"";
93
0
    } else if (this->Condition == ReadOnlyCondition::NonImported) {
94
0
      msg =
95
0
        " property can't be set on a file set attached to the non-imported "
96
0
        "target \"";
97
0
    }
98
0
    return cmStrCat(prop, msg, target->GetName(), "\"\n");
99
0
  }
100
101
  bool isReadOnly(std::string const& prop, cmMakefile* context,
102
                  cmTarget* target, cmFileSet* fileSet) const
103
0
  {
104
0
    auto importedTarget = target->IsImported();
105
0
    bool matchingCondition = true;
106
0
    if ((!importedTarget && this->Condition == ReadOnlyCondition::Imported) ||
107
0
        (importedTarget &&
108
0
         this->Condition == ReadOnlyCondition::NonImported)) {
109
0
      matchingCondition = false;
110
0
    }
111
0
    if (!matchingCondition) {
112
      // Not read-only in this scenario
113
0
      return false;
114
0
    }
115
116
0
    bool readOnly = true;
117
0
    if (!this->Policy) {
118
      // No policy associated, so is always read-only
119
0
      context->IssueMessage(MessageType::FATAL_ERROR,
120
0
                            this->message(prop, target, fileSet));
121
0
    }
122
0
    return readOnly;
123
0
  }
124
};
125
126
bool IsSettableProperty(cmMakefile* context, cmTarget* target,
127
                        cmFileSet* fileSet, std::string const& prop)
128
0
{
129
0
  using ROC = ReadOnlyCondition;
130
0
  static std::unordered_map<std::string, ReadOnlyProperty> const readOnlyProps{
131
0
    { "TYPE", { ROC::All } }, { "SCOPE", { ROC::All } }
132
0
  };
133
134
0
  auto it = readOnlyProps.find(prop);
135
136
0
  if (it != readOnlyProps.end()) {
137
0
    return !(it->second.isReadOnly(prop, context, target, fileSet));
138
0
  }
139
0
  return true;
140
0
}
141
142
cm::string_view const BASE_DIRS = "BASE_DIRS"_s;
143
cm::string_view const SOURCES = "SOURCES"_s;
144
cm::string_view const INTERFACE_SOURCES = "INTERFACE_SOURCES"_s;
145
cm::string_view const COMPILE_DEFINITIONS = "COMPILE_DEFINITIONS"_s;
146
cm::string_view const COMPILE_OPTIONS = "COMPILE_OPTIONS"_s;
147
cm::string_view const INCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES"_s;
148
}
149
150
void cmFileSet::SetProperty(std::string const& prop, cmValue value)
151
0
{
152
0
  if (!IsSettableProperty(this->Makefile, this->Target, this, prop)) {
153
0
    return;
154
0
  }
155
156
0
  if (prop == BASE_DIRS) {
157
0
    this->ClearDirectoryEntries();
158
0
    if (value) {
159
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
160
0
      this->AddDirectoryEntry(BT<std::string>{ value, lfbt });
161
0
    }
162
0
  } else if (prop == SOURCES) {
163
0
    if (!this->IsForSelf()) {
164
0
      return;
165
0
    }
166
0
    this->ClearFileEntries();
167
0
    if (value) {
168
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
169
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
170
0
    }
171
0
  } else if (prop == INTERFACE_SOURCES) {
172
0
    if (!this->IsForInterface()) {
173
0
      return;
174
0
    }
175
0
    this->ClearFileEntries();
176
0
    if (value) {
177
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
178
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
179
0
    }
180
0
  } else if (prop == INCLUDE_DIRECTORIES) {
181
0
    this->IncludeDirectories.clear();
182
0
    if (value) {
183
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
184
0
      this->IncludeDirectories.emplace_back(value, lfbt);
185
0
    }
186
0
  } else if (prop == COMPILE_OPTIONS) {
187
0
    this->CompileOptions.clear();
188
0
    if (value) {
189
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
190
0
      this->CompileOptions.emplace_back(value, lfbt);
191
0
    }
192
0
  } else if (prop == COMPILE_DEFINITIONS) {
193
0
    this->CompileDefinitions.clear();
194
0
    if (value) {
195
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
196
0
      this->CompileDefinitions.emplace_back(value, lfbt);
197
0
    }
198
0
  } else {
199
0
    this->Properties.SetProperty(prop, value);
200
0
  }
201
0
}
202
203
void cmFileSet::AppendProperty(std::string const& prop,
204
                               std::string const& value, bool asString)
205
0
{
206
0
  if (!IsSettableProperty(this->Makefile, this->Target, this, prop)) {
207
0
    return;
208
0
  }
209
210
0
  if (prop == BASE_DIRS) {
211
0
    if (!value.empty()) {
212
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
213
0
      this->AddDirectoryEntry(BT<std::string>{ value, lfbt });
214
0
    }
215
0
  } else if (prop == SOURCES) {
216
0
    if (!this->IsForSelf()) {
217
0
      return;
218
0
    }
219
0
    if (!value.empty()) {
220
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
221
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
222
0
    }
223
0
  } else if (prop == INTERFACE_SOURCES) {
224
0
    if (!this->IsForInterface()) {
225
0
      return;
226
0
    }
227
0
    if (!value.empty()) {
228
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
229
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
230
0
    }
231
0
  } else if (prop == INCLUDE_DIRECTORIES) {
232
0
    if (!value.empty()) {
233
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
234
0
      this->IncludeDirectories.emplace_back(value, lfbt);
235
0
    }
236
0
  } else if (prop == COMPILE_OPTIONS) {
237
0
    if (!value.empty()) {
238
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
239
0
      this->CompileOptions.emplace_back(value, lfbt);
240
0
    }
241
0
  } else if (prop == COMPILE_DEFINITIONS) {
242
0
    if (!value.empty()) {
243
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
244
0
      this->CompileDefinitions.emplace_back(value, lfbt);
245
0
    }
246
0
  } else {
247
0
    this->Properties.AppendProperty(prop, value, asString);
248
0
  }
249
0
}
250
251
cmValue cmFileSet::GetProperty(std::string const& prop) const
252
0
{
253
  // Check for the properties with backtraces.
254
0
  if (prop == BASE_DIRS) {
255
256
0
    static std::string output;
257
0
    output = cmList::to_string(this->GetDirectoryEntries());
258
0
    return cmValue(output);
259
0
  }
260
0
  if (prop == SOURCES) {
261
0
    if (!this->IsForSelf() || this->GetFileEntries().empty()) {
262
0
      return nullptr;
263
0
    }
264
265
0
    static std::string output;
266
0
    output = cmList::to_string(this->GetFileEntries());
267
0
    return cmValue(output);
268
0
  }
269
0
  if (prop == INTERFACE_SOURCES) {
270
0
    if (!this->IsForInterface() || this->GetFileEntries().empty()) {
271
0
      return nullptr;
272
0
    }
273
274
0
    static std::string output;
275
0
    output = cmList::to_string(this->GetFileEntries());
276
0
    return cmValue(output);
277
0
  }
278
279
0
  if (prop == INCLUDE_DIRECTORIES) {
280
0
    if (this->IncludeDirectories.empty()) {
281
0
      return nullptr;
282
0
    }
283
284
0
    static std::string output;
285
0
    output = cmList::to_string(this->IncludeDirectories);
286
0
    return cmValue(output);
287
0
  }
288
289
0
  if (prop == COMPILE_OPTIONS) {
290
0
    if (this->CompileOptions.empty()) {
291
0
      return nullptr;
292
0
    }
293
294
0
    static std::string output;
295
0
    output = cmList::to_string(this->CompileOptions);
296
0
    return cmValue(output);
297
0
  }
298
299
0
  if (prop == COMPILE_DEFINITIONS) {
300
0
    if (this->CompileDefinitions.empty()) {
301
0
      return nullptr;
302
0
    }
303
304
0
    static std::string output;
305
0
    output = cmList::to_string(this->CompileDefinitions);
306
0
    return cmValue(output);
307
0
  }
308
309
0
  if (prop == "TYPE"_s) {
310
0
    return cmValue{ this->GetType() };
311
0
  }
312
0
  if (prop == "SCOPE"_s) {
313
0
    static std::string scope =
314
0
      std::string{ Metadata::VisibilityToName(this->GetVisibility()) };
315
0
    return cmValue{ scope };
316
0
  }
317
318
0
  return this->Properties.GetPropertyValue(prop);
319
0
}