OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/analyzer.h" | 5 #include "tools/gn/analyzer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <iterator> | 8 #include <iterator> |
9 #include <set> | 9 #include <set> |
10 #include <vector> | 10 #include <vector> |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 strings = GetStringVector(*dict, "files", &err); | 150 strings = GetStringVector(*dict, "files", &err); |
151 if (err.has_error()) | 151 if (err.has_error()) |
152 return err; | 152 return err; |
153 for (auto s : strings) { | 153 for (auto s : strings) { |
154 if (!IsPathSourceAbsolute(s) && !IsPathAbsolute(s)) | 154 if (!IsPathSourceAbsolute(s) && !IsPathAbsolute(s)) |
155 return Err(Location(), | 155 return Err(Location(), |
156 "\"" + s + "\" is not a source-absolute or absolute path."); | 156 "\"" + s + "\" is not a source-absolute or absolute path."); |
157 inputs->source_vec.push_back(SourceFile(s)); | 157 inputs->source_vec.push_back(SourceFile(s)); |
158 } | 158 } |
159 | 159 |
160 strings = GetStringVector(*dict, "compile_targets", &err); | 160 strings = GetStringVector(*dict, "additional_compile_targets", &err); |
161 if (err.has_error()) | 161 if (err.has_error()) |
162 return err; | 162 return err; |
163 | 163 |
164 inputs->compile_included_all = false; | 164 inputs->compile_included_all = false; |
165 for (auto& s : strings) { | 165 for (auto& s : strings) { |
166 if (s == "all") { | 166 if (s == "all") { |
167 inputs->compile_included_all = true; | 167 inputs->compile_included_all = true; |
168 } else { | 168 } else { |
169 inputs->compile_vec.push_back( | 169 inputs->compile_vec.push_back( |
170 AbsoluteOrSourceAbsoluteStringToLabel(default_toolchain, s, &err)); | 170 AbsoluteOrSourceAbsoluteStringToLabel(default_toolchain, s, &err)); |
(...skipping 15 matching lines...) Expand all Loading... |
186 for (auto& s : inputs->source_vec) | 186 for (auto& s : inputs->source_vec) |
187 inputs->source_files.insert(&s); | 187 inputs->source_files.insert(&s); |
188 for (auto& l : inputs->compile_vec) | 188 for (auto& l : inputs->compile_vec) |
189 inputs->compile_labels.insert(l); | 189 inputs->compile_labels.insert(l); |
190 for (auto& l : inputs->test_vec) | 190 for (auto& l : inputs->test_vec) |
191 inputs->test_labels.insert(l); | 191 inputs->test_labels.insert(l); |
192 return Err(); | 192 return Err(); |
193 } | 193 } |
194 | 194 |
195 std::string OutputsToJSON(const Outputs& outputs, | 195 std::string OutputsToJSON(const Outputs& outputs, |
196 const Label& default_toolchain) { | 196 const Label& default_toolchain, Err *err) { |
197 std::string output; | 197 std::string output; |
198 auto value = base::MakeUnique<base::DictionaryValue>(); | 198 auto value = base::MakeUnique<base::DictionaryValue>(); |
199 | 199 |
200 if (outputs.error.size()) { | 200 if (outputs.error.size()) { |
201 WriteString(*value, "error", outputs.error); | 201 WriteString(*value, "error", outputs.error); |
202 WriteLabels(default_toolchain, *value, "invalid_targets", | 202 WriteLabels(default_toolchain, *value, "invalid_targets", |
203 outputs.invalid_labels); | 203 outputs.invalid_labels); |
204 } else { | 204 } else { |
205 WriteString(*value, "status", outputs.status); | 205 WriteString(*value, "status", outputs.status); |
206 WriteLabels(default_toolchain, *value, "compile_targets", | 206 WriteLabels(default_toolchain, *value, "compile_targets", |
207 outputs.compile_labels); | 207 outputs.compile_labels); |
208 WriteLabels(default_toolchain, *value, "test_targets", outputs.test_labels); | 208 WriteLabels(default_toolchain, *value, "test_targets", outputs.test_labels); |
209 } | 209 } |
210 | 210 |
211 base::JSONWriter::Write(*value.get(), &output); | 211 if (!base::JSONWriter::Write(*value.get(), &output)) |
| 212 *err = Err(Location(), "Failed to marshal JSON value for output"); |
212 return output; | 213 return output; |
213 } | 214 } |
214 | 215 |
215 } // namespace | 216 } // namespace |
216 | 217 |
217 Analyzer::Analyzer(const Builder& builder) | 218 Analyzer::Analyzer(const Builder& builder) |
218 : all_targets_(builder.GetAllResolvedTargets()), | 219 : all_targets_(builder.GetAllResolvedTargets()), |
219 default_toolchain_(builder.loader()->GetDefaultToolchain()) { | 220 default_toolchain_(builder.loader()->GetDefaultToolchain()) { |
220 for (const auto* target : all_targets_) { | 221 for (const auto* target : all_targets_) { |
221 labels_to_targets_[target->label()] = target; | 222 labels_to_targets_[target->label()] = target; |
222 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) | 223 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) |
223 dep_map_.insert(std::make_pair(dep_pair.ptr, target)); | 224 dep_map_.insert(std::make_pair(dep_pair.ptr, target)); |
224 } | 225 } |
225 for (const auto* target : all_targets_) { | 226 for (const auto* target : all_targets_) { |
226 if (dep_map_.find(target) == dep_map_.end()) | 227 if (dep_map_.find(target) == dep_map_.end()) |
227 roots_.insert(target); | 228 roots_.insert(target); |
228 } | 229 } |
229 } | 230 } |
230 | 231 |
231 Analyzer::~Analyzer() {} | 232 Analyzer::~Analyzer() {} |
232 | 233 |
233 std::string Analyzer::Analyze(const std::string& input, Err* err) const { | 234 std::string Analyzer::Analyze(const std::string& input, Err* err) const { |
234 Inputs inputs; | 235 Inputs inputs; |
235 Outputs outputs; | 236 Outputs outputs; |
236 | 237 |
237 Err local_err = JSONToInputs(default_toolchain_, input, &inputs); | 238 Err local_err = JSONToInputs(default_toolchain_, input, &inputs); |
238 if (local_err.has_error()) { | 239 if (local_err.has_error()) { |
239 outputs.error = local_err.message(); | 240 outputs.error = local_err.message(); |
240 if (err) | 241 return OutputsToJSON(outputs, default_toolchain_, err); |
241 *err = Err(); | |
242 return ""; | |
243 } | 242 } |
244 | 243 |
245 LabelSet invalid_labels; | 244 LabelSet invalid_labels; |
246 for (const auto& label : InvalidLabels(inputs.compile_labels)) | 245 for (const auto& label : InvalidLabels(inputs.compile_labels)) |
247 invalid_labels.insert(label); | 246 invalid_labels.insert(label); |
248 for (const auto& label : InvalidLabels(inputs.test_labels)) | 247 for (const auto& label : InvalidLabels(inputs.test_labels)) |
249 invalid_labels.insert(label); | 248 invalid_labels.insert(label); |
250 if (!invalid_labels.empty()) { | 249 if (!invalid_labels.empty()) { |
251 outputs.error = "Invalid targets"; | 250 outputs.error = "Invalid targets"; |
252 outputs.invalid_labels = invalid_labels; | 251 outputs.invalid_labels = invalid_labels; |
253 if (err) | 252 return OutputsToJSON(outputs, default_toolchain_, err); |
254 *err = Err(); | |
255 return OutputsToJSON(outputs, default_toolchain_); | |
256 } | 253 } |
257 | 254 |
258 TargetSet affected_targets = AllAffectedTargets(inputs.source_files); | 255 TargetSet affected_targets = AllAffectedTargets(inputs.source_files); |
259 if (affected_targets.empty()) { | 256 if (affected_targets.empty()) { |
260 outputs.status = "No dependency"; | 257 outputs.status = "No dependency"; |
261 if (err) | 258 return OutputsToJSON(outputs, default_toolchain_, err); |
262 *err = Err(); | |
263 return OutputsToJSON(outputs, default_toolchain_); | |
264 } | 259 } |
265 | 260 |
266 // TODO: We can do smarter things when we detect changes to build files. | 261 // TODO: We can do smarter things when we detect changes to build files. |
267 // For example, if all of the ninja files are unchanged, we know that we | 262 // For example, if all of the ninja files are unchanged, we know that we |
268 // can ignore changes to these files. Also, for most .gn files, we can | 263 // can ignore changes to these files. Also, for most .gn files, we can |
269 // treat a change as simply affecting every target, config, or toolchain | 264 // treat a change as simply affecting every target, config, or toolchain |
270 // defined in that file. | 265 // defined in that file. |
271 if (AnyBuildFilesWereModified(inputs.source_files)) { | 266 if (AnyBuildFilesWereModified(inputs.source_files)) { |
272 outputs.status = "Found dependency (all)"; | 267 outputs.status = "Found dependency (all)"; |
273 outputs.compile_labels = inputs.compile_labels; | 268 outputs.compile_labels = inputs.compile_labels; |
274 outputs.test_labels = inputs.test_labels; | 269 outputs.test_labels = inputs.test_labels; |
275 if (err) | 270 return OutputsToJSON(outputs, default_toolchain_, err); |
276 *err = Err(); | |
277 return OutputsToJSON(outputs, default_toolchain_); | |
278 } | 271 } |
279 | 272 |
280 TargetSet compile_targets = TargetsFor(inputs.compile_labels); | 273 TargetSet compile_targets = TargetsFor(inputs.compile_labels); |
281 if (inputs.compile_included_all) { | 274 if (inputs.compile_included_all) { |
282 for (auto& root : roots_) | 275 for (auto& root : roots_) |
283 compile_targets.insert(root); | 276 compile_targets.insert(root); |
284 } | 277 } |
285 TargetSet filtered_targets = Filter(compile_targets); | 278 TargetSet filtered_targets = Filter(compile_targets); |
286 outputs.compile_labels = | 279 outputs.compile_labels = |
287 LabelsFor(Intersect(filtered_targets, affected_targets)); | 280 LabelsFor(Intersect(filtered_targets, affected_targets)); |
288 | 281 |
289 TargetSet test_targets = TargetsFor(inputs.test_labels); | 282 TargetSet test_targets = TargetsFor(inputs.test_labels); |
290 outputs.test_labels = LabelsFor(Intersect(test_targets, affected_targets)); | 283 outputs.test_labels = LabelsFor(Intersect(test_targets, affected_targets)); |
291 | 284 |
292 if (outputs.compile_labels.empty() && outputs.test_labels.empty()) | 285 if (outputs.compile_labels.empty() && outputs.test_labels.empty()) |
293 outputs.status = "No dependency"; | 286 outputs.status = "No dependency"; |
294 else | 287 else |
295 outputs.status = "Found dependency"; | 288 outputs.status = "Found dependency"; |
296 *err = Err(); | 289 return OutputsToJSON(outputs, default_toolchain_, err); |
297 return OutputsToJSON(outputs, default_toolchain_); | |
298 } | 290 } |
299 | 291 |
300 TargetSet Analyzer::AllAffectedTargets( | 292 TargetSet Analyzer::AllAffectedTargets( |
301 const SourceFileSet& source_files) const { | 293 const SourceFileSet& source_files) const { |
302 TargetSet direct_matches; | 294 TargetSet direct_matches; |
303 for (const auto& source_file : source_files) | 295 for (const auto& source_file : source_files) |
304 AddTargetsDirectlyReferringToFileTo(source_file, &direct_matches); | 296 AddTargetsDirectlyReferringToFileTo(source_file, &direct_matches); |
305 TargetSet all_matches; | 297 TargetSet all_matches; |
306 for (const auto& match : direct_matches) | 298 for (const auto& match : direct_matches) |
307 AddAllRefsTo(match, &all_matches); | 299 AddAllRefsTo(match, &all_matches); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 void Analyzer::AddAllRefsTo(const Target* target, TargetSet* results) const { | 388 void Analyzer::AddAllRefsTo(const Target* target, TargetSet* results) const { |
397 if (results->find(target) != results->end()) | 389 if (results->find(target) != results->end()) |
398 return; // Already found this target. | 390 return; // Already found this target. |
399 results->insert(target); | 391 results->insert(target); |
400 | 392 |
401 auto dep_begin = dep_map_.lower_bound(target); | 393 auto dep_begin = dep_map_.lower_bound(target); |
402 auto dep_end = dep_map_.upper_bound(target); | 394 auto dep_end = dep_map_.upper_bound(target); |
403 for (auto cur_dep = dep_begin; cur_dep != dep_end; cur_dep++) | 395 for (auto cur_dep = dep_begin; cur_dep != dep_end; cur_dep++) |
404 AddAllRefsTo(cur_dep->second, results); | 396 AddAllRefsTo(cur_dep->second, results); |
405 } | 397 } |
OLD | NEW |