full diff: https://github.com/dominikh/go-tools/compare/2019.2.3...2020.1.3 Also updates tests to accomodate updated rules: --- FAIL: TestSourcesFromTestdataWithIssuesDir/staticcheck.go (0.43s) linters_test.go:137: [run --disable-all --print-issued-lines=false --print-linter-name=false --out-format=line-number --max-same-issues=10 -Estaticcheck --no-config testdata/staticcheck.go] linters_test.go:33: Error Trace: linters_test.go:33 linters_test.go:138 linters_test.go:53 Error: Received unexpected error: staticcheck.go:11: no match for `self-assignment of x to x` vs ["SA4006: this value of `x` is never used"] in: staticcheck.go:11:2: SA4006: this value of `x` is never used unmatched errors staticcheck.go:11:2: SA4006: this value of `x` is never used Test: TestSourcesFromTestdataWithIssuesDir/staticcheck.go Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
		
			
				
	
	
		
			222 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package pattern
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"go/token"
 | 
						|
	"unicode"
 | 
						|
	"unicode/utf8"
 | 
						|
)
 | 
						|
 | 
						|
type lexer struct {
 | 
						|
	f *token.File
 | 
						|
 | 
						|
	input string
 | 
						|
	start int
 | 
						|
	pos   int
 | 
						|
	width int
 | 
						|
	items chan item
 | 
						|
}
 | 
						|
 | 
						|
type itemType int
 | 
						|
 | 
						|
const eof = -1
 | 
						|
 | 
						|
const (
 | 
						|
	itemError itemType = iota
 | 
						|
	itemLeftParen
 | 
						|
	itemRightParen
 | 
						|
	itemLeftBracket
 | 
						|
	itemRightBracket
 | 
						|
	itemTypeName
 | 
						|
	itemVariable
 | 
						|
	itemAt
 | 
						|
	itemColon
 | 
						|
	itemBlank
 | 
						|
	itemString
 | 
						|
	itemEOF
 | 
						|
)
 | 
						|
 | 
						|
