Skip to content

Commit 68c1c4d

Browse files
committed
SA1019: simplify rules for deprecated standard library API
In the past, we made use of the AlternativeAvailableSince field. If a function was deprecated in Go 1.6 and an alternative had been available in Go 1.0, then we'd recommend using the alternative even if targeting Go 1.2. The idea was to suggest writing future-proof code by using already-existing alternatives. This had a major flaw, however: the user would need to use at least Go 1.6 for Staticcheck to know that the function had been deprecated. Thus, targeting Go 1.2 and using Go 1.2 would behave differently from targeting Go 1.2 and using Go 1.6. This is especially a problem if the user tries to ignore the warning. Depending on the Go version in use, the ignore directive may or may not match, causing a warning of its own. To avoid this issue, we no longer try to be smart. We now only compare the targeted version against the version that deprecated an object. Closes: gh-1318 (cherry picked from commit 6422635)
1 parent e40dea5 commit 68c1c4d

File tree

3 files changed

+26
-30
lines changed

3 files changed

+26
-30
lines changed

staticcheck/lint.go

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3095,32 +3095,25 @@ func CheckDeprecated(pass *analysis.Pass) (interface{}, error) {
30953095
return
30963096
}
30973097
if ok {
3098-
switch std.AlternativeAvailableSince {
3099-
case knowledge.DeprecatedNeverUse:
3100-
// This should never be used, regardless of the
3101-
// targeted Go version. Examples include insecure
3102-
// cryptography or inherently broken APIs.
3103-
//
3104-
// We always want to flag these.
3105-
case knowledge.DeprecatedUseNoLonger:
3106-
// This should no longer be used. Using it with
3107-
// older Go versions might still make sense.
3108-
if !code.IsGoVersion(pass, std.DeprecatedSince) {
3109-
return
3110-
}
3111-
default:
3112-
if std.AlternativeAvailableSince < 0 {
3113-
panic(fmt.Sprintf("unhandled case %d", std.AlternativeAvailableSince))
3114-
}
3115-
// Look for the first available alternative, not the first
3116-
// version something was deprecated in. If a function was
3117-
// deprecated in Go 1.6, an alternative has been available
3118-
// already in 1.0, and we're targeting 1.2, it still
3119-
// makes sense to use the alternative from 1.0, to be
3120-
// future-proof.
3121-
if !code.IsGoVersion(pass, std.AlternativeAvailableSince) {
3122-
return
3123-
}
3098+
// In the past, we made use of the AlternativeAvailableSince field. If a function was deprecated in Go
3099+
// 1.6 and an alternative had been available in Go 1.0, then we'd recommend using the alternative even
3100+
// if targeting Go 1.2. The idea was to suggest writing future-proof code by using already-existing
3101+
// alternatives. This had a major flaw, however: the user would need to use at least Go 1.6 for
3102+
// Staticcheck to know that the function had been deprecated. Thus, targeting Go 1.2 and using Go 1.2
3103+
// would behave differently from targeting Go 1.2 and using Go 1.6. This is especially a problem if the
3104+
// user tries to ignore the warning. Depending on the Go version in use, the ignore directive may or may
3105+
// not match, causing a warning of its own.
3106+
//
3107+
// To avoid this issue, we no longer try to be smart. We now only compare the targeted version against
3108+
// the version that deprecated an object.
3109+
//
3110+
// Unfortunately, this issue also applies to AlternativeAvailableSince == DeprecatedNeverUse. Even though it
3111+
// is only applied to seriously flawed API, such as broken cryptography, users may wish to ignore those
3112+
// warnings.
3113+
//
3114+
// See also https://staticcheck.io/issues/1318.
3115+
if !code.IsGoVersion(pass, std.DeprecatedSince) {
3116+
return
31243117
}
31253118
}
31263119

staticcheck/testdata/src/example.com/CheckDeprecated_go13/CheckDeprecated.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77
)
88

99
func fn() {
10-
filepath.HasPrefix("", "") //@ diag(`filepath.HasPrefix has been deprecated since Go 1.0 because it shouldn't be used:`)
11-
_ = httputil.ErrPersistEOF //@ diag(`httputil.ErrPersistEOF has been deprecated since Go 1.0:`)
12-
_ = httputil.ServerConn{} //@ diag(`httputil.ServerConn has been deprecated since Go 1.0:`)
13-
_ = x509.CertificateRequest{}.Attributes //@ diag(`x509.CertificateRequest{}.Attributes has been deprecated since Go 1.5 and an alternative has been available since Go 1.3:`)
10+
filepath.HasPrefix("", "") //@ diag(`filepath.HasPrefix has been deprecated since Go 1.0 because it shouldn't be used:`)
11+
_ = httputil.ErrPersistEOF //@ diag(`httputil.ErrPersistEOF has been deprecated since Go 1.0:`)
12+
_ = httputil.ServerConn{} //@ diag(`httputil.ServerConn has been deprecated since Go 1.0:`)
13+
_ = x509.CertificateRequest{}.Attributes
1414
}

staticcheck/testdata/src/example.com/CheckDeprecated_go18/CheckDeprecated.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package pkg
22

33
import (
44
"compress/flate"
5+
"crypto/x509"
56
"database/sql/driver"
67
"net/http"
78
"os"
@@ -29,6 +30,8 @@ func fn1(err error) {
2930

3031
var conn driver.Conn
3132
conn.Begin() //@ diag(`Begin has been deprecated`)
33+
34+
_ = x509.CertificateRequest{}.Attributes //@ diag(`x509.CertificateRequest{}.Attributes has been deprecated since Go 1.5 and an alternative has been available since Go 1.3:`)
3235
}
3336

3437
// Deprecated: Don't use this.

0 commit comments

Comments
 (0)