Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Api computes the exported API of a set of Go packages. | 5 // Api computes the exported API of a set of Go packages. |
6 // | 6 // |
7 // BUG(bradfitz): Note that this tool is only currently suitable | 7 // BUG(bradfitz): Note that this tool is only currently suitable |
8 // for use on the Go standard library, not arbitrary packages. | 8 // for use on the Go standard library, not arbitrary packages. |
9 // Once the Go AST has type information, this tool will be more | 9 // Once the Go AST has type information, this tool will be more |
10 // reliable without hard-coded hacks throughout. | 10 // reliable without hard-coded hacks throughout. |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
346 if err != nil { | 346 if err != nil { |
347 log.Fatalf("error unquoting import string %q: %v", is.Pa th.Value, err) | 347 log.Fatalf("error unquoting import string %q: %v", is.Pa th.Value, err) |
348 } | 348 } |
349 if fpkg != "C" { | 349 if fpkg != "C" { |
350 pkgs = append(pkgs, fpkg) | 350 pkgs = append(pkgs, fpkg) |
351 } | 351 } |
352 } | 352 } |
353 return | 353 return |
354 } | 354 } |
355 | 355 |
356 var parsedFileCache = make(map[string]*ast.File) | |
357 | |
358 func parseFile(filename string) (*ast.File, error) { | |
359 f, ok := parsedFileCache[filename] | |
360 if !ok { | |
361 var err error | |
362 f, err = parser.ParseFile(fset, filename, nil, 0) | |
363 if err != nil { | |
364 return nil, err | |
365 } | |
366 parsedFileCache[filename] = f | |
367 } | |
368 return clone(f).(*ast.File), nil | |
369 } | |
370 | |
356 // WalkPackage walks all files in package `name'. | 371 // WalkPackage walks all files in package `name'. |
357 // WalkPackage does nothing if the package has already been loaded. | 372 // WalkPackage does nothing if the package has already been loaded. |
358 func (w *Walker) WalkPackage(name string) { | 373 func (w *Walker) WalkPackage(name string) { |
359 switch w.packageState[name] { | 374 switch w.packageState[name] { |
360 case loading: | 375 case loading: |
361 log.Fatalf("import cycle loading package %q?", name) | 376 log.Fatalf("import cycle loading package %q?", name) |
362 case loaded: | 377 case loaded: |
363 return | 378 return |
364 } | 379 } |
365 w.packageState[name] = loading | 380 w.packageState[name] = loading |
(...skipping 13 matching lines...) Expand all Loading... | |
379 } | 394 } |
380 log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err) | 395 log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err) |
381 } | 396 } |
382 | 397 |
383 apkg := &ast.Package{ | 398 apkg := &ast.Package{ |
384 Files: make(map[string]*ast.File), | 399 Files: make(map[string]*ast.File), |
385 } | 400 } |
386 | 401 |
387 files := append(append([]string{}, info.GoFiles...), info.CgoFiles...) | 402 files := append(append([]string{}, info.GoFiles...), info.CgoFiles...) |
388 for _, file := range files { | 403 for _, file := range files { |
389 » » f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0) | 404 » » f, err := parseFile(filepath.Join(dir, file)) |
390 if err != nil { | 405 if err != nil { |
391 log.Fatalf("error parsing package %s, file %s: %v", name , file, err) | 406 log.Fatalf("error parsing package %s, file %s: %v", name , file, err) |
392 } | 407 } |
393 apkg.Files[file] = f | 408 apkg.Files[file] = f |
394 | 409 |
395 for _, dep := range fileDeps(f) { | 410 for _, dep := range fileDeps(f) { |
396 w.WalkPackage(dep) | 411 w.WalkPackage(dep) |
397 } | 412 } |
398 } | 413 } |
399 | 414 |
(...skipping 23 matching lines...) Expand all Loading... | |
423 for _, afile := range apkg.Files { | 438 for _, afile := range apkg.Files { |
424 w.walkFile(afile) | 439 w.walkFile(afile) |
425 } | 440 } |
426 | 441 |
427 w.resolveConstantDeps() | 442 w.resolveConstantDeps() |
428 | 443 |
429 // Now that we're done walking types, vars and consts | 444 // Now that we're done walking types, vars and consts |
430 // in the *ast.Package, use go/doc to do the rest | 445 // in the *ast.Package, use go/doc to do the rest |
431 // (functions and methods). This is done here because | 446 // (functions and methods). This is done here because |
432 // go/doc is destructive. We can't use the | 447 // go/doc is destructive. We can't use the |
433 // *ast.Package after this. | 448 // *ast.Package after this. |
minux1
2012/11/17 19:31:36
do you want to update the comment here?
bradfitz
2012/11/17 22:13:09
No. This comment is still accurate. doc.New is sti
| |
434 dpkg := doc.New(apkg, name, doc.AllMethods) | 449 dpkg := doc.New(apkg, name, doc.AllMethods) |
435 | 450 |
436 for _, t := range dpkg.Types { | 451 for _, t := range dpkg.Types { |
437 // Move funcs up to the top-level, not hiding in the Types. | 452 // Move funcs up to the top-level, not hiding in the Types. |
438 dpkg.Funcs = append(dpkg.Funcs, t.Funcs...) | 453 dpkg.Funcs = append(dpkg.Funcs, t.Funcs...) |
439 | 454 |
440 for _, m := range t.Methods { | 455 for _, m := range t.Methods { |
441 w.walkFuncDecl(m.Decl) | 456 w.walkFuncDecl(m.Decl) |
442 } | 457 } |
443 } | 458 } |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1144 } | 1159 } |
1145 | 1160 |
1146 func strListContains(l []string, s string) bool { | 1161 func strListContains(l []string, s string) bool { |
1147 for _, v := range l { | 1162 for _, v := range l { |
1148 if v == s { | 1163 if v == s { |
1149 return true | 1164 return true |
1150 } | 1165 } |
1151 } | 1166 } |
1152 return false | 1167 return false |
1153 } | 1168 } |
OLD | NEW |