Coverage Report

Created: 2026-04-29 07:01

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 "cmRange.h"
20
#include "cmStringAlgorithms.h"
21
#include "cmTarget.h"
22
23
namespace Metadata = cm::FileSetMetadata;
24
25
cmFileSet::cmFileSet(cmMakefile* makefile, cmTarget* target, std::string name,
26
                     std::string type, Metadata::Visibility visibility)
27
0
  : Makefile(makefile)
28
0
  , Target(target)
29
0
  , Name(std::move(name))
30
0
  , Type(std::move(type))
31
0
  , Visibility(visibility)
32
0
{
33
0
}
34
35
void cmFileSet::CopyEntries(cmFileSet const* fs)
36
0
{
37
0
  cm::append(this->DirectoryEntries, fs->DirectoryEntries);
38
0
  cm::append(this->FileEntries, fs->FileEntries);
39
0
}
40
41
void cmFileSet::ClearDirectoryEntries()
42
0
{
43
0
  this->DirectoryEntries.clear();
44
0
}
45
46
void cmFileSet::AddDirectoryEntry(BT<std::string> directories)
47
0
{
48
0
  this->DirectoryEntries.push_back(std::move(directories));
49
0
}
50
51
void cmFileSet::ClearFileEntries()
52
0
{
53
0
  this->FileEntries.clear();
54
0
}
55
56
void cmFileSet::AddFileEntry(BT<std::string> files)
57
0
{
58
0
  this->FileEntries.push_back(std::move(files));
59
0
}
60
61
cmBTStringRange cmFileSet::GetIncludeDirectories() const
62
0
{
63
0
  return cmMakeRange(this->IncludeDirectories);
64
0
}
65
cmBTStringRange cmFileSet::GetInterfaceIncludeDirectories() const
66
0
{
67
0
  return cmMakeRange(this->InterfaceIncludeDirectories);
68
0
}
69
70
cmBTStringRange cmFileSet::GetCompileOptions() const
71
0
{
72
0
  return cmMakeRange(this->CompileOptions);
73
0
}
74
cmBTStringRange cmFileSet::GetInterfaceCompileOptions() const
75
0
{
76
0
  return cmMakeRange(this->InterfaceCompileOptions);
77
0
}
78
79
cmBTStringRange cmFileSet::GetCompileDefinitions() const
80
0
{
81
0
  return cmMakeRange(this->CompileDefinitions);
82
0
}
83
cmBTStringRange cmFileSet::GetInterfaceCompileDefinitions() const
84
0
{
85
0
  return cmMakeRange(this->InterfaceCompileDefinitions);
86
0
}
87
88
namespace {
89
enum class ReadOnlyCondition
90
{
91
  All,
92
  Imported,
93
  NonImported,
94
};
95
96
struct ReadOnlyProperty
97
{
98
  ReadOnlyProperty(ReadOnlyCondition cond)
99
0
    : Condition{ cond }
100
0
  {
101
0
  }
102
  // ReadOnlyProperty(ReadOnlyCondition cond, cmPolicies::PolicyID id)
103
  //   : Condition{ cond }
104
  //   , Policy{ id }
105
  // {
106
  // }
107
108
  ReadOnlyCondition Condition;
109
  cm::optional<cmPolicies::PolicyID> Policy;
110
111
  std::string message(std::string const& prop, cmTarget* target,
112
                      cmFileSet* fileSet) const
113
0
  {
114
0
    std::string msg;
115
0
    if (this->Condition == ReadOnlyCondition::All) {
116
0
      msg = cmStrCat(" property is read-only for the file set \"",
117
0
                     fileSet->GetName(), " of the target \"");
118
0
    } else if (this->Condition == ReadOnlyCondition::Imported) {
119
0
      msg = " property can't be set on a file set attached to the imported "
120
0
            "target \"";
121
0
    } else if (this->Condition == ReadOnlyCondition::NonImported) {
122
0
      msg =
123
0
        " property can't be set on a file set attached to the non-imported "
124
0
        "target \"";
125
0
    }
126
0
    return cmStrCat(prop, msg, target->GetName(), "\"\n");
127
0
  }
128
129
  bool isReadOnly(std::string const& prop, cmMakefile* context,
130
                  cmTarget* target, cmFileSet* fileSet) const
131
0
  {
132
0
    auto importedTarget = target->IsImported();
133
0
    bool matchingCondition = true;
134
0
    if ((!importedTarget && this->Condition == ReadOnlyCondition::Imported) ||
135
0
        (importedTarget &&
136
0
         this->Condition == ReadOnlyCondition::NonImported)) {
137
0
      matchingCondition = false;
138
0
    }
139
0
    if (!matchingCondition) {
140
      // Not read-only in this scenario
141
0
      return false;
142
0
    }
143
144
0
    bool readOnly = true;
145
0
    if (!this->Policy) {
146
      // No policy associated, so is always read-only
147
0
      context->IssueMessage(MessageType::FATAL_ERROR,
148
0
                            this->message(prop, target, fileSet));
149
0
    }
150
0
    return readOnly;
151
0
  }
152
};
153
154
bool IsSettableProperty(cmMakefile* context, cmTarget* target,
155
                        cmFileSet* fileSet, std::string const& prop)
156
0
{
157
0
  using ROC = ReadOnlyCondition;
158
0
  static std::unordered_map<std::string, ReadOnlyProperty> const readOnlyProps{
159
0
    { "TYPE", { ROC::All } }, { "SCOPE", { ROC::All } }
160
0
  };
161
162
0
  auto it = readOnlyProps.find(prop);
163
164
0
  if (it != readOnlyProps.end()) {
165
0
    return !(it->second.isReadOnly(prop, context, target, fileSet));
166
0
  }
167
0
  return true;
168
0
}
169
170
cm::string_view const BASE_DIRS = "BASE_DIRS"_s;
171
cm::string_view const SOURCES = "SOURCES"_s;
172
cm::string_view const INTERFACE_SOURCES = "INTERFACE_SOURCES"_s;
173
cm::string_view const INCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES"_s;
174
cm::string_view const INTERFACE_INCLUDE_DIRECTORIES =
175
  "INTERFACE_INCLUDE_DIRECTORIES"_s;
176
cm::string_view const COMPILE_DEFINITIONS = "COMPILE_DEFINITIONS"_s;
177
cm::string_view const INTERFACE_COMPILE_DEFINITIONS =
178
  "INTERFACE_COMPILE_DEFINITIONS"_s;
179
cm::string_view const COMPILE_OPTIONS = "COMPILE_OPTIONS"_s;
180
cm::string_view const INTERFACE_COMPILE_OPTIONS =
181
  "INTERFACE_COMPILE_OPTIONS"_s;
182
}
183
184
void cmFileSet::SetProperty(std::string const& prop, cmValue value)
185
0
{
186
0
  if (!IsSettableProperty(this->Makefile, this->Target, this, prop)) {
187
0
    return;
188
0
  }
189
190
0
  if (prop == BASE_DIRS) {
191
0
    this->ClearDirectoryEntries();
192
0
    if (value) {
193
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
194
0
      this->AddDirectoryEntry(BT<std::string>{ value, lfbt });
195
0
    }
196
0
  } else if (prop == SOURCES) {
197
0
    if (!this->IsForSelf()) {
198
0
      return;
199
0
    }
200
0
    this->ClearFileEntries();
201
0
    if (value) {
202
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
203
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
204
0
    }
205
0
  } else if (prop == INTERFACE_SOURCES) {
206
0
    if (!this->IsForInterface()) {
207
0
      return;
208
0
    }
209
0
    this->ClearFileEntries();
210
0
    if (value) {
211
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
212
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
213
0
    }
214
0
  } else if (prop == INCLUDE_DIRECTORIES) {
215
0
    if (!this->IsForSelf()) {
216
0
      return;
217
0
    }
218
0
    this->IncludeDirectories.clear();
219
0
    if (value) {
220
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
221
0
      this->IncludeDirectories.emplace_back(value, lfbt);
222
0
    }
223
0
  } else if (prop == INTERFACE_INCLUDE_DIRECTORIES) {
224
0
    if (!this->IsForInterface()) {
225
0
      return;
226
0
    }
227
0
    this->InterfaceIncludeDirectories.clear();
228
0
    if (value) {
229
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
230
0
      this->InterfaceIncludeDirectories.emplace_back(value, lfbt);
231
0
    }
232
0
  } else if (prop == COMPILE_OPTIONS) {
233
0
    if (!this->IsForSelf()) {
234
0
      return;
235
0
    }
236
0
    this->CompileOptions.clear();
237
0
    if (value) {
238
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
239
0
      this->CompileOptions.emplace_back(value, lfbt);
240
0
    }
241
0
  } else if (prop == INTERFACE_COMPILE_OPTIONS) {
242
0
    if (!this->IsForInterface()) {
243
0
      return;
244
0
    }
245
0
    this->InterfaceCompileOptions.clear();
246
0
    if (value) {
247
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
248
0
      this->InterfaceCompileOptions.emplace_back(value, lfbt);
249
0
    }
250
0
  } else if (prop == COMPILE_DEFINITIONS) {
251
0
    if (!this->IsForSelf()) {
252
0
      return;
253
0
    }
254
0
    this->CompileDefinitions.clear();
255
0
    if (value) {
256
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
257
0
      this->CompileDefinitions.emplace_back(value, lfbt);
258
0
    }
259
0
  } else if (prop == INTERFACE_COMPILE_DEFINITIONS) {
260
0
    if (!this->IsForInterface()) {
261
0
      return;
262
0
    }
263
0
    this->InterfaceCompileDefinitions.clear();
264
0
    if (value) {
265
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
266
0
      this->InterfaceCompileDefinitions.emplace_back(value, lfbt);
267
0
    }
268
0
  } else {
269
0
    this->Properties.SetProperty(prop, value);
270
0
  }
271
0
}
272
273
void cmFileSet::AppendProperty(std::string const& prop,
274
                               std::string const& value, bool asString)
