github.com/alash3al/go@v0.0.0-20150827002835-d497eeb00540/src/cmd/vet/types.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file contains the pieces of the tool that use typechecking from the go/types package. 6 7 package main 8 9 import ( 10 "go/ast" 11 "go/importer" 12 "go/token" 13 "go/types" 14 ) 15 16 // stdImporter is the importer we use to import packages. 17 // It is created during initialization so that all packages 18 // are imported by the same importer. 19 var stdImporter = importer.Default() 20 21 var ( 22 errorType *types.Interface 23 stringerType *types.Interface // possibly nil 24 formatterType *types.Interface // possibly nil 25 ) 26 27 func init() { 28 errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) 29 30 if typ := importType("fmt", "Stringer"); typ != nil { 31 stringerType = typ.Underlying().(*types.Interface) 32 } 33 34 if typ := importType("fmt", "Formatter"); typ != nil { 35 formatterType = typ.Underlying().(*types.Interface) 36 } 37 } 38 39 // importType returns the type denoted by the qualified identifier 40 // path.name, and adds the respective package to the imports map 41 // as a side effect. In case of an error, importType returns nil. 42 func importType(path, name string) types.Type { 43 pkg, err := stdImporter.Import(path) 44 if err != nil { 45 // This can happen if the package at path hasn't been compiled yet. 46 warnf("import failed: %v", err) 47 return nil 48 } 49 if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok { 50 return obj.Type() 51 } 52 warnf("invalid type name %q", name) 53 return nil 54 } 55 56 func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error { 57 pkg.defs = make(map[*ast.Ident]types.Object) 58 pkg.uses = make(map[*ast.Ident]types.Object) 59 pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection) 60 pkg.spans = make(map[types.Object]Span) 61 pkg.types = make(map[ast.Expr]types.TypeAndValue) 62 config := types.Config{ 63 // We use the same importer for all imports to ensure that 64 // everybody sees identical packages for the given paths. 65 Importer: stdImporter, 66 // By providing a Config with our own error function, it will continue 67 // past the first error. There is no need for that function to do anything. 68 Error: func(error) {}, 69 } 70 info := &types.Info{ 71 Selections: pkg.selectors, 72 Types: pkg.types, 73 Defs: pkg.defs, 74 Uses: pkg.uses, 75 } 76 typesPkg, err := config.Check(pkg.path, fs, astFiles, info) 77 pkg.typesPkg = typesPkg 78 // update spans 79 for id, obj := range pkg.defs { 80 pkg.growSpan(id, obj) 81 } 82 for id, obj := range pkg.uses { 83 pkg.growSpan(id, obj) 84 } 85 return err 86 } 87 88 // isStruct reports whether the composite literal c is a struct. 89 // If it is not (probably a struct), it returns a printable form of the type. 90 func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) { 91 // Check that the CompositeLit's type is a slice or array (which needs no field keys), if possible. 92 typ := pkg.types[c].Type 93 // If it's a named type, pull out the underlying type. If it's not, the Underlying 94 // method returns the type itself. 95 actual := typ 96 if actual != nil { 97 actual = actual.Underlying() 98 } 99 if actual == nil { 100 // No type information available. Assume true, so we do the check. 101 return true, "" 102 } 103 switch actual.(type) { 104 case *types.Struct: 105 return true, typ.String() 106 default: 107 return false, "" 108 } 109 } 110 111 // matchArgType reports an error if printf verb t is not appropriate 112 // for operand arg. 113 // 114 // typ is used only for recursive calls; external callers must supply nil. 115 // 116 // (Recursion arises from the compound types {map,chan,slice} which 117 // may be printed with %d etc. if that is appropriate for their element 118 // types.) 119 func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool { 120 return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool)) 121 } 122 123 // matchArgTypeInternal is the internal version of matchArgType. It carries a map 124 // remembering what types are in progress so we don't recur when faced with recursive 125 // types or mutually recursive types. 126 func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool { 127 // %v, %T accept any argument type. 128 if t == anyType { 129 return true 130 } 131 if typ == nil { 132 // external call 133 typ = f.pkg.types[arg].Type 134 if typ == nil { 135 return true // probably a type check problem 136 } 137 } 138 // If the type implements fmt.Formatter, we have nothing to check. 139 // formatterTyp may be nil - be conservative and check for Format method in that case. 140 if formatterType != nil && types.Implements(typ, formatterType) || f.hasMethod(typ, "Format") { 141 return true 142 } 143 // If we can use a string, might arg (dynamically) implement the Stringer or Error interface? 144 if t&argString != 0 { 145 if types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ) { 146 return true 147 } 148 } 149 150 typ = typ.Underlying() 151 if inProgress[typ] { 152 // We're already looking at this type. The call that started it will take care of it. 153 return true 154 } 155 inProgress[typ] = true 156 157 switch typ := typ.(type) { 158 case *types.Signature: 159 return t&argPointer != 0 160 161 case *types.Map: 162 // Recur: map[int]int matches %d. 163 return t&argPointer != 0 || 164 (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)) 165 166 case *types.Chan: 167 return t&argPointer != 0 168 169 case *types.Array: 170 // Same as slice. 171 if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { 172 return true // %s matches []byte 173 } 174 // Recur: []int matches %d. 175 return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress) 176 177 case *types.Slice: 178 // Same as array. 179 if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { 180 return true // %s matches []byte 181 } 182 // Recur: []int matches %d. But watch out for 183 // type T []T 184 // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below. 185 return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress) 186 187 case *types.Pointer: 188 // Ugly, but dealing with an edge case: a known pointer to an invalid type, 189 // probably something from a failed import. 190 if typ.Elem().String() == "invalid type" { 191 if *verbose { 192 f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg)) 193 } 194 return true // special case 195 } 196 // If it's actually a pointer with %p, it prints as one. 197 if t == argPointer { 198 return true 199 } 200 // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct. 201 if str, ok := typ.Elem().Underlying().(*types.Struct); ok { 202 return f.matchStructArgType(t, str, arg, inProgress) 203 } 204 // The rest can print with %p as pointers, or as integers with %x etc. 205 return t&(argInt|argPointer) != 0 206 207 case *types.Struct: 208 return f.matchStructArgType(t, typ, arg, inProgress) 209 210 case *types.Interface: 211 // If the static type of the argument is empty interface, there's little we can do. 212 // Example: 213 // func f(x interface{}) { fmt.Printf("%s", x) } 214 // Whether x is valid for %s depends on the type of the argument to f. One day 215 // we will be able to do better. For now, we assume that empty interface is OK 216 // but non-empty interfaces, with Stringer and Error handled above, are errors. 217 return typ.NumMethods() == 0 218 219 case *types.Basic: 220 switch typ.Kind() { 221 case types.UntypedBool, 222 types.Bool: 223 return t&argBool != 0 224 225 case types.UntypedInt, 226 types.Int, 227 types.Int8, 228 types.Int16, 229 types.Int32, 230 types.Int64, 231 types.Uint, 232 types.Uint8, 233 types.Uint16, 234 types.Uint32, 235 types.Uint64, 236 types.Uintptr: 237 return t&argInt != 0 238 239 case types.UntypedFloat, 240 types.Float32, 241 types.Float64: 242 return t&argFloat != 0 243 244 case types.UntypedComplex, 245 types.Complex64, 246 types.Complex128: 247 return t&argComplex != 0 248 249 case types.UntypedString, 250 types.String: 251 return t&argString != 0 252 253 case types.UnsafePointer: 254 return t&(argPointer|argInt) != 0 255 256 case types.UntypedRune: 257 return t&(argInt|argRune) != 0 258 259 case types.UntypedNil: 260 return t&argPointer != 0 // TODO? 261 262 case types.Invalid: 263 if *verbose { 264 f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg)) 265 } 266 return true // Probably a type check problem. 267 } 268 panic("unreachable") 269 } 270 271 return false 272 } 273 274 // hasBasicType reports whether x's type is a types.Basic with the given kind. 275 func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool { 276 t := f.pkg.types[x].Type 277 if t != nil { 278 t = t.Underlying() 279 } 280 b, ok := t.(*types.Basic) 281 return ok && b.Kind() == kind 282 } 283 284 // matchStructArgType reports whether all the elements of the struct match the expected 285 // type. For instance, with "%d" all the elements must be printable with the "%d" format. 286 func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool { 287 for i := 0; i < typ.NumFields(); i++ { 288 if !f.matchArgTypeInternal(t, typ.Field(i).Type(), arg, inProgress) { 289 return false 290 } 291 } 292 return true 293 } 294 295 // numArgsInSignature tells how many formal arguments the function type 296 // being called has. 297 func (f *File) numArgsInSignature(call *ast.CallExpr) int { 298 // Check the type of the function or method declaration 299 typ := f.pkg.types[call.Fun].Type 300 if typ == nil { 301 return 0 302 } 303 // The type must be a signature, but be sure for safety. 304 sig, ok := typ.(*types.Signature) 305 if !ok { 306 return 0 307 } 308 return sig.Params().Len() 309 } 310 311 // isErrorMethodCall reports whether the call is of a method with signature 312 // func Error() string 313 // where "string" is the universe's string type. We know the method is called "Error". 314 func (f *File) isErrorMethodCall(call *ast.CallExpr) bool { 315 typ := f.pkg.types[call].Type 316 if typ != nil { 317 // We know it's called "Error", so just check the function signature 318 // (stringerType has exactly one method, String). 319 if stringerType != nil && stringerType.NumMethods() == 1 { 320 return types.Identical(f.pkg.types[call.Fun].Type, stringerType.Method(0).Type()) 321 } 322 } 323 // Without types, we can still check by hand. 324 // Is it a selector expression? Otherwise it's a function call, not a method call. 325 sel, ok := call.Fun.(*ast.SelectorExpr) 326 if !ok { 327 return false 328 } 329 // The package is type-checked, so if there are no arguments, we're done. 330 if len(call.Args) > 0 { 331 return false 332 } 333 // Check the type of the method declaration 334 typ = f.pkg.types[sel].Type 335 if typ == nil { 336 return false 337 } 338 // The type must be a signature, but be sure for safety. 339 sig, ok := typ.(*types.Signature) 340 if !ok { 341 return false 342 } 343 // There must be a receiver for it to be a method call. Otherwise it is 344 // a function, not something that satisfies the error interface. 345 if sig.Recv() == nil { 346 return false 347 } 348 // There must be no arguments. Already verified by type checking, but be thorough. 349 if sig.Params().Len() > 0 { 350 return false 351 } 352 // Finally the real questions. 353 // There must be one result. 354 if sig.Results().Len() != 1 { 355 return false 356 } 357 // It must have return type "string" from the universe. 358 return sig.Results().At(0).Type() == types.Typ[types.String] 359 } 360 361 // hasMethod reports whether the type contains a method with the given name. 362 // It is part of the workaround for Formatters and should be deleted when 363 // that workaround is no longer necessary. 364 // TODO: This could be better once issue 6259 is fixed. 365 func (f *File) hasMethod(typ types.Type, name string) bool { 366 // assume we have an addressable variable of type typ 367 obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name) 368 _, ok := obj.(*types.Func) 369 return ok 370 }