Name every render start, and let no backticked spelling go unchecked
This commit is contained in:
+39
-32
@@ -2,18 +2,20 @@ package fejkdata
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var backticked = regexp.MustCompile("`([A-Za-z][A-Za-z0-9]*(?:\\.[A-Za-z][A-Za-z0-9]*)?)`")
|
||||
// Every backtick in the Vocabulary is a symbol, so an unrecognised spelling fails
|
||||
// rather than going unchecked.
|
||||
var backticked = regexp.MustCompile("`([^`]+)`")
|
||||
|
||||
// TestVocabularyNamesDeclaredSymbols proves every symbol the package doc's Vocabulary
|
||||
// names is declared here, so a renamed unit renames its entry with it.
|
||||
// TestVocabularyNamesDeclaredSymbols proves the package doc's Vocabulary names
|
||||
// symbols this package declares, so a renamed unit renames its entry with it.
|
||||
func TestVocabularyNamesDeclaredSymbols(t *testing.T) {
|
||||
files := sourceFiles(t)
|
||||
declared := declaredSymbols(files)
|
||||
@@ -24,21 +26,15 @@ func TestVocabularyNamesDeclaredSymbols(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// sourceFiles parses the package's own files, the tests left out: the Vocabulary
|
||||
// indexes what ships, not what proves it.
|
||||
func sourceFiles(t *testing.T) []*ast.File {
|
||||
t.Helper()
|
||||
entries, err := os.ReadDir(".")
|
||||
pkg, err := build.ImportDir(".", 0)
|
||||
if err != nil {
|
||||
t.Fatalf("read the package directory: %v", err)
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
var files []*ast.File
|
||||
for _, e := range entries {
|
||||
name := e.Name()
|
||||
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
||||
continue
|
||||
}
|
||||
for _, name := range pkg.GoFiles {
|
||||
f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Fatalf("parse %s: %v", name, err)
|
||||
@@ -48,7 +44,6 @@ func sourceFiles(t *testing.T) []*ast.File {
|
||||
return files
|
||||
}
|
||||
|
||||
// vocabulary is the package doc from its Vocabulary heading on.
|
||||
func vocabulary(t *testing.T, files []*ast.File) string {
|
||||
t.Helper()
|
||||
for _, f := range files {
|
||||
@@ -63,45 +58,57 @@ func vocabulary(t *testing.T, files []*ast.File) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// declaredSymbols is every name the package declares, a method and a struct field
|
||||
// under its type as well: fence, draws.pin, tableRead.whole.
|
||||
// declaredSymbols is every name the package declares at the top level, a method and
|
||||
// a struct field keyed under its type: draws.pin, tableRead.whole. A name declared
|
||||
// inside a function body is not one a Vocabulary entry may name.
|
||||
func declaredSymbols(files []*ast.File) map[string]bool {
|
||||
names := map[string]bool{}
|
||||
for _, f := range files {
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
switch d := n.(type) {
|
||||
for _, decl := range f.Decls {
|
||||
switch d := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
names[d.Name.Name] = true
|
||||
if d.Recv != nil {
|
||||
names[receiverType(d.Recv)+"."+d.Name.Name] = true
|
||||
}
|
||||
case *ast.TypeSpec:
|
||||
names[d.Name.Name] = true
|
||||
addFields(names, d)
|
||||
case *ast.ValueSpec:
|
||||
for _, id := range d.Names {
|
||||
names[id.Name] = true
|
||||
if recv := receiverType(d.Recv); recv != "" {
|
||||
names[recv+"."+d.Name.Name] = true
|
||||
}
|
||||
case *ast.GenDecl:
|
||||
addSpecs(names, d)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func addFields(names map[string]bool, d *ast.TypeSpec) {
|
||||
s, isStruct := d.Type.(*ast.StructType)
|
||||
func addSpecs(names map[string]bool, d *ast.GenDecl) {
|
||||
for _, spec := range d.Specs {
|
||||
switch s := spec.(type) {
|
||||
case *ast.TypeSpec:
|
||||
names[s.Name.Name] = true
|
||||
addFields(names, s)
|
||||
case *ast.ValueSpec:
|
||||
for _, id := range s.Names {
|
||||
names[id.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addFields(names map[string]bool, s *ast.TypeSpec) {
|
||||
st, isStruct := s.Type.(*ast.StructType)
|
||||
if !isStruct {
|
||||
return
|
||||
}
|
||||
for _, field := range s.Fields.List {
|
||||
for _, field := range st.Fields.List {
|
||||
for _, id := range field.Names {
|
||||
names[d.Name.Name+"."+id.Name] = true
|
||||
names[s.Name.Name+"."+id.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func receiverType(recv *ast.FieldList) string {
|
||||
if recv == nil || len(recv.List) == 0 {
|
||||
return ""
|
||||
}
|
||||
e := recv.List[0].Type
|
||||
if star, isPointer := e.(*ast.StarExpr); isPointer {
|
||||
e = star.X
|
||||
|
||||
Reference in New Issue
Block a user