]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/vet: do not import net/http at startup
authorRuss Cox <rsc@golang.org>
Mon, 30 Oct 2017 14:47:30 +0000 (10:47 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 31 Oct 2017 13:49:46 +0000 (13:49 +0000)
The httpresponse.go module wants to be able to tell if a particular type t
is net/http.Response (and also net/http.Client). It does this by importing
net/http, looking up Response, and then comparing that saved type against
each t.

Instead of doing an eager import of net/http, wait until we have a type t
to ask a question about, and then just look to see if that t is http.Response.
This kind of lazy check does not require assuming that net/http is available
or will be important (perhaps the check is disabled in this run, or perhaps
other conditions that lead to the comparison are not satisfied).

Not loading these kinds of types at startup time will scale better.

Change-Id: Ibb00623901a96e725a4ff6f231e6d15127979dfd
Reviewed-on: https://go-review.googlesource.com/74353
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/vet/httpresponse.go
src/cmd/vet/tests.go
src/cmd/vet/types.go

index ce5ae468ab87719853987b9399a4cfdb5fbd3587..791d11d5bdef047349a8fd9c5a8ff6f6360fe568 100644 (file)
@@ -19,10 +19,6 @@ func init() {
 }
 
 func checkHTTPResponse(f *File, node ast.Node) {
-       // If http.Response or http.Client are not defined, skip this check.
-       if httpResponseType == nil || httpClientType == nil {
-               return
-       }
        call := node.(*ast.CallExpr)
        if !isHTTPFuncOrMethodOnClient(f, call) {
                return // the function call is not related to this check.
@@ -72,7 +68,7 @@ func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool {
        if res.Len() != 2 {
                return false // the function called does not return two values.
        }
-       if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !types.Identical(ptr.Elem(), httpResponseType) {
+       if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") {
                return false // the first return type is not *http.Response.
        }
        if !types.Identical(res.At(1).Type().Underlying(), errorType) {
@@ -85,11 +81,11 @@ func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool {
                return ok && id.Name == "http" // function in net/http package.
        }
 
-       if types.Identical(typ, httpClientType) {
+       if isNamedType(typ, "net/http", "Client") {
                return true // method on http.Client.
        }
        ptr, ok := typ.(*types.Pointer)
-       return ok && types.Identical(ptr.Elem(), httpClientType) // method on *http.Client.
+       return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
 }
 
 // blockStmtFinder is an ast.Visitor that given any ast node can find the
index 8c051f133620b53e9a282239ee07753aa6737c59..5b157084fa2570abccf0a09cbeafcf0d5a43306a 100644 (file)
@@ -161,7 +161,7 @@ func checkTest(fn *ast.FuncDecl, prefix string, report reporter) {
 type reporter func(format string, args ...interface{})
 
 // checkTestFunctions walks Test, Benchmark and Example functions checking
-// malformed names, wrong signatures and examples documenting inexistent
+// malformed names, wrong signatures and examples documenting nonexistent
 // identifiers.
 func checkTestFunctions(f *File, node ast.Node) {
        if !strings.HasSuffix(f.name, "_test.go") {
index 48efa52c0b7dd7955146865b5d114f7670384ec6..3d6936d13631603e592494d78c3d198b55e16db6 100644 (file)
@@ -19,11 +19,9 @@ import (
 var stdImporter types.Importer
 
 var (
-       errorType        *types.Interface
-       stringerType     *types.Interface // possibly nil
-       formatterType    *types.Interface // possibly nil
-       httpResponseType types.Type       // possibly nil
-       httpClientType   types.Type       // possibly nil
+       errorType     *types.Interface
+       stringerType  *types.Interface // possibly nil
+       formatterType *types.Interface // possibly nil
 )
 
 func inittypes() {
@@ -35,12 +33,16 @@ func inittypes() {
        if typ := importType("fmt", "Formatter"); typ != nil {
                formatterType = typ.Underlying().(*types.Interface)
        }
-       if typ := importType("net/http", "Response"); typ != nil {
-               httpResponseType = typ
-       }
-       if typ := importType("net/http", "Client"); typ != nil {
-               httpClientType = typ
+}
+
+// isNamedType reports whether t is the named type path.name.
+func isNamedType(t types.Type, path, name string) bool {
+       n, ok := t.(*types.Named)
+       if !ok {
+               return false
        }
+       obj := n.Obj()
+       return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path
 }
 
 // importType returns the type denoted by the qualified identifier