Skip to content

Combine checks and trims with CutPrefix or CutSuffix Has Fix ​

Description ​

Since Go 1.20, strings.CutPrefix and strings.CutSuffix return both the remaining string and whether the affix matched. This rule replaces an adjacent check and trim only when they use the same simple value and affix. It also skips bodies containing ok, because the fix introduces that name in the if initializer.

The rule assumes strings is the standard-library package imported under its canonical name and does not add the import.

YAML ​

yaml
id: use-strings-cut-prefix-suffix
language: Go
severity: hint
message: Combine an affix check and trim with strings.CutPrefix or strings.CutSuffix.
rule:
  all:
    - pattern:
        context: |
          func f() {
            if $_CHECK($$$CHECK_ARGS) {
              $REST := $TRIM_CALL
              $$$BODY
            }
          }
        selector: if_statement
    - any:
        - pattern:
            context: |
              func f() {
                if strings.HasPrefix($VALUE, $AFFIX) {
                  $REST := strings.TrimPrefix($VALUE, $AFFIX)
                  $$$BODY
                }
              }
            selector: if_statement
        - pattern:
            context: |
              func f() {
                if strings.HasSuffix($VALUE, $AFFIX) {
                  $REST := strings.TrimSuffix($VALUE, $AFFIX)
                  $$$BODY
                }
              }
            selector: if_statement
    - not:
        regex: '\bok\b'
constraints:
  VALUE:
    kind: identifier
  AFFIX:
    any:
      - kind: identifier
      - kind: interpreted_string_literal
      - kind: raw_string_literal
transform:
  CUT_CALL:
    replace:
      source: $TRIM_CALL
      replace: '^strings\.Trim'
      by: strings.Cut
fix: |-
  if $REST, ok := $CUT_CALL; ok {
    $$$BODY
  }

Example ​

go
import "strings"

func inspect(name string) {
  if strings.HasPrefix(name, "log:") {
    value := strings.TrimPrefix(name, "log:")
    use(value)
  }
  if strings.HasSuffix(name, ".tmp") {
    value := strings.TrimSuffix(name, ".tmp")
    use(value)
  }
}

Diff ​

go
import "strings"

func inspect(name string) {
  if strings.HasPrefix(name, "log:") { 
    value := strings.TrimPrefix(name, "log:") 
  if value, ok := strings.CutPrefix(name, "log:"); ok { 
    use(value)
  }
  if strings.HasSuffix(name, ".tmp") { 
    value := strings.TrimSuffix(name, ".tmp") 
  if value, ok := strings.CutSuffix(name, ".tmp"); ok { 
    use(value)
  }
}

Credits ​

Based on JetBrains' Go Modern Guidelines.

Made with ❤️ with Rust