-
Notifications
You must be signed in to change notification settings - Fork 21
Cthl 5116 adds global regex anotation #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
50a8e90
eeadb78
f5753cd
6f85e31
e92ea95
d4d2d50
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,4 +3,4 @@ skip_with_build_tags: true | |
| json_output: false | ||
| silent_mode: false | ||
| exclude_dirs: | ||
| - example | ||
| - example | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package annotation | ||
|
|
||
| type filters struct { | ||
| filteredRegexps []string | ||
| } | ||
|
|
||
| type options struct { | ||
| global filters | ||
| } | ||
|
|
||
| // OptionFunc function that allows you to change options | ||
| type OptionFunc func(*options) | ||
|
|
||
| // WithGlobalRegexpFilter returns OptionFunc which enables global regexp exclusion for mutators | ||
| func WithGlobalRegexpFilter(filteredRegexps ...string) OptionFunc { | ||
| return func(o *options) { | ||
| o.global.filteredRegexps = filteredRegexps | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| package annotation | ||
|
|
||
| import ( | ||
| "bufio" | ||
| "go/ast" | ||
| "go/token" | ||
| "log" | ||
| "os" | ||
| "regexp" | ||
| "strings" | ||
| ) | ||
|
|
||
| // Collector defines the interface for handlers. | ||
| // Implementations should handle specific annotation types. | ||
| type Collector interface { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. не совсем понимаю, зачем нам тут нужен интерфейс |
||
| // Handle processes an annotation if it matches the handler's type, | ||
| // otherwise delegates to the next handler in the chain. | ||
| Handle(name string, comment *ast.Comment, fset *token.FileSet, file *ast.File, fileAbs string) | ||
| } | ||
|
|
||
| // RegexExclusion structure that contains info required for ast.Node exclusion from mutations | ||
| type RegexExclusion struct { | ||
| regex *regexp.Regexp | ||
| mutators mutatorInfo | ||
| } | ||
|
|
||
| // RegexCollector Collector based on regular expressions parse all file | ||
| type RegexCollector struct { | ||
| Exclusions map[int]map[token.Pos]mutatorInfo | ||
| GlobalExclusionsRegex []RegexExclusion | ||
| } | ||
|
|
||
| // NewRegexCollector constructor for RegexCollector | ||
| func NewRegexCollector( | ||
| exclusionsConfig []string, | ||
| ) RegexCollector { | ||
| exclusionsRegex := make([]RegexExclusion, 0, len(exclusionsConfig)) | ||
| for _, exclusion := range exclusionsConfig { | ||
| re, inf := parseConfig(exclusion) | ||
| if re != nil { | ||
| exclusionsRegex = append(exclusionsRegex, RegexExclusion{ | ||
| regex: re, | ||
| mutators: inf, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| return RegexCollector{ | ||
| Exclusions: make(map[int]map[token.Pos]mutatorInfo), | ||
| GlobalExclusionsRegex: exclusionsRegex, | ||
| } | ||
| } | ||
|
|
||
| // Collect processes regex pattern | ||
| func (r *RegexCollector) Collect( | ||
| fset *token.FileSet, | ||
| file *ast.File, | ||
| fileAbs string, | ||
| ) { | ||
| for _, exclusions := range r.GlobalExclusionsRegex { | ||
| lines, err := r.findLinesMatchingRegex(fileAbs, exclusions.regex) | ||
| if err != nil { | ||
| log.Printf("Error scaning a source file: %v", err) | ||
| } | ||
|
|
||
| if len(lines) > 0 { | ||
| collectExcludedNodes(fset, file, lines, r.Exclusions, exclusions.mutators) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func parseConfig(configLine string) (*regexp.Regexp, mutatorInfo) { | ||
| // splitted[0] - contains regexp splitted[1] contains mutators | ||
| splitted := strings.SplitN(configLine, " ", 2) | ||
|
|
||
| if len(splitted) < 1 { | ||
| return nil, mutatorInfo{} | ||
| } | ||
|
|
||
| pattern := splitted[0] | ||
| re, err := regexp.Compile(pattern) | ||
| if err != nil { | ||
| log.Printf("Warning: invalid regex in annotation: %q, error: %v\n", pattern, err) | ||
| return nil, mutatorInfo{} | ||
| } | ||
|
|
||
| var mutators []string | ||
| if len(splitted) > 1 { | ||
| mutators = parseMutators(splitted[1]) | ||
| } else { | ||
| mutators = []string{"*"} | ||
| } | ||
|
|
||
| return re, mutatorInfo{ | ||
| Names: mutators, | ||
| } | ||
| } | ||
|
|
||
| // findLinesMatchingRegex scans a source file and returns line numbers that match the given regex. | ||
| func (r *RegexCollector) findLinesMatchingRegex(filePath string, regex *regexp.Regexp) ([]int, error) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. не очень красиво, когда функция полностью скопипащена из другого файла. давай сделаем ее общей и будем переиспользовать |
||
| var matchedLineNumbers []int | ||
|
|
||
| if regex == nil { | ||
| return matchedLineNumbers, nil | ||
| } | ||
|
|
||
| f, err := os.Open(filePath) | ||
| if err != nil { | ||
| log.Printf("Error opening file: %v", err) | ||
| } | ||
|
|
||
| reader := bufio.NewReader(f) | ||
|
|
||
| lineNumber := 0 | ||
| for { | ||
| line, err := reader.ReadString('\n') | ||
| if err != nil { | ||
| break | ||
| } | ||
|
|
||
| if regex.MatchString(line) { | ||
| matchedLineNumbers = append(matchedLineNumbers, lineNumber+1) | ||
| } | ||
| lineNumber++ | ||
| } | ||
|
|
||
| defer func() { | ||
| err = f.Close() | ||
| if err != nil { | ||
| log.Printf("Error while file closing duting processing regex annotation: %v", err.Error()) | ||
| } | ||
| }() | ||
|
|
||
| return matchedLineNumbers, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //go:build examplemain | ||
| // +build examplemain | ||
|
|
||
| package main | ||
|
|
||
| type Logger struct{} | ||
|
|
||
| func (l *Logger) Log(items ...any) {} | ||
|
|
||
| func (l *Logger) Debug(items ...any) {} | ||
|
|
||
| func main() { | ||
| logger := &Logger{} | ||
| _, err := fmt.Println("hello world") | ||
|
|
||
| if err != nil { | ||
| logger.Log(err) | ||
| } else { | ||
| logger.Debug("debug log") | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
глобальное исключение по конфигу - это уже не аннотирование. стоит перенести в другой пакет