Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmDefinePropertyCommand.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 "cmDefinePropertyCommand.h"
4
5
#include <algorithm>
6
#include <iterator>
7
8
#include <cmext/string_view>
9
10
#include "cmArgumentParser.h"
11
#include "cmArgumentParserTypes.h"
12
#include "cmExecutionStatus.h"
13
#include "cmMakefile.h"
14
#include "cmProperty.h"
15
#include "cmRange.h"
16
#include "cmState.h"
17
#include "cmStringAlgorithms.h"
18
19
bool cmDefinePropertyCommand(std::vector<std::string> const& args,
20
                             cmExecutionStatus& status)
21
0
{
22
0
  if (args.empty()) {
23
0
    status.SetError("called with incorrect number of arguments");
24
0
    return false;
25
0
  }
26
27
  // Get the scope in which to define the property.
28
0
  cmProperty::ScopeType scope;
29
0
  std::string const& scope_arg = args[0];
30
31
0
  if (scope_arg == "GLOBAL") {
32
0
    scope = cmProperty::GLOBAL;
33
0
  } else if (scope_arg == "DIRECTORY") {
34
0
    scope = cmProperty::DIRECTORY;
35
0
  } else if (scope_arg == "TARGET") {
36
0
    scope = cmProperty::TARGET;
37
0
  } else if (scope_arg == "SOURCE") {
38
0
    scope = cmProperty::SOURCE_FILE;
39
0
  } else if (scope_arg == "TEST") {
40
0
    scope = cmProperty::TEST;
41
0
  } else if (scope_arg == "VARIABLE") {
42
0
    scope = cmProperty::VARIABLE;
43
0
  } else if (scope_arg == "CACHED_VARIABLE") {
44
0
    scope = cmProperty::CACHED_VARIABLE;
45
0
  } else {
46
0
    status.SetError(cmStrCat("given invalid scope ", scope_arg,
47
0
                             ".  Valid scopes are GLOBAL, DIRECTORY, TARGET, "
48
0
                             "SOURCE, TEST, VARIABLE, CACHED_VARIABLE."));
49
0
    return false;
50
0
  }
51
52
  // Parse remaining arguments.
53
0
  bool inherited = false;
54
0
  std::string PropertyName;
55
0
  ArgumentParser::NonEmpty<std::vector<std::string>> BriefDocs;
56
0
  ArgumentParser::NonEmpty<std::vector<std::string>> FullDocs;
57
0
  std::string initializeFromVariable;
58
59
0
  cmArgumentParser<void> parser;
60
0
  parser.Bind("PROPERTY"_s, PropertyName);
61
0
  parser.Bind("BRIEF_DOCS"_s, BriefDocs);
62
0
  parser.Bind("FULL_DOCS"_s, FullDocs);
63
0
  parser.Bind("INHERITED"_s, inherited);
64
0
  parser.Bind("INITIALIZE_FROM_VARIABLE"_s, initializeFromVariable);
65
0
  std::vector<std::string> invalidArgs;
66
67
0
  parser.Parse(cmMakeRange(args).advance(1), &invalidArgs);
68
0
  if (!invalidArgs.empty()) {
69
0
    status.SetError(
70
0
      cmStrCat("given invalid argument \"", invalidArgs.front(), "\"."));
71
0
    return false;
72
0
  }
73
74
  // Make sure a property name was found.
75
0
  if (PropertyName.empty()) {
76
0
    status.SetError("not given a PROPERTY <name> argument.");
77
0
    return false;
78
0
  }
79
80
0
  if (!initializeFromVariable.empty()) {
81
    // Make sure property scope is TARGET.
82
0
    if (scope != cmProperty::TARGET) {
83
0
      status.SetError(
84
0
        "Scope must be TARGET if INITIALIZE_FROM_VARIABLE is specified");
85
0
      return false;
86
0
    }
87
88
    // Make sure the variable has the property name as a suffix.
89
0
    if (!cmHasSuffix(initializeFromVariable, PropertyName)) {
90
0
      status.SetError(cmStrCat("Variable name \"", initializeFromVariable,
91
0
                               "\" does not end with property name \"",
92
0
                               PropertyName, '"'));
93
0
      return false;
94
0
    }
95
0
    if (PropertyName.find('_') == std::string::npos) {
96
0
      status.SetError(cmStrCat("Property name \"", PropertyName,
97
0
                               "\" defined with INITIALIZE_FROM_VARIABLE does "
98
0
                               "not contain underscore"));
99
0
      return false;
100
0
    }
101
102
    // Make sure the variable is not reserved.
103
0
    static constexpr char const* reservedPrefixes[] = {
104
0
      "CMAKE_",
105
0
      "_CMAKE_",
106
0
    };
107
0
    if (std::any_of(std::begin(reservedPrefixes), std::end(reservedPrefixes),
108
0
                    [&initializeFromVariable](char const* prefix) {
109
0
                      return cmHasPrefix(initializeFromVariable, prefix);
110
0
                    })) {
111
0
      status.SetError(cmStrCat("variable name \"", initializeFromVariable,
112
0
                               "\" is reserved"));
113
0
      return false;
114
0
    }
115
0
  }
116
117
  // Actually define the property.
118
0
  status.GetMakefile().GetState()->DefineProperty(
119
0
    PropertyName, scope, cmJoin(BriefDocs, ""), cmJoin(FullDocs, ""),
120
0
    inherited, initializeFromVariable);
121
122
0
  return true;
123
0
}