KDOC 22: whitespaceを読む
whitespaceは、無意味な空白を検知するGoのLinterである。
tasks
DONE どうやって空行を検知しているか
仕組み。
- 関数定義一覧をとる
- visitorを作成
- walkの引数にvisitorを渡す
- ast.Walkは探索アルゴリズムを切り替えるときに使う
- visitorインターフェースがアルゴリズム
- messagesをスライスに貯める
- ループを抜けてmessagesを返却
https://github.com/ultraware/whitespace/blob/a14a2923c0f916b3fc7dbd0238ef85b88f85ef8a/main.go#L63-L73
if stmt, ok := node.(*ast.IfStmt); ok && v.settings.MultiIf { checkMultiLine(v, stmt.Body, stmt.Cond) } if stmt, ok := node.(*ast.FuncLit); ok && v.settings.MultiFunc { checkMultiLine(v, stmt.Body, stmt.Type) } if stmt, ok := node.(*ast.FuncDecl); ok && v.settings.MultiFunc { checkMultiLine(v, stmt.Body, stmt.Type) }
https://github.com/ultraware/whitespace/blob/a14a2923c0f916b3fc7dbd0238ef85b88f85ef8a/main.go#L75-L95
if stmt, ok := node.(*ast.BlockStmt); ok { wantNewline := v.wantNewline[stmt] comments := v.comments if wantNewline { comments = nil // Comments also count as a newline if we want a newline } first, last := firstAndLast(comments, v.fset, stmt.Pos(), stmt.End(), stmt.List) startMsg := checkStart(v.fset, stmt.Lbrace, first) if wantNewline && startMsg == nil { v.messages = append(v.messages, Message{v.fset.Position(stmt.Pos()), MessageTypeAddAfter, `multi-line statement should be followed by a newline`}) } else if !wantNewline && startMsg != nil { v.messages = append(v.messages, *startMsg) } if msg := checkEnd(v.fset, stmt.Rbrace, last); msg != nil { v.messages = append(v.messages, *msg) } }
- check系関数を使って、警告メッセージを格納する
DONE オプションはどうやって指定しているか
オプションを指定しているようだが、どうやっているか。
Settings構造体を初期化している箇所はない。呼び出し元の設定で、このコードからはわからない。
DONE checkMultilineは何をしているか
https://github.com/ultraware/whitespace/blob/a14a2923c0f916b3fc7dbd0238ef85b88f85ef8a/main.go#L100-L106
DONE 警告部分
https://github.com/ultraware/whitespace/blob/a14a2923c0f916b3fc7dbd0238ef85b88f85ef8a/main.go#L138-L149
func checkStart(fset *token.FileSet, start token.Pos, first ast.Node) *Message { if first == nil { return nil } if posLine(fset, start)+1 < posLine(fset, first.Pos()) { pos := fset.Position(start) return &Message{pos, MessageTypeLeading, `unnecessary leading newline`} } return nil }
- どうして、posLineの比較でわかるのか
- 実際のコードの位置と、ASTから生成したコードの位置を比較しているぽい
- 適切であればposは変わらない。余計なwhitespaceがあると、元の位置が大きくなる
memo
- ast.FuncDeclは関数定義
- linterじゃないが、キーワードの出現回数とかの統計情報を出せるわけか
- 関数の一覧
- 長さ
- 行数
- 並び替え