Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratorExpressionDAGChecker.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 "cmGeneratorExpressionDAGChecker.h"
4
5
#include <utility>
6
7
#include <cm/optional>
8
#include <cm/string_view>
9
#include <cmext/string_view>
10
11
#include "cmGenExContext.h"
12
#include "cmGenExEvaluation.h"
13
#include "cmGeneratorExpressionEvaluator.h"
14
#include "cmGeneratorTarget.h"
15
#include "cmLocalGenerator.h"
16
#include "cmMessageType.h"
17
#include "cmStringAlgorithms.h"
18
#include "cmake.h"
19
20
cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker(
21
  cmGeneratorTarget const* target, std::string property,
22
  GeneratorExpressionContent const* content,
23
  cmGeneratorExpressionDAGChecker* parent, cm::GenEx::Context const& context,
24
  cmListFileBacktrace backtrace, ComputingLinkLibraries computingLinkLibraries)
25
42.2k
  : Parent(parent)
26
42.2k
  , Top(parent ? parent->Top : this)
27
42.2k
  , Target(target)
28
42.2k
  , Property(std::move(property))
29
42.2k
  , Content(content)
30
42.2k
  , Backtrace(std::move(backtrace))
31
42.2k
  , ComputingLinkLibraries_(computingLinkLibraries)
32
42.2k
{
33
42.2k
  if (parent) {
34
8.03k
    this->TopIsTransitiveProperty = parent->TopIsTransitiveProperty;
35
34.2k
  } else {
36
34.2k
    this->TopIsTransitiveProperty =
37
34.2k
      this->Target->IsTransitiveProperty(this->Property, context, this)
38
34.2k
        .has_value();
39
34.2k
  }
40
41
42.2k
  this->CheckResult = this->CheckGraph();
42
43
42.2k
  if (this->CheckResult == DAG && this->EvaluatingTransitiveProperty()) {
44
13.6k
    auto const* top = this->Top;
45
13.6k
    auto it = top->Seen.find(this->Target);
46
13.6k
    if (it != top->Seen.end()) {
47
1.74k
      std::set<std::string> const& propSet = it->second;
48
1.74k
      if (propSet.find(this->Property) != propSet.end()) {
49
1.16k
        this->CheckResult = ALREADY_SEEN;
50
1.16k
        return;
51
1.16k
      }
52
1.74k
    }
53
12.4k
    top->Seen[this->Target].insert(this->Property);
54
12.4k
  }
55
42.2k
}
56
57
cmGeneratorExpressionDAGChecker::Result
58
cmGeneratorExpressionDAGChecker::Check() const
59
19.4k
{
60
19.4k
  return this->CheckResult;
61
19.4k
}
62
63
void cmGeneratorExpressionDAGChecker::ReportError(cm::GenEx::Evaluation* eval,
64
                                                  std::string const& expr)
65
1
{
66
1
  if (this->CheckResult == DAG) {
67
0
    return;
68
0
  }
69
70
1
  eval->HadError = true;
71
1
  if (eval->Quiet) {
72
0
    return;
73
0
  }
74
75
1
  cmGeneratorExpressionDAGChecker const* parent = this->Parent;
76
77
1
  if (parent && !parent->Parent) {
78
0
    eval->Context.LG->GetCMakeInstance()->IssueMessage(
79
0
      MessageType::FATAL_ERROR,
80
0
      cmStrCat("Error evaluating generator expression:\n"
81
0
               "  ",
82
0
               expr,
83
0
               "\n"
84
0
               "Self reference on target \"",
85
0
               eval->HeadTarget->GetName(), "\".\n"),
86
0
      parent->Backtrace);
87
0
    return;
88
0
  }
89
90
1
  {
91
1
    eval->Context.LG->GetCMakeInstance()->IssueMessage(
92
1
      MessageType::FATAL_ERROR,
93
1
      cmStrCat("Error evaluating generator expression:\n"
94
1
               "  ",
95
1
               expr,
96
1
               "\n"
97
1
               "Dependency loop found."),
98
1
      eval->Backtrace);
99
1
  }
100
101
1
  int loopStep = 1;
102
4
  while (parent) {
103
3
    eval->Context.LG->GetCMakeInstance()->IssueMessage(
104
3
      MessageType::FATAL_ERROR,
105
3
      cmStrCat("Loop step ", loopStep, "\n  ",
106
3
               parent->Content ? parent->Content->GetOriginalExpression()
107
3
                               : expr,
108
3
               '\n'),
109
3
      parent->Backtrace);
110
3
    parent = parent->Parent;
111
3
    ++loopStep;
112
3
  }
113
1
}
114
115
cmGeneratorExpressionDAGChecker::Result
116
cmGeneratorExpressionDAGChecker::CheckGraph() const
117
42.2k
{
118
42.2k
  cmGeneratorExpressionDAGChecker const* parent = this->Parent;
119
55.3k
  while (parent) {
120
13.1k
    if (this->Target == parent->Target && this->Property == parent->Property) {
121
32
      return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
122
32
    }
123
13.0k
    parent = parent->Parent;
124
13.0k
  }
125
42.2k
  return DAG;
126
42.2k
}
127
128
bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnly() const
129
738
{
130
738
  return this->Top->TransitivePropertiesOnly;
131
738
}
132
133
bool cmGeneratorExpressionDAGChecker::GetTransitivePropertiesOnlyCMP0131()
134
  const
