|
4 | 4 | #![allow(non_upper_case_globals, dead_code)]
|
5 | 5 | #![deny(clippy::missing_docs_in_private_items)]
|
6 | 6 |
|
7 |
| -use crate::ir::context::BindgenContext; |
| 7 | +use crate::ir::context::{BindgenContext, IncludeLocation}; |
8 | 8 | use clang_sys::*;
|
9 | 9 | use std::cmp;
|
10 | 10 |
|
@@ -552,32 +552,145 @@ impl Cursor {
|
552 | 552 | return offset.cmp(&other_offset);
|
553 | 553 | }
|
554 | 554 |
|
555 |
| - // `None` here means `file`/`other_file` is the main header file. |
556 |
| - let include_location = ctx.included_file_location(&file); |
557 |
| - let other_include_location = ctx.included_file_location(&other_file); |
| 555 | + let mut include_location = ctx.included_file_location(&file); |
| 556 | + let mut other_include_location = |
| 557 | + ctx.included_file_location(&other_file); |
558 | 558 |
|
559 |
| - match (include_location, other_include_location) { |
560 |
| - // The main header file (`None`) comes after header passed as CLI argument (`Some((None, _))`). |
561 |
| - (None, Some((None, _))) => cmp::Ordering::Greater, |
562 |
| - (Some((None, _)), None) => cmp::Ordering::Less, |
563 |
| - // If an item was included in the same source file as the other item, |
564 |
| - // compare its `#include` location offset the offset of the other item. |
565 |
| - (Some((Some(file2), offset2)), _) if file2 == other_file => { |
566 |
| - offset2.cmp(&other_offset) |
567 |
| - } |
568 |
| - (_, Some((Some(other_file2), other_offset2))) |
569 |
| - if file == other_file2 => |
570 |
| - { |
571 |
| - offset.cmp(&other_offset2) |
572 |
| - } |
573 |
| - // If both items were included in the same file, compare the offset of their `#include` directives. |
574 |
| - (Some((file2, offset2)), Some((other_file2, other_offset2))) |
575 |
| - if file2 == other_file2 => |
576 |
| - { |
577 |
| - offset2.cmp(&other_offset2) |
| 559 | + use IncludeLocation::*; |
| 560 | + |
| 561 | + loop { |
| 562 | + match (&include_location, &other_include_location) { |
| 563 | + // Both items are in the main header file, this should already have been handled at this point. |
| 564 | + (Main, Main) => { |
| 565 | + unreachable!("Should have been handled at this point.") |
| 566 | + } |
| 567 | + // Headers passed as CLI arguments come before the main header file. |
| 568 | + (Main, Cli { .. }) => return cmp::Ordering::Greater, |
| 569 | + (Cli { .. }, Main) => return cmp::Ordering::Less, |
| 570 | + // If both were included via CLI arguments, compare their offset. |
| 571 | + ( |
| 572 | + Cli { offset: offset2 }, |
| 573 | + Cli { |
| 574 | + offset: other_offset2, |
| 575 | + }, |
| 576 | + ) => return offset2.cmp(&other_offset2), |
| 577 | + // If an item was included in the same source file as the other item, |
| 578 | + // compare its `#include` location offset the offset of the other item. |
| 579 | + ( |
| 580 | + File { |
| 581 | + file_name: ref file2, |
| 582 | + offset: offset2, |
| 583 | + }, |
| 584 | + Main, |
| 585 | + ) => { |
| 586 | + if *file2 == other_file { |
| 587 | + return offset2.cmp(&other_offset); |
| 588 | + } |
| 589 | + |
| 590 | + // Continue checking one level up. |
| 591 | + include_location = ctx.included_file_location(&file2); |
| 592 | + } |
| 593 | + ( |
| 594 | + Main, |
| 595 | + File { |
| 596 | + file_name: ref other_file2, |
| 597 | + offset: other_offset2, |
| 598 | + }, |
| 599 | + ) => { |
| 600 | + if file == *other_file2 { |
| 601 | + return offset.cmp(&other_offset2); |
| 602 | + } |
| 603 | + |
| 604 | + // Continue checking one level up. |
| 605 | + other_include_location = |
| 606 | + ctx.included_file_location(&other_file2); |
| 607 | + } |
| 608 | + ( |
| 609 | + File { |
| 610 | + file_name: file2, |
| 611 | + offset: offset2, |
| 612 | + }, |
| 613 | + File { |
| 614 | + file_name: other_file2, |
| 615 | + offset: other_offset2, |
| 616 | + }, |
| 617 | + ) => { |
| 618 | + // If both items were included in the same file, compare the offset of their `#include` directives. |
| 619 | + if file2 == other_file2 { |
| 620 | + return offset2.cmp(&other_offset2); |
| 621 | + } |
| 622 | + |
| 623 | + // Find the offset of where `file` is transivitely included in `ancestor_file`. |
| 624 | + let offset_in_ancestor = |
| 625 | + |mut file: String, ancestor_file: &str| { |
| 626 | + while file != ancestor_file { |
| 627 | + let mut include_location = |
| 628 | + ctx.included_file_location(&file); |
| 629 | + file = if let IncludeLocation::File { |
| 630 | + file_name: file, |
| 631 | + offset, |
| 632 | + } = include_location |
| 633 | + { |
| 634 | + if file == ancestor_file { |
| 635 | + return Some(offset); |
| 636 | + } |
| 637 | + |
| 638 | + file |
| 639 | + } else { |
| 640 | + break; |
| 641 | + } |
| 642 | + } |
| 643 | + |
| 644 | + None |
| 645 | + }; |
| 646 | + |
| 647 | + if let Some(offset2) = |
| 648 | + offset_in_ancestor(file2.clone(), &other_file2) |
| 649 | + { |
| 650 | + return offset2.cmp(&other_offset2); |
| 651 | + } |
| 652 | + |
| 653 | + if let Some(other_offset2) = |
| 654 | + offset_in_ancestor(other_file2.clone(), &file2) |
| 655 | + { |
| 656 | + return offset2.cmp(&other_offset2); |
| 657 | + } |
| 658 | + |
| 659 | + // Otherwise, go one level up. |
| 660 | + // |
| 661 | + // # Example |
| 662 | + // |
| 663 | + // a.h |
| 664 | + // ├── b.h |
| 665 | + // └── c.h |
| 666 | + // |
| 667 | + // When comparing items inside `b.h` and `c.h`, go up one level and |
| 668 | + // compare the include locations of `b.h` and `c.h` in `a.h` instead. |
| 669 | + include_location = ctx.included_file_location(file2); |
| 670 | + other_include_location = |
| 671 | + ctx.included_file_location(other_file2); |
| 672 | + } |
| 673 | + ( |
| 674 | + File { |
| 675 | + file_name: file2, .. |
| 676 | + }, |
| 677 | + Cli { .. }, |
| 678 | + ) => { |
| 679 | + // Continue checking one level up. |
| 680 | + include_location = ctx.included_file_location(&file2); |
| 681 | + } |
| 682 | + ( |
| 683 | + Cli { .. }, |
| 684 | + File { |
| 685 | + file_name: other_file2, |
| 686 | + .. |
| 687 | + }, |
| 688 | + ) => { |
| 689 | + // Continue checking one level up. |
| 690 | + other_include_location = |
| 691 | + ctx.included_file_location(&other_file2); |
| 692 | + } |
578 | 693 | }
|
579 |
| - // Otherwise, keep the original sorting. |
580 |
| - _ => cmp::Ordering::Equal, |
581 | 694 | }
|
582 | 695 | }
|
583 | 696 |
|
|
0 commit comments