mirror of
https://github.com/golang/go
synced 2024-11-18 14:54:40 -07:00
Revert "go/analysis: add pass to check for impossible interface-to-interface type assertions"
This reverts commit 7a72f3f8e9
.
Reason for revert: The 1.15 tree is not open yet.
Change-Id: I5b3e458748bb3d69950f6331672e8c883d6234fb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/219119
Run-TryBot: Andrew Bonventre <andybons@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
6822f1ada4
commit
11eff242d1
@ -1,13 +0,0 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The ifaceassert command runs the ifaceassert analyzer.
|
||||
package main
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/analysis/passes/ifaceassert"
|
||||
"golang.org/x/tools/go/analysis/singlechecker"
|
||||
)
|
||||
|
||||
func main() { singlechecker.Main(ifaceassert.Analyzer) }
|
@ -1,101 +0,0 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ifaceassert defines an Analyzer that flags
|
||||
// impossible interface-interface type assertions.
|
||||
package ifaceassert
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
)
|
||||
|
||||
const Doc = `detect impossible interface-to-interface type assertions
|
||||
|
||||
This checker flags type assertions v.(T) and corresponding type-switch cases
|
||||
in which the static type V of v is an interface that cannot possibly implement
|
||||
the target interface T. This occurs when V and T contain methods with the same
|
||||
name but different signatures. Example:
|
||||
|
||||
var v interface {
|
||||
Read()
|
||||
}
|
||||
_ = v.(io.Reader)
|
||||
|
||||
The Read method in v has a different signature than the Read method in
|
||||
io.Reader, so this assertion cannot succeed.
|
||||
`
|
||||
|
||||
var Analyzer = &analysis.Analyzer{
|
||||
Name: "ifaceassert",
|
||||
Doc: Doc,
|
||||
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||
Run: run,
|
||||
}
|
||||
|
||||
// assertableTo checks whether interface v can be asserted into t. It returns
|
||||
// nil on success, or the first conflicting method on failure.
|
||||
func assertableTo(v, t types.Type) *types.Func {
|
||||
// ensure that v and t are interfaces
|
||||
V, _ := v.Underlying().(*types.Interface)
|
||||
T, _ := t.Underlying().(*types.Interface)
|
||||
if V == nil || T == nil {
|
||||
return nil
|
||||
}
|
||||
if f, wrongType := types.MissingMethod(V, T, false); wrongType {
|
||||
return f
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func run(pass *analysis.Pass) (interface{}, error) {
|
||||
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||
nodeFilter := []ast.Node{
|
||||
(*ast.TypeAssertExpr)(nil),
|
||||
(*ast.TypeSwitchStmt)(nil),
|
||||
}
|
||||
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||
var (
|
||||
assert *ast.TypeAssertExpr // v.(T) expression
|
||||
targets []ast.Expr // interfaces T in v.(T)
|
||||
)
|
||||
switch n := n.(type) {
|
||||
case *ast.TypeAssertExpr:
|
||||
// take care of v.(type) in *ast.TypeSwitchStmt
|
||||
if n.Type == nil {
|
||||
return
|
||||
}
|
||||
assert = n
|
||||
targets = append(targets, n.Type)
|
||||
case *ast.TypeSwitchStmt:
|
||||
// retrieve type assertion from type switch's 'assign' field
|
||||
switch t := n.Assign.(type) {
|
||||
case *ast.ExprStmt:
|
||||
assert = t.X.(*ast.TypeAssertExpr)
|
||||
case *ast.AssignStmt:
|
||||
assert = t.Rhs[0].(*ast.TypeAssertExpr)
|
||||
}
|
||||
// gather target types from case clauses
|
||||
for _, c := range n.Body.List {
|
||||
targets = append(targets, c.(*ast.CaseClause).List...)
|
||||
}
|
||||
}
|
||||
V := pass.TypesInfo.TypeOf(assert.X)
|
||||
for _, target := range targets {
|
||||
T := pass.TypesInfo.TypeOf(target)
|
||||
if f := assertableTo(V, T); f != nil {
|
||||
pass.Reportf(
|
||||
target.Pos(),
|
||||
"impossible type assertion: no type can implement both %v and %v (conflicting types for %v method)",
|
||||
V, T, f.Name(),
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
return nil, nil
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ifaceassert_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/analysis/analysistest"
|
||||
"golang.org/x/tools/go/analysis/passes/ifaceassert"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
testdata := analysistest.TestData()
|
||||
analysistest.Run(t, testdata, ifaceassert.Analyzer, "a")
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file contains tests for the ifaceassert checker.
|
||||
|
||||
package a
|
||||
|
||||
import "io"
|
||||
|
||||
func InterfaceAssertionTest() {
|
||||
var (
|
||||
a io.ReadWriteSeeker
|
||||
b interface {
|
||||
Read()
|
||||
Write()
|
||||
}
|
||||
)
|
||||
_ = a.(io.Reader)
|
||||
_ = a.(io.ReadWriter)
|
||||
_ = b.(io.Reader) // want `^impossible type assertion: no type can implement both interface{Read\(\); Write\(\)} and io.Reader \(conflicting types for Read method\)$`
|
||||
_ = b.(interface { // want `^impossible type assertion: no type can implement both interface{Read\(\); Write\(\)} and interface{Read\(p \[\]byte\) \(n int, err error\)} \(conflicting types for Read method\)$`
|
||||
Read(p []byte) (n int, err error)
|
||||
})
|
||||
|
||||
switch a.(type) {
|
||||
case io.ReadWriter:
|
||||
case interface { // want `^impossible type assertion: no type can implement both io.ReadWriteSeeker and interface{Write\(\)} \(conflicting types for Write method\)$`
|
||||
Write()
|
||||
}:
|
||||
default:
|
||||
}
|
||||
|
||||
switch b := b.(type) {
|
||||
case io.ReadWriter, interface{ Read() }: // want `^impossible type assertion: no type can implement both interface{Read\(\); Write\(\)} and io.ReadWriter \(conflicting types for Read method\)$`
|
||||
case io.Writer: // want `^impossible type assertion: no type can implement both interface{Read\(\); Write\(\)} and io.Writer \(conflicting types for Write method\)$`
|
||||
default:
|
||||
_ = b
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user