135
8.52k
{
136
8.52k
  return this->Top->CMP0131;
137
8.52k
}
138
139
bool cmGeneratorExpressionDAGChecker::EvaluatingTransitiveProperty() const
140
42.2k
{
141
42.2k
  return this->TopIsTransitiveProperty;
142
42.2k
}
143
144
bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() const
145
2.43k
{
146
  // Corresponds to GenexEvaluator::EvaluateExpression.
147
2.43k
  return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
148
2.43k
    cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
149
2.43k
}
150
151
bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() const
152
2.43k
{
153
  // Corresponds to checkInterfacePropertyCompatibility's special case
154
  // that evaluates the value of POSITION_INDEPENDENT_CODE as a genex.
155
2.43k
  return this->Top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
156
2.43k
}
157
158
bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
159
631
{
160
631
  cm::string_view property(this->Top->Property);
161
162
631
  return property == "INCLUDE_DIRECTORIES"_s ||
163
630
    property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s ||
164
490
    property == "COMPILE_WRAPPERS"_s;
165
631
}
166
167
bool cmGeneratorExpressionDAGChecker::EvaluatingSources() const
168
2.86k
{
169
2.86k
  return this->Property == "SOURCES"_s ||
170
2.86k
    this->Property == "INTERFACE_SOURCES"_s;
171
2.86k
}
172
173
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
174
138
{
175
138
  cm::string_view property(this->Top->Property);
176
177
138
  return property == "LINK_DIRECTORIES"_s || property == "LINK_OPTIONS"_s ||
178
29
    property == "LINK_DEPENDS"_s || property == "LINK_LIBRARY_OVERRIDE"_s ||
179
29
    property == "LINKER_TYPE"_s || property == "LINK_WRAPPERS"_s;
180
138
}
181
182
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkOptionsExpression() const
183
18
{
184
18
  cm::string_view property(this->Top->Property);
185
186
18
  return property == "LINK_OPTIONS"_s || property == "LINKER_TYPE"_s;
187
18
}
188
189
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkerLauncher() const
190
2.44k
{
191
2.44k
  cm::string_view property(this->Top->Property);
192
193
2.44k
  return property.length() > cmStrLen("_LINKER_LAUNCHER") &&
194
1.38k
    property.substr(property.length() - cmStrLen("_LINKER_LAUNCHER")) ==
195
1.38k
    "_LINKER_LAUNCHER"_s;
196
2.44k
}
197
198
bool cmGeneratorExpressionDAGChecker::IsComputingLinkLibraries() const
199
29.4k
{
200
29.4k
  return this->Top->ComputingLinkLibraries_ == ComputingLinkLibraries::Yes;
201
29.4k
}
202
203
bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries(
204
  cmGeneratorTarget const* tgt, ForGenex genex) const
205
9.39k
{
206
9.39k
  auto const* top = this->Top;
207
208
9.39k
  cm::string_view prop(top->Property);
209
210
9.39k
  if (tgt) {
211
2.86k
    return top->Target == tgt && prop == "LINK_LIBRARIES"_s;
212
2.86k
  }
213
214
6.53k
  auto result = prop == "LINK_LIBRARIES"_s ||
215
1.78k
    prop == "INTERFACE_LINK_LIBRARIES"_s ||
216
928
    prop == "INTERFACE_LINK_LIBRARIES_DIRECT"_s ||
217
928
    prop == "LINK_INTERFACE_LIBRARIES"_s ||
218
928
    prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s ||
219
928
    cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") ||
220
928
    cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_");
221
222
6.53k
  return genex == ForGenex::LINK_LIBRARY || genex == ForGenex::LINK_GROUP
223
6.53k
    ? result
224
6.53k
    : (result || prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s);
225
9.39k
}
226
227
cmGeneratorTarget const* cmGeneratorExpressionDAGChecker::TopTarget() const
228
0
{
229
0
  return this->Top->Target;
230
0
}