@@ -655,205 +655,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
655
655
headers
656
656
}
657
657
658
- <<<<<<< HEAD:src/tools/clippy/clippy_lints/src/doc/mod.rs
659
- =======
660
- fn check_link_quotes(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
661
- if trimmed_text.starts_with('\'')
662
- && trimmed_text.ends_with('\'')
663
- && let Some(span) = fragments.span(cx, range)
664
- {
665
- span_lint(
666
- cx,
667
- DOC_LINK_WITH_QUOTES,
668
- span,
669
- "possible intra-doc link using quotes instead of backticks",
670
- );
671
- }
672
- }
673
-
674
- fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) {
675
- fn has_needless_main(code: String, edition: Edition) -> bool {
676
- rustc_driver::catch_fatal_errors(|| {
677
- rustc_span::create_session_globals_then(edition, || {
678
- let filename = FileName::anon_source_code(&code);
679
-
680
- let fallback_bundle =
681
- rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
682
- let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
683
- let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
684
- #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler
685
- let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
686
- let sess = ParseSess::with_span_handler(handler, sm);
687
-
688
- let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
689
- Ok(p) => p,
690
- Err(errs) => {
691
- drop(errs);
692
- return false;
693
- },
694
- };
695
-
696
- let mut relevant_main_found = false;
697
- loop {
698
- match parser.parse_item(ForceCollect::No) {
699
- Ok(Some(item)) => match &item.kind {
700
- ItemKind::Fn(box Fn {
701
- sig, body: Some(block), ..
702
- }) if item.ident.name == sym::main => {
703
- let is_async = sig.header.coro_kind.map_or(false, |coro| coro.is_async());
704
- let returns_nothing = match &sig.decl.output {
705
- FnRetTy::Default(..) => true,
706
- FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
707
- FnRetTy::Ty(_) => false,
708
- };
709
-
710
- if returns_nothing && !is_async && !block.stmts.is_empty() {
711
- // This main function should be linted, but only if there are no other functions
712
- relevant_main_found = true;
713
- } else {
714
- // This main function should not be linted, we're done
715
- return false;
716
- }
717
- },
718
- // Tests with one of these items are ignored
719
- ItemKind::Static(..)
720
- | ItemKind::Const(..)
721
- | ItemKind::ExternCrate(..)
722
- | ItemKind::ForeignMod(..)
723
- // Another function was found; this case is ignored
724
- | ItemKind::Fn(..) => return false,
725
- _ => {},
726
- },
727
- Ok(None) => break,
728
- Err(e) => {
729
- e.cancel();
730
- return false;
731
- },
732
- }
733
- }
734
-
735
- relevant_main_found
736
- })
737
- })
738
- .ok()
739
- .unwrap_or_default()
740
- }
741
-
742
- let trailing_whitespace = text.len() - text.trim_end().len();
743
-
744
- // Because of the global session, we need to create a new session in a different thread with
745
- // the edition we need.
746
- let text = text.to_owned();
747
- if thread::spawn(move || has_needless_main(text, edition))
748
- .join()
749
- .expect("thread::spawn failed")
750
- && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
751
- {
752
- span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
753
- }
754
- }
755
-
756
- fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
757
- for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
758
- // Trim punctuation as in `some comment (see foo::bar).`
759
- // ^^
760
- // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
761
- let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
762
-
763
- // Remove leading or trailing single `:` which may be part of a sentence.
764
- if word.starts_with(':') && !word.starts_with("::") {
765
- word = word.trim_start_matches(':');
766
- }
767
- if word.ends_with(':') && !word.ends_with("::") {
768
- word = word.trim_end_matches(':');
769
- }
770
-
771
- if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
772
- continue;
773
- }
774
-
775
- // Adjust for the current word
776
- let offset = word.as_ptr() as usize - text.as_ptr() as usize;
777
- let span = Span::new(
778
- span.lo() + BytePos::from_usize(offset),
779
- span.lo() + BytePos::from_usize(offset + word.len()),
780
- span.ctxt(),
781
- span.parent(),
782
- );
783
-
784
- check_word(cx, word, span);
785
- }
786
- }
787
-
788
- fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
789
- /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
790
- /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
791
- /// letter (`NASA` is ok).
792
- /// Plurals are also excluded (`IDs` is ok).
793
- fn is_camel_case(s: &str) -> bool {
794
- if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) {
795
- return false;
796
- }
797
-
798
- let s = s.strip_suffix('s').unwrap_or(s);
799
-
800
- s.chars().all(char::is_alphanumeric)
801
- && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
802
- && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
803
- }
804
-
805
- fn has_underscore(s: &str) -> bool {
806
- s != "_" && !s.contains("\\_") && s.contains('_')
807
- }
808
-
809
- fn has_hyphen(s: &str) -> bool {
810
- s != "-" && s.contains('-')
811
- }
812
-
813
- if let Ok(url) = Url::parse(word) {
814
- // try to get around the fact that `foo::bar` parses as a valid URL
815
- if !url.cannot_be_a_base() {
816
- span_lint(
817
- cx,
818
- DOC_MARKDOWN,
819
- span,
820
- "you should put bare URLs between `<`/`>` or make a proper Markdown link",
821
- );
822
-
823
- return;
824
- }
825
- }
826
-
827
- // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
828
- if has_underscore(word) && has_hyphen(word) {
829
- return;
830
- }
831
-
832
- if has_underscore(word) || word.contains("::") || is_camel_case(word) {
833
- let mut applicability = Applicability::MachineApplicable;
834
-
835
- span_lint_and_then(
836
- cx,
837
- DOC_MARKDOWN,
838
- span,
839
- "item in documentation is missing backticks",
840
- |diag| {
841
- let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
842
- diag.span_suggestion_with_style(
843
- span,
844
- "try",
845
- format!("`{snippet}`"),
846
- applicability,
847
- // always show the suggestion in a separate line, since the
848
- // inline presentation adds another pair of backticks
849
- SuggestionStyle::ShowAlways,
850
- );
851
- },
852
- );
853
- }
854
- }
855
-
856
- >>>>>>> d116f1718f1 (Merge Async and Gen into CoroutineKind):src/tools/clippy/clippy_lints/src/doc.rs
857
658
struct FindPanicUnwrap<'a, 'tcx> {
858
659
cx: &'a LateContext<'tcx>,
859
660
panic_span: Option<Span>,
0 commit comments