275
0
{
276
0
  if (!IsSettableProperty(this->Makefile, this->Target, this, prop)) {
277
0
    return;
278
0
  }
279
280
0
  if (prop == BASE_DIRS) {
281
0
    if (!value.empty()) {
282
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
283
0
      this->AddDirectoryEntry(BT<std::string>{ value, lfbt });
284
0
    }
285
0
  } else if (prop == SOURCES) {
286
0
    if (!this->IsForSelf()) {
287
0
      return;
288
0
    }
289
0
    if (!value.empty()) {
290
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
291
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
292
0
    }
293
0
  } else if (prop == INTERFACE_SOURCES) {
294
0
    if (!this->IsForInterface()) {
295
0
      return;
296
0
    }
297
0
    if (!value.empty()) {
298
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
299
0
      this->AddFileEntry(BT<std::string>{ value, lfbt });
300
0
    }
301
0
  } else if (prop == INCLUDE_DIRECTORIES) {
302
0
    if (!this->IsForSelf()) {
303
0
      return;
304
0
    }
305
0
    if (!value.empty()) {
306
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
307
0
      this->IncludeDirectories.emplace_back(value, lfbt);
308
0
    }
309
0
  } else if (prop == INTERFACE_INCLUDE_DIRECTORIES) {
310
0
    if (!this->IsForInterface()) {
311
0
      return;
312
0
    }
313
0
    if (!value.empty()) {
314
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
315
0
      this->InterfaceIncludeDirectories.emplace_back(value, lfbt);
316
0
    }
317
0
  } else if (prop == COMPILE_OPTIONS) {
318
0
    if (!this->IsForSelf()) {
319
0
      return;
320
0
    }
321
0
    if (!value.empty()) {
322
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
323
0
      this->CompileOptions.emplace_back(value, lfbt);
324
0
    }
325
0
  } else if (prop == INTERFACE_COMPILE_OPTIONS) {
326
0
    if (!this->IsForInterface()) {
327
0
      return;
328
0
    }
329
0
    if (!value.empty()) {
330
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
331
0
      this->InterfaceCompileOptions.emplace_back(value, lfbt);
332
0
    }
333
0
  } else if (prop == COMPILE_DEFINITIONS) {
334
0
    if (!this->IsForSelf()) {
335
0
      return;
336
0
    }
337
0
    if (!value.empty()) {
338
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
339
0
      this->CompileDefinitions.emplace_back(value, lfbt);
340
0
    }
341
0
  } else if (prop == INTERFACE_COMPILE_DEFINITIONS) {
342
0
    if (!this->IsForInterface()) {
343
0
      return;
344
0
    }
345
0
    if (!value.empty()) {
346
0
      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
347
0
      this->InterfaceCompileDefinitions.emplace_back(value, lfbt);
348
0
    }
349
0
  } else {
350
0
    this->Properties.AppendProperty(prop, value, asString);
351
0
  }
352
0
}
353
354
cmValue cmFileSet::GetProperty(std::string const& prop) const
355
0
{
356
  // Check for the properties with backtraces.
357
0
  if (prop == BASE_DIRS) {
358
359
0
    static std::string output;
360
0
    output = cmList::to_string(this->GetDirectoryEntries());
361
0
    return cmValue(output);
362
0
  }
363
0
  if (prop == SOURCES) {
364
0
    if (!this->IsForSelf() || this->GetFileEntries().empty()) {
365
0
      return nullptr;
366
0
    }
367
368
0
    static std::string output;
369
0
    output = cmList::to_string(this->GetFileEntries());
370
0
    return cmValue(output);
371
0
  }
372
0
  if (prop == INTERFACE_SOURCES) {
373
0
    if (!this->IsForInterface() || this->GetFileEntries().empty()) {
374
0
      return nullptr;
375
0
    }
376
377
0
    static std::string output;
378
0
    output = cmList::to_string(this->GetFileEntries());
379
0
    return cmValue(output);
380
0
  }
381
382
0
  if (prop == INCLUDE_DIRECTORIES) {
383
0
    if (this->IncludeDirectories.empty()) {
384
0
      return nullptr;
385
0
    }
386
387
0
    static std::string output;
388
0
    output = cmList::to_string(this->IncludeDirectories);
389
0
    return cmValue(output);
390
0
  }
391
392
0
  if (prop == INTERFACE_INCLUDE_DIRECTORIES) {
393
0
    if (this->InterfaceIncludeDirectories.empty()) {
394
0
      return nullptr;
395
0
    }
396
397
0
    static std::string output;
398
0
    output = cmList::to_string(this->InterfaceIncludeDirectories);
399
0
    return cmValue(output);
400
0
  }
401
402
0
  if (prop == COMPILE_OPTIONS) {
403
0
    if (this->CompileOptions.empty()) {
404
0
      return nullptr;
405
0
    }
406
407
0
    static std::string output;
408
0
    output = cmList::to_string(this->CompileOptions);
409
0
    return cmValue(output);
410
0
  }
411
412
0
  if (prop == INTERFACE_COMPILE_OPTIONS) {
413
0
    if (this->InterfaceCompileOptions.empty()) {
414
0
      return nullptr;
415
0
    }
416
417
0
    static std::string output;
418
0
    output = cmList::to_string(this->InterfaceCompileOptions);
419
0
    return cmValue(output);
420
0
  }
421
422
0
  if (prop == COMPILE_DEFINITIONS) {
423
0
    if (this->CompileDefinitions.empty()) {
424
0
      return nullptr;
425
0
    }
426
427
0
    static std::string output;
428
0
    output = cmList::to_string(this->CompileDefinitions);
429
0
    return cmValue(output);
430
0
  }
431
432
0
  if (prop == INTERFACE_COMPILE_DEFINITIONS) {
433
0
    if (this->InterfaceCompileDefinitions.empty()) {
434
0
      return nullptr;
435
0
    }
436
437
0
    static std::string output;
438
0
    output = cmList::to_string(this->InterfaceCompileDefinitions);
439
0
    return cmValue(output);
440
0
  }
441
442
0
  if (prop == "TYPE"_s) {
443
0
    return cmValue{ this->GetType() };
444
0
  }
445
0
  if (prop == "SCOPE"_s) {
446
0
    static std::string scope =
447
0
      std::string{ Metadata::VisibilityToName(this->GetVisibility()) };
448
0
    return cmValue{ scope };
449
0
  }
450
451
0
  return this->Properties.GetPropertyValue(prop);
452
0
}