func (typ itemType) String() string {
 | 
						|
	switch typ {
 | 
						|
	case itemError:
 | 
						|
		return "ERROR"
 | 
						|
	case itemLeftParen:
 | 
						|
		return "("
 | 
						|
	case itemRightParen:
 | 
						|
		return ")"
 | 
						|
	case itemLeftBracket:
 | 
						|
		return "["
 | 
						|
	case itemRightBracket:
 | 
						|
		return "]"
 | 
						|
	case itemTypeName:
 | 
						|
		return "TYPE"
 | 
						|
	case itemVariable:
 | 
						|
		return "VAR"
 | 
						|
	case itemAt:
 | 
						|
		return "@"
 | 
						|
	case itemColon:
 | 
						|
		return ":"
 | 
						|
	case itemBlank:
 | 
						|
		return "_"
 | 
						|
	case itemString:
 | 
						|
		return "STRING"
 | 
						|
	case itemEOF:
 | 
						|
		return "EOF"
 | 
						|
	default:
 | 
						|
		return fmt.Sprintf("itemType(%d)", typ)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type item struct {
 | 
						|
	typ itemType
 | 
						|
	val string
 | 
						|
	pos int
 | 
						|
}
 | 
						|
 | 
						|
type stateFn func(*lexer) stateFn
 | 
						|
 | 
						|
func (l *lexer) run() {
 | 
						|
	for state := lexStart; state != nil; {
 | 
						|
		state = state(l)
 | 
						|
	}
 | 
						|
	close(l.items)
 | 
						|
}
 | 
						|
 | 
						|
func (l *lexer) emitValue(t itemType, value string) {
 | 
						|
	l.items <- item{t, value, l.start}
 | 
						|
	l.start = l.pos
 | 
						|
}
 | 
						|
 | 
						|
func (l *lexer) emit(t itemType) {
 | 
						|
	l.items <- item{t, l.input[l.start:l.pos], l.start}
 | 
						|
	l.start = l.pos
 | 
						|
}
 | 
						|
 | 
						|
func lexStart(l *lexer) stateFn {
 | 
						|
	switch r := l.next(); {
 | 
						|
	case r == eof:
 | 
						|
		l.emit(itemEOF)
 | 
						|
		return nil
 | 
						|
	case unicode.IsSpace(r):
 | 
						|
		l.ignore()
 | 
						|
	case r == '(':
 | 
						|
		l.emit(itemLeftParen)
 | 
						|
	case r == ')':
 | 
						|
		l.emit(itemRightParen)
 | 
						|
	case r == '[':
 | 
						|
		l.emit(itemLeftBracket)
 | 
						|
	case r == ']':
 | 
						|
		l.emit(itemRightBracket)
 | 
						|
	case r == '@':
 | 
						|
		l.emit(itemAt)
 | 
						|
	case r == ':':
 | 
						|
		l.emit(itemColon)
 | 
						|
	case r == '_':
 | 
						|
		l.emit(itemBlank)
 | 
						|
	case r == '"':
 | 
						|
		l.backup()
 | 
						|
		return lexString
 | 
						|
	case unicode.IsUpper(r):
 | 
						|
		l.backup()
 | 
						|
		return lexType
 | 
						|
	case unicode.IsLower(r):
 | 
						|
		l.backup()
 | 
						|
		return lexVariable
 | 
						|
	default:
 | 
						|
		return l.errorf("unexpected character %c", r)
 | 
						|
	}
 | 
						|
	return lexStart
 | 
						|
}
 | 
						|
 | 
						|
func (l *lexer) next() (r rune) {
 | 
						|
	if l.pos >= len(l.input) {
 | 
						|
		l.width = 0
 | 
						|
		return eof
 | 
						|
	}
 | 
						|
	r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
 | 
						|
 | 
						|
	if r == '\n' {
 | 
						|
		l.f.AddLine(l.pos)
 | 
						|
	}
 | 
						|
 | 
						|
	l.pos += l.width
 | 
						|
 | 
						|
	return r
 | 
						|
}
 | 
						|
 | 
						|
func (l *lexer) ignore() {
 | 
						|
	l.start = l.pos
 | 
						|
}
 | 
						|
 | 
						|
func (l *lexer) backup() {
 | 
						|
	l.pos -= l.width
 | 
						|
}
 | 
						|
 | 
						|
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
 | 
						|
	// TODO(dh): emit position information in errors
 | 
						|
	l.items <- item{
 | 
						|
		itemError,
 | 
						|
		fmt.Sprintf(format, args...),
 | 
						|
		l.start,
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func isAlphaNumeric(r rune) bool {
 | 
						|
	return r >= '0' && r <= '9' ||
 | 
						|
		r >= 'a' && r <= 'z' ||
 | 
						|
		r >= 'A' && r <= 'Z'
 | 
						|
}
 | 
						|
 | 
						|
func lexString(l *lexer) stateFn {
 | 
						|
	l.next() // skip quote
 | 
						|
	escape := false
 | 
						|
 | 
						|
	var runes []rune
 | 
						|
	for {
 | 
						|
		switch r := l.next(); r {
 | 
						|
		case eof:
 | 
						|
			return l.errorf("unterminated string")
 | 
						|
		case '"':
 | 
						|
			if !escape {
 | 
						|
				l.emitValue(itemString, string(runes))
 | 
						|
				return lexStart
 | 
						|
			} else {
 | 
						|
				runes = append(runes, '"')
 | 
						|
				escape = false
 | 
						|
			}
 | 
						|
		case '\\':
 | 
						|
			if escape {
 | 
						|
				runes = append(runes, '\\')
 | 
						|
				escape = false
 | 
						|
			} else {
 | 
						|
				escape = true
 | 
						|
			}
 | 
						|
		default:
 | 
						|
			runes = append(runes, r)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func lexType(l *lexer) stateFn {
 | 
						|
	l.next()
 | 
						|
	for {
 | 
						|
		if !isAlphaNumeric(l.next()) {
 | 
						|
			l.backup()
 | 
						|
			l.emit(itemTypeName)
 | 
						|
			return lexStart
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func lexVariable(l *lexer) stateFn {
 | 
						|
	l.next()
 | 
						|
	for {
 | 
						|
		if !isAlphaNumeric(l.next()) {
 | 
						|
			l.backup()
 | 
						|
			l.emit(itemVariable)
 | 
						|
			return lexStart
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |