Hook up typechecker.

This does nothing with the extra information except warn if there's an error
returned by the typechecker (e.g. var not used).

This is the first step towards addressing #7.
diff --git a/lint.go b/lint.go
index 30a2fb2..19324c9 100644
--- a/lint.go
+++ b/lint.go
@@ -19,6 +19,10 @@
 	"strings"
 	"unicode"
 	"unicode/utf8"
+
+	"code.google.com/p/go.tools/go/types"
+
+	_ "code.google.com/p/go.tools/go/gcimporter" // use gcimporter as types.DefaultImport
 )
 
 const styleGuideBase = "http://golang.org/s/comments"
@@ -61,6 +65,9 @@
 	src      []byte
 	filename string
 
+	typesPkg  *types.Package
+	typesInfo *types.Info
+
 	// sortable is the set of types in the file that implement sort.Interface.
 	sortable map[string]bool
 	// main is whether this file is in a "main" package.
@@ -72,6 +79,23 @@
 func (f *file) isTest() bool { return strings.HasSuffix(f.filename, "_test.go") }
 
 func (f *file) lint() []Problem {
+	if err := f.typeCheck(); err != nil {
+		if e, ok := err.(types.Error); ok {
+			p := f.fset.Position(e.Pos)
+			conf := 1.0
+			if strings.Contains(e.Msg, "can't find import: ") {
+				// Golint is probably being run in a context that doesn't support
+				// typechecking (e.g. package files aren't found), so don't warn about it.
+				conf = 0
+			}
+			if conf > 0 {
+				f.errorfAt(p, conf, category("typechecking"), e.Msg)
+			}
+
+			// TODO(dsymonds): Abort if !e.Soft?
+		}
+	}
+
 	f.scanSortable()
 	f.main = f.isMain()
 
@@ -101,6 +125,10 @@
 // and must end with a format string and any arguments.
 func (f *file) errorf(n ast.Node, confidence float64, args ...interface{}) {
 	p := f.fset.Position(n.Pos())
+	f.errorfAt(p, confidence, args...)
+}
+
+func (f *file) errorfAt(p token.Position, confidence float64, args ...interface{}) {
 	problem := Problem{
 		Position:   p,
 		Confidence: confidence,
@@ -125,6 +153,19 @@
 	f.problems = append(f.problems, problem)
 }
 
+func (f *file) typeCheck() error {
+	// Do typechecking without errors so we do as much as possible.
+	config := &types.Config{}
+	f.typesInfo = &types.Info{
+		Types: make(map[ast.Expr]types.TypeAndValue),
+		Defs:  make(map[*ast.Ident]types.Object),
+		Uses:  make(map[*ast.Ident]types.Object),
+	}
+	var err error
+	f.typesPkg, err = config.Check(f.f.Name.Name, f.fset, []*ast.File{f.f}, f.typesInfo)
+	return err
+}
+
 func (f *file) scanSortable() {
 	f.sortable = make(map[string]bool)
 
diff --git a/testdata/blank-import-lib.go b/testdata/blank-import-lib.go
index b3da02c..fe1eb50 100644
--- a/testdata/blank-import-lib.go
+++ b/testdata/blank-import-lib.go
@@ -32,3 +32,8 @@
 	_ "go/scanner" // Don't gripe about this or the following line.
 	_ "go/token"
 )
+
+var (
+	_ fmt.Stringer // for "fmt"
+	_ ast.Node     // for "go/ast"
+)
diff --git a/testdata/blank-import-lib_test.go b/testdata/blank-import-lib_test.go
index 0307985..abbf7d7 100644
--- a/testdata/blank-import-lib_test.go
+++ b/testdata/blank-import-lib_test.go
@@ -18,3 +18,8 @@
 	_ "net/http"
 	_ "path"
 )
+
+var (
+	_ fmt.Stringer // for "fmt"
+	_ testing.T    // for "testing"
+)
diff --git a/testdata/blank-import-main.go b/testdata/blank-import-main.go
index 9b72b1c..6ec3a24 100644
--- a/testdata/blank-import-main.go
+++ b/testdata/blank-import-main.go
@@ -10,3 +10,5 @@
 	"os"
 	_ "path"
 )
+
+var _ os.File // for "os"
diff --git a/testdata/error-return.go b/testdata/error-return.go
index bc8bf00..446a64c 100644
--- a/testdata/error-return.go
+++ b/testdata/error-return.go
@@ -23,21 +23,21 @@
 }
 
 // Check for multiple return but error at end with named variables.
-func i() (x int, err error) { // ok
+func j() (x int, err error) { // ok
 	return 0, nil
 }
 
 // Check for error in the wrong location on 2 types
-func j() (error, int) { // MATCH /error should be the last type/
+func k() (error, int) { // MATCH /error should be the last type/
 	return nil, 0
 }
 
 // Check for error in the wrong location for > 2 types
-func k() (int, error, int) { // MATCH /error should be the last type/
+func l() (int, error, int) { // MATCH /error should be the last type/
 	return 0, nil, 0
 }
 
 // Check for error in the wrong location with named variables.
-func l() (x int, err error, y int) { // MATCH /error should be the last type/
+func m() (x int, err error, y int) { // MATCH /error should be the last type/
 	return 0, nil, 0
 }
diff --git a/testdata/errorf.go b/testdata/errorf.go
index 768fb8c..2d26721 100644
--- a/testdata/errorf.go
+++ b/testdata/errorf.go
@@ -20,3 +20,5 @@
 	}
 	return nil
 }
+
+func g(s string) string { return "prefix: " + s }
diff --git a/testdata/errors.go b/testdata/errors.go
index 2882738..396dcfc 100644
--- a/testdata/errors.go
+++ b/testdata/errors.go
@@ -21,6 +21,7 @@
 
 func f() {
 	var whatever = errors.New("ok") // ok
+	_ = whatever
 }
 
 // Check for the error strings themselves.
diff --git a/testdata/import-dot.go b/testdata/import-dot.go
index bb4c267..879de26 100644
--- a/testdata/import-dot.go
+++ b/testdata/import-dot.go
@@ -4,3 +4,5 @@
 package pkg
 
 import . "fmt" // MATCH /dot import/
+
+var _ Stringer // from "fmt"
diff --git a/testdata/make.go b/testdata/make.go
index 5211375..eb5362a 100644
--- a/testdata/make.go
+++ b/testdata/make.go
@@ -3,8 +3,17 @@
 // Package pkg ...
 package pkg
 
+import "net/http"
+
+// T is a test type.
+type T int
+
+var z []T
+
 func f() {
-	x := make([]T, 0)               // MATCH /var x \[\]T/
-	y := make([]somepkg.Foo_Bar, 0) // MATCH /var y \[\]somepkg.Foo_Bar/
-	z = make([]T, 0)                // ok, because we don't know where z is declared
+	x := make([]T, 0)            // MATCH /var x \[\]T/
+	y := make([]http.Request, 0) // MATCH /var y \[\]http\.Request/
+	z = make([]T, 0)             // ok, because we don't know where z is declared
+
+	_, _ = x, y
 }
diff --git a/testdata/names.go b/testdata/names.go
index ca7ffde..9b2bf17 100644
--- a/testdata/names.go
+++ b/testdata/names.go
@@ -3,6 +3,13 @@
 // Package pkg_with_underscores ...
 package pkg_with_underscores // MATCH /underscore.*package name/
 
+import (
+	"io"
+	"net"
+	net_http "net/http" // renamed deliberately
+	"net/url"
+)
+
 var var_name int // MATCH /underscore.*var.*var_name/
 
 type t_wow struct { // MATCH /underscore.*type.*t_wow/
@@ -13,23 +20,35 @@
 const fooId = "blah" // MATCH /fooId.*fooID/
 
 func f_it() { // MATCH /underscore.*func.*f_it/
-	more_underscore := 4                 // MATCH /underscore.*var.*more_underscore/
+	more_underscore := 4 // MATCH /underscore.*var.*more_underscore/
+	_ = more_underscore
+	var err error
 	if isEof := (err == io.EOF); isEof { // MATCH /var.*isEof.*isEOF/
 		more_underscore = 7 // should be okay
 	}
 
-	x := foo_proto.Blah{} // should be okay
+	x := net_http.Request{} // should be okay
+	_ = x
 
+	var ips []net.IP
 	for _, theIp := range ips { // MATCH /range var.*theIp.*theIP/
+		_ = theIp
 	}
 
 	switch myJson := g(); { // MATCH /var.*myJson.*myJSON/
+	default:
+		_ = myJson
 	}
-	switch tApi := x.(type) { // MATCH /var.*tApi.*tAPI/
+	var y net_http.ResponseWriter // an interface
+	switch tApi := y.(type) {     // MATCH /var.*tApi.*tAPI/
+	default:
+		_ = tApi
 	}
 
+	var c chan int
 	select {
 	case qId := <-c: // MATCH /var.*qId.*qID/
+		_ = qId
 	}
 }
 
@@ -42,10 +61,10 @@
 	X509B = 4 // ditto
 )
 
-func f(bad_name int)                    {} // MATCH /underscore.*func parameter.*bad_name/
-func g() (no_way int)                   {} // MATCH /underscore.*func result.*no_way/
-func (t *t_wow) f(more_under string)    {} // MATCH /underscore.*method parameter.*more_under/
-func (t *t_wow) g() (still_more string) {} // MATCH /underscore.*method result.*still_more/
+func f(bad_name int)                    {}            // MATCH /underscore.*func parameter.*bad_name/
+func g() (no_way int)                   { return 0 }  // MATCH /underscore.*func result.*no_way/
+func (t *t_wow) f(more_under string)    {}            // MATCH /underscore.*method parameter.*more_under/
+func (t *t_wow) g() (still_more string) { return "" } // MATCH /underscore.*method result.*still_more/
 
 type i interface {
 	CheckHtml() string // okay; interface method names are often constrained by the concrete types' method names
diff --git a/testdata/range.go b/testdata/range.go
index e8629ed..a01c2bf 100644
--- a/testdata/range.go
+++ b/testdata/range.go
@@ -4,24 +4,34 @@
 package foo
 
 func f() {
+	var m map[string]int
+
 	// with :=
 	for x, _ := range m { // MATCH /should omit 2nd value.*range.*equivalent.*for x := range/
+		_ = x
 	}
 	// with =
+	var y string
+	_ = y
 	for y, _ = range m { // MATCH /should omit 2nd value.*range.*equivalent.*for y = range/
 	}
 
 	// all OK:
 	for x := range m {
+		_ = x
 	}
 	for x, y := range m {
+		_, _ = x, y
 	}
 	for _, y := range m {
+		_ = y
 	}
-	for x = range m {
+	var x int
+	_ = x
+	for y = range m {
 	}
-	for x, y = range m {
+	for y, x = range m {
 	}
-	for _, y = range m {
+	for _, x = range m {
 	}
 }
diff --git a/testdata/var-decl.go b/testdata/var-decl.go
index bbc687c..76c6c7c 100644
--- a/testdata/var-decl.go
+++ b/testdata/var-decl.go
@@ -6,13 +6,16 @@
 import "fmt"
 import "net/http"
 
+// Q is a test type.
+type Q bool
+
 var mux *http.ServeMux = http.NewServeMux() // MATCH /should.*\*http\.ServeMux.*inferred/
 var myInt int = 7                           // MATCH /should.*int.*myInt.*inferred/
 
 var myZeroInt int = 0         // MATCH /should.*= 0.*myZeroInt.*zero value/
 var myZeroFlt float32 = 0.    // MATCH /should.*= 0\..*myZeroFlt.*zero value/
 var myZeroF64 float64 = 0.0   // MATCH /should.*= 0\..*myZeroF64.*zero value/
-var myZeroImg complex = 0i    // MATCH /should.*= 0i.*myZeroImg.*zero value/
+var myZeroImg complex64 = 0i  // MATCH /should.*= 0i.*myZeroImg.*zero value/
 var myZeroStr string = ""     // MATCH /should.*= "".*myZeroStr.*zero value/
 var myZeroRaw string = ``     // MATCH /should.*= ``.*myZeroRaw.*zero value/
 var myZeroPtr *Q = nil        // MATCH /should.*= nil.*myZeroPtr.*zero value/
@@ -26,7 +29,7 @@
 var str fmt.Stringer
 
 // No warning because this is a const.
-const x uint64 = 7
+const k uint64 = 7
 
 // No warnings because the RHS is an ideal int, and the LHS is a different int type.
 var userID int64 = 1235
@@ -43,6 +46,11 @@
 
 // No warning because the LHS names an interface type.
 var data interface{} = googleIPs
+var googleIPs []int
 
 // No warning because it's a common idiom for interface satisfaction.
 var _ Server = (*serverImpl)(nil)
+
+// Server is a test type.
+type Server interface{}
+type serverImpl struct{}