Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(365)

Side by Side Diff: tools/gn/header_checker.cc

Issue 424133002: GN: (HeaderChecker) Allow any chain to forward direct dependent configs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: update comments in header Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/header_checker.h ('k') | tools/gn/header_checker_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/header_checker.h" 5 #include "tools/gn/header_checker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 // check it. It would be nice if we could give an error if this happens, but 267 // check it. It would be nice if we could give an error if this happens, but
268 // our include finder is too primitive and returns all includes, even if 268 // our include finder is too primitive and returns all includes, even if
269 // they're in a #if not executed in the current build. In that case, it's 269 // they're in a #if not executed in the current build. In that case, it's
270 // not unusual for the buildfiles to not specify that header at all. 270 // not unusual for the buildfiles to not specify that header at all.
271 FileMap::const_iterator found = file_map_.find(include_file); 271 FileMap::const_iterator found = file_map_.find(include_file);
272 if (found == file_map_.end()) 272 if (found == file_map_.end())
273 return true; 273 return true;
274 274
275 const TargetVector& targets = found->second; 275 const TargetVector& targets = found->second;
276 std::vector<const Target*> chain; // Prevent reallocating in the loop. 276 std::vector<const Target*> chain; // Prevent reallocating in the loop.
277 bool direct_dependent_configs_apply = false;
277 278
278 // For all targets containing this file, we require that at least one be 279 // For all targets containing this file, we require that at least one be
279 // a dependency of the current target, and all targets that are dependencies 280 // a dependency of the current target, and all targets that are dependencies
280 // must have the file listed in the public section. 281 // must have the file listed in the public section.
281 bool found_dependency = false; 282 bool found_dependency = false;
282 for (size_t i = 0; i < targets.size(); i++) { 283 for (size_t i = 0; i < targets.size(); i++) {
283 // We always allow source files in a target to include headers also in that 284 // We always allow source files in a target to include headers also in that
284 // target. 285 // target.
285 const Target* to_target = targets[i].target; 286 const Target* to_target = targets[i].target;
286 if (to_target == from_target) 287 if (to_target == from_target)
287 return true; 288 return true;
288 289
289 if (IsDependencyOf(to_target, from_target, &chain)) { 290 bool has_direct_dependent_compiler_settings =
291 HasDirectDependentCompilerSettings(to_target);
292 if (IsDependencyOf(to_target,
293 from_target,
294 has_direct_dependent_compiler_settings,
295 &chain,
296 &direct_dependent_configs_apply)) {
290 DCHECK(chain.size() >= 2); 297 DCHECK(chain.size() >= 2);
291 DCHECK(chain[0] == to_target); 298 DCHECK(chain[0] == to_target);
292 DCHECK(chain[chain.size() - 1] == from_target); 299 DCHECK(chain[chain.size() - 1] == from_target);
293 300
294 // The include is in a target that's a proper dependency. Verify that 301 // The include is in a target that's a proper dependency. Verify that
295 // the including target has visibility. 302 // the including target has visibility.
296 if (!to_target->visibility().CanSeeMe(from_target->label())) { 303 if (!to_target->visibility().CanSeeMe(from_target->label())) {
297 std::string msg = "The included file is in " + 304 std::string msg = "The included file is in " +
298 to_target->label().GetUserVisibleName(false) + 305 to_target->label().GetUserVisibleName(false) +
299 "\nwhich is not visible from " + 306 "\nwhich is not visible from " +
(...skipping 11 matching lines...) Expand all
311 // Danger: must call CreatePersistentRange to put in Err. 318 // Danger: must call CreatePersistentRange to put in Err.
312 *err = Err(CreatePersistentRange(source_file, range), 319 *err = Err(CreatePersistentRange(source_file, range),
313 "Including a private header.", 320 "Including a private header.",
314 "This file is private to the target " + 321 "This file is private to the target " +
315 targets[i].target->label().GetUserVisibleName(false)); 322 targets[i].target->label().GetUserVisibleName(false));
316 return false; 323 return false;
317 } 324 }
318 325
319 // If the to_target has direct_dependent_configs, they must apply to the 326 // If the to_target has direct_dependent_configs, they must apply to the
320 // from_target. 327 // from_target.
321 if (HasDirectDependentCompilerSettings(to_target)) { 328 if (has_direct_dependent_compiler_settings &&
322 size_t problematic_index; 329 !direct_dependent_configs_apply) {
323 if (!DoDirectDependentConfigsApply(chain, &problematic_index)) { 330 size_t problematic_index = GetDependentConfigChainProblemIndex(chain);
331 if (!direct_dependent_configs_apply) {
324 *err = Err(CreatePersistentRange(source_file, range), 332 *err = Err(CreatePersistentRange(source_file, range),
325 "Can't include this header from here.", 333 "Can't include this header from here.",
326 GetDependentConfigChainError(chain, problematic_index)); 334 GetDependentConfigChainError(chain, problematic_index));
327 return false; 335 return false;
328 } 336 }
329 } 337 }
330 338
331 found_dependency = true; 339 found_dependency = true;
332 } 340 }
333 } 341 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 // 374 //
367 // - Save the includes found in each file and actually compute the graph of 375 // - Save the includes found in each file and actually compute the graph of
368 // includes to detect when A implicitly includes C's header. This will not 376 // includes to detect when A implicitly includes C's header. This will not
369 // have the annoying false positive problem, but is complex to write. 377 // have the annoying false positive problem, but is complex to write.
370 378
371 return true; 379 return true;
372 } 380 }
373 381
374 bool HeaderChecker::IsDependencyOf(const Target* search_for, 382 bool HeaderChecker::IsDependencyOf(const Target* search_for,
375 const Target* search_from, 383 const Target* search_from,
376 std::vector<const Target*>* chain) const { 384 bool prefer_direct_dependent_configs,
377 std::set<const Target*> checked; 385 std::vector<const Target*>* chain,
378 return IsDependencyOf(search_for, search_from, chain, &checked); 386 bool* direct_dependent_configs_apply) const {
387 if (search_for == search_from)
388 return false;
389
390 // Find the shortest path that forwards dependent configs, if one exists.
391 if (prefer_direct_dependent_configs &&
392 IsDependencyOf(search_for, search_from, true, chain)) {
393 if (direct_dependent_configs_apply)
394 *direct_dependent_configs_apply = true;
395 return true;
396 }
397
398 // If not, try to find any dependency path at all.
399 if (IsDependencyOf(search_for, search_from, false, chain)) {
400 if (direct_dependent_configs_apply)
401 *direct_dependent_configs_apply = false;
402 return true;
403 }
404
405 return false;
379 } 406 }
380 407
381 bool HeaderChecker::IsDependencyOf(const Target* search_for, 408 bool HeaderChecker::IsDependencyOf(const Target* search_for,
382 const Target* search_from, 409 const Target* search_from,
383 std::vector<const Target*>* chain, 410 bool requires_dependent_configs,
384 std::set<const Target*>* checked) const { 411 std::vector<const Target*>* chain) const {
385 if (checked->find(search_for) != checked->end()) 412 // This maps targets to the target which receives dependent configs from it.
brettw 2014/07/31 20:50:49 I'm a bit confused about this function. Rather tha
jbroman 2014/07/31 22:05:37 It maps targets to their predecessor in a shortest
386 return false; // Already checked this subtree. 413 std::map<const Target*, const Target*> breadcrumbs;
414 std::queue<const Target*> work_queue;
415 breadcrumbs.insert(std::make_pair(
416 search_from, static_cast<const Target*>(NULL)));
brettw 2014/07/31 20:50:49 I see you add this to make the reconstruction step
jbroman 2014/07/31 22:05:37 It's unnecessarily clever. I can just make getting
417 work_queue.push(search_from);
387 418
388 const LabelTargetVector& deps = search_from->deps(); 419 while (!work_queue.empty()) {
389 for (size_t i = 0; i < deps.size(); i++) { 420 const Target* target = work_queue.front();
390 if (deps[i].ptr == search_for) { 421 work_queue.pop();
391 // Found it. 422
423 if (target == search_for) {
424 // Found it! Reconstruct the chain.
392 chain->clear(); 425 chain->clear();
393 chain->push_back(deps[i].ptr); 426 while (target) {
394 chain->push_back(search_from); 427 chain->push_back(target);
428 target = breadcrumbs[target];
429 }
395 return true; 430 return true;
396 } 431 }
397 432
398 // Recursive search. 433 // All deps of a group implicitly forward dependent configs.
399 checked->insert(deps[i].ptr); 434 bool uses_all_deps = !requires_dependent_configs ||
400 if (IsDependencyOf(search_for, deps[i].ptr, chain, checked)) { 435 target == search_from ||
401 chain->push_back(search_from); 436 target->output_type() == Target::GROUP;
402 return true; 437
438 const LabelTargetVector& deps = uses_all_deps ? target->deps() :
439 target->forward_dependent_configs();
440 for (size_t i = 0; i < deps.size(); i++) {
441 bool seeing_for_first_time = breadcrumbs.insert(
442 std::make_pair(deps[i].ptr, target)).second;
443 if (seeing_for_first_time)
444 work_queue.push(deps[i].ptr);
403 } 445 }
404 } 446 }
405 447
406 return false; 448 return false;
407 } 449 }
408 450
409 // static 451 // static
410 bool HeaderChecker::DoDirectDependentConfigsApply( 452 size_t HeaderChecker::GetDependentConfigChainProblemIndex(
411 const std::vector<const Target*>& chain, 453 const std::vector<const Target*>& chain)
412 size_t* problematic_index) { 454 {
413 // Direct dependent configs go up the chain one level with the following 455 // Direct dependent configs go up the chain one level with the following
414 // exceptions: 456 // exceptions:
415 // - Skip over groups 457 // - Skip over groups
416 // - Skip anything that explicitly forwards it 458 // - Skip anything that explicitly forwards it
417 459
418 // All chains should be at least two (or it wouldn't be a chain). 460 // Chains of length less than three have no problems.
419 DCHECK(chain.size() >= 2); 461 // These should have been filtered out earlier.
462 DCHECK(chain.size() >= 3);
420 463
421 // A chain of length 2 is always OK as far as direct dependent configs are
422 // concerned since the targets are direct dependents.
423 if (chain.size() == 2)
424 return true;
425
426 // Check the middle configs to make sure they're either groups or configs
427 // are forwarded.
428 for (size_t i = 1; i < chain.size() - 1; i++) { 464 for (size_t i = 1; i < chain.size() - 1; i++) {
429 if (chain[i]->output_type() == Target::GROUP) 465 if (chain[i]->output_type() == Target::GROUP)
430 continue; // This one is OK, skip to next one. 466 continue; // This one is OK, skip to next one.
431 467
432 // The forward list on this target should have contained in it the target 468 // The forward list on this target should have contained in it the target
433 // at the next lower level. 469 // at the next lower level.
434 const LabelTargetVector& forwarded = chain[i]->forward_dependent_configs(); 470 const LabelTargetVector& forwarded = chain[i]->forward_dependent_configs();
435 if (std::find_if(forwarded.begin(), forwarded.end(), 471 if (std::find_if(forwarded.begin(), forwarded.end(),
436 LabelPtrPtrEquals<Target>(chain[i - 1])) == 472 LabelPtrPtrEquals<Target>(chain[i - 1])) ==
437 forwarded.end()) { 473 forwarded.end())
438 *problematic_index = i; 474 return i;
439 return false;
440 }
441 } 475 }
442 476
443 return true; 477 CHECK(false) << "Unable to diagnose dependent config chain problem.";
478 return 0;
444 } 479 }
OLDNEW
« no previous file with comments | « tools/gn/header_checker.h ('k') | tools/gn/header_checker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698