@@ -157,6 +157,9 @@ func parseRustImportsFast(sourceCode []byte) ([]RustImport, bool) {
157157 continue
158158 }
159159 if c == '\'' {
160+ if isRustLifetimeStart (sourceCode , i ) && ! looksLikeRustCharLiteralStart (sourceCode , i ) {
161+ continue
162+ }
160163 inChar = true
161164 continue
162165 }
@@ -441,6 +444,9 @@ func sanitizeRustSourceForPathMatching(sourceCode []byte) []byte {
441444 continue
442445 }
443446 if c == '\'' {
447+ if isRustLifetimeStart (sourceCode , i ) && ! looksLikeRustCharLiteralStart (sourceCode , i ) {
448+ continue
449+ }
444450 cleaned [i ] = ' '
445451 inChar = true
446452 continue
@@ -496,138 +502,53 @@ func isRustIdentChar(c byte) bool {
496502 return c == '_' || (c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || (c >= '0' && c <= '9' )
497503}
498504
499- func dedupeRustImports (imports []RustImport ) []RustImport {
500- if len (imports ) == 0 {
501- return nil
502- }
503- seen := make (map [RustImport ]bool , len (imports ))
504- result := make ([]RustImport , 0 , len (imports ))
505- for _ , imp := range imports {
506- if imp .Path == "" {
507- continue
508- }
509- if seen [imp ] {
510- continue
511- }
512- seen [imp ] = true
513- result = append (result , imp )
514- }
515- return result
516- }
517-
518- func parseTopLevelRustImportStatement (stmt string ) (RustImport , bool ) {
519- s := strings .TrimSpace (stmt )
520- if s == "" {
521- return RustImport {}, false
522- }
523- s = stripLeadingRustAttributes (s )
524- if s == "" {
525- return RustImport {}, false
505+ func isRustLifetimeStart (source []byte , idx int ) bool {
506+ if idx + 1 >= len (source ) || ! isRustIdentChar (source [idx + 1 ]) {
507+ return false
526508 }
527509
528- s = stripRustVisibilityPrefix (s )
529- switch {
530- case strings .HasPrefix (s , "use " ):
531- path := normalizeUsePath (strings .TrimSpace (strings .TrimPrefix (s , "use " )))
532- if path == "" {
533- return RustImport {}, false
534- }
535- return RustImport {Path : path , Kind : RustImportUse }, true
536- case strings .HasPrefix (s , "extern crate " ):
537- name := leadingRustIdent (strings .TrimSpace (strings .TrimPrefix (s , "extern crate " )))
538- if name == "" {
539- return RustImport {}, false
540- }
541- return RustImport {Path : name , Kind : RustImportExternCrate }, true
542- case strings .HasPrefix (s , "mod " ):
543- name := leadingRustIdent (strings .TrimSpace (strings .TrimPrefix (s , "mod " )))
544- if name == "" {
545- return RustImport {}, false
546- }
547- return RustImport {Path : name , Kind : RustImportModDecl }, true
510+ prev := previousNonWhitespaceByte (source , idx )
511+ switch prev {
512+ case '&' , '<' , '>' , ',' , ':' , '+' , '(' :
513+ return true
548514 default :
549- return RustImport {}, false
550- }
551- }
552-
553- func stripLeadingRustAttributes (s string ) string {
554- trimmed := strings .TrimSpace (s )
555- for strings .HasPrefix (trimmed , "#[" ) || strings .HasPrefix (trimmed , "#![" ) {
556- open := strings .Index (trimmed , "[" )
557- if open < 0 {
558- return trimmed
559- }
560- level := 0
561- end := - 1
562- for i := open ; i < len (trimmed ); i ++ {
563- switch trimmed [i ] {
564- case '[' :
565- level ++
566- case ']' :
567- level --
568- if level == 0 {
569- end = i
570- break
571- }
572- }
573- }
574- if end < 0 {
575- return trimmed
576- }
577- trimmed = strings .TrimSpace (trimmed [end + 1 :])
515+ return false
578516 }
579- return trimmed
580517}
581518
582- func stripRustVisibilityPrefix (s string ) string {
583- trimmed := strings .TrimSpace (s )
584- if strings .HasPrefix (trimmed , "pub " ) {
585- return strings .TrimSpace (strings .TrimPrefix (trimmed , "pub " ))
586- }
587- if strings .HasPrefix (trimmed , "pub(" ) {
588- if idx := strings .Index (trimmed , ")" ); idx >= 0 {
589- return strings .TrimSpace (trimmed [idx + 1 :])
519+ func previousNonWhitespaceByte (source []byte , idx int ) byte {
520+ for i := idx - 1 ; i >= 0 ; i -- {
521+ if ! isRustWhitespace (source [i ]) {
522+ return source [i ]
590523 }
591524 }
592- return trimmed
525+ return 0
593526}
594527
595- func normalizeUsePath (expr string ) string {
596- path := strings .TrimSpace (expr )
597- if path == "" {
598- return ""
599- }
600- if idx := strings .Index (path , " as " ); idx >= 0 {
601- path = strings .TrimSpace (path [:idx ])
602- }
603- if idx := strings .Index (path , "{" ); idx >= 0 {
604- path = strings .TrimSpace (path [:idx ])
605- }
606- for strings .HasSuffix (path , "::" ) {
607- path = strings .TrimSuffix (path , "::" )
608- path = strings .TrimSpace (path )
528+ func looksLikeRustCharLiteralStart (source []byte , idx int ) bool {
529+ if idx + 2 < len (source ) && source [idx + 2 ] == '\'' {
530+ return true
609531 }
610- path = strings .TrimPrefix (path , "::" )
611- return strings .TrimSpace (path )
532+ return idx + 3 < len (source ) && source [idx + 1 ] == '\\' && source [idx + 3 ] == '\''
612533}
613534
614- func leadingRustIdent ( s string ) string {
615- if s == "" {
616- return ""
535+ func dedupeRustImports ( imports [] RustImport ) [] RustImport {
536+ if len ( imports ) == 0 {
537+ return nil
617538 }
618- i := 0
619- for i < len (s ) {
620- c := s [i ]
621- if c == '_' || (c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || (i > 0 && c >= '0' && c <= '9' ) {
622- i ++
539+ seen := make (map [RustImport ]bool , len (imports ))
540+ result := make ([]RustImport , 0 , len (imports ))
541+ for _ , imp := range imports {
542+ if imp .Path == "" {
623543 continue
624544 }
625- break
626- }
627- if i == 0 {
628- return ""
545+ if seen [imp ] {
546+ continue
547+ }
548+ seen [imp ] = true
549+ result = append (result , imp )
629550 }
630- return s [: i ]
551+ return result
631552}
632553
633554func extractImports (rootNode * sitter.Node , sourceCode []byte ) []RustImport {
0 commit comments