github.com/Zenithar/prototool@v1.3.0/internal/lint/check_file_options_same_in_dir.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package lint 22 23 import ( 24 "sort" 25 "strings" 26 "text/scanner" 27 28 "github.com/emicklei/proto" 29 "github.com/uber/prototool/internal/text" 30 ) 31 32 var fileOptionsGoPackageSameInDirLinter = NewLinter( 33 "FILE_OPTIONS_GO_PACKAGE_SAME_IN_DIR", 34 `Verifies that the file option "go_package" of all files in a directory are the same.`, 35 newCheckFileOptionsSameInDir("go_package"), 36 ) 37 38 var fileOptionsJavaMultipleFilesSameInDirLinter = NewLinter( 39 "FILE_OPTIONS_JAVA_MULTIPLE_FILES_SAME_IN_DIR", 40 `Verifies that the file option "java_multiple_files" of all files in a directory are the same.`, 41 newCheckFileOptionsSameInDir("java_multiple_files"), 42 ) 43 44 var fileOptionsJavaPackageSameInDirLinter = NewLinter( 45 "FILE_OPTIONS_JAVA_PACKAGE_SAME_IN_DIR", 46 `Verifies that the file option "java_package" of all files in a directory are the same.`, 47 newCheckFileOptionsSameInDir("java_package"), 48 ) 49 50 func newCheckFileOptionsSameInDir(fileOption string) func(func(*text.Failure), string, []*proto.Proto) error { 51 return func(add func(*text.Failure), dirPath string, descriptors []*proto.Proto) error { 52 visitor := &fileOptionsSameInDirVisitor{ 53 baseAddVisitor: newBaseAddVisitor(add), 54 fileOption: fileOption, 55 fileOptionValues: make(map[string]struct{}), 56 } 57 if err := runVisitor(visitor, descriptors); err != nil { 58 return err 59 } 60 if len(visitor.fileOptionValues) > 1 { 61 if _, ok := visitor.fileOptionValues[""]; ok { 62 for _, descriptor := range descriptors { 63 visitor.AddFailuref(scanner.Position{Filename: descriptor.Filename}, "File option %q set in some files in directory but not in others.", fileOption) 64 } 65 return nil 66 } 67 fileOptionValuesSlice := make([]string, 0, len(visitor.fileOptionValues)) 68 for fileOptionValue := range visitor.fileOptionValues { 69 fileOptionValuesSlice = append(fileOptionValuesSlice, fileOptionValue) 70 } 71 sort.Strings(fileOptionValuesSlice) 72 for _, descriptor := range descriptors { 73 visitor.AddFailuref(scanner.Position{Filename: descriptor.Filename}, "Multiple values for file option %q in directory: %v.", fileOption, strings.Join(fileOptionValuesSlice, ", ")) 74 } 75 } 76 return nil 77 } 78 } 79 80 type fileOptionsSameInDirVisitor struct { 81 baseAddVisitor 82 83 fileOption string 84 85 fileOptionValues map[string]struct{} 86 87 option *proto.Option 88 } 89 90 func (v *fileOptionsSameInDirVisitor) OnStart(*proto.Proto) error { 91 v.option = nil 92 return nil 93 } 94 95 func (v *fileOptionsSameInDirVisitor) VisitOption(element *proto.Option) { 96 // TODO: not validating this is a file option, or are we since we're not recursing on other elements? 97 if element.Name == v.fileOption { 98 if v.option != nil { 99 v.AddFailuref(element.Position, "multiple option declarations for %s, first was %v", v.fileOption, v.option) 100 return 101 } 102 v.option = element 103 } 104 } 105 106 func (v *fileOptionsSameInDirVisitor) Finally() error { 107 value := "" 108 if v.option != nil { 109 value = v.option.Constant.Source 110 } 111 v.fileOptionValues[value] = struct{}{} 112 return nil 113 }