github.com/googleapis/api-linter@v1.65.2/rules/aip0191/file_option_consistency.go (about) 1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package aip0191 16 17 import ( 18 "fmt" 19 "sort" 20 "strconv" 21 22 "github.com/googleapis/api-linter/lint" 23 "github.com/googleapis/api-linter/locations" 24 "github.com/jhump/protoreflect/desc" 25 dpb "google.golang.org/protobuf/types/descriptorpb" 26 ) 27 28 var consistentOptions = map[string]func(*dpb.FileOptions) string{ 29 "csharp_namespace": func(o *dpb.FileOptions) string { return o.GetCsharpNamespace() }, 30 "go_package": func(o *dpb.FileOptions) string { return o.GetGoPackage() }, 31 "java_package": func(o *dpb.FileOptions) string { return o.GetJavaPackage() }, 32 "java_multiple_files": func(o *dpb.FileOptions) string { return strconv.FormatBool(o.GetJavaMultipleFiles()) }, 33 "php_class_prefix": func(o *dpb.FileOptions) string { return o.GetPhpClassPrefix() }, 34 "php_metadata_namespace": func(o *dpb.FileOptions) string { return o.GetPhpMetadataNamespace() }, 35 "php_namespace": func(o *dpb.FileOptions) string { return o.GetPhpNamespace() }, 36 "objc_class_prefix": func(o *dpb.FileOptions) string { return o.GetObjcClassPrefix() }, 37 "ruby_package": func(o *dpb.FileOptions) string { return o.GetRubyPackage() }, 38 "swift_prefix": func(o *dpb.FileOptions) string { return o.GetSwiftPrefix() }, 39 } 40 41 var fileOptionConsistency = &lint.FileRule{ 42 Name: lint.NewRuleName(191, "file-option-consistency"), 43 OnlyIf: hasPackage, 44 LintFile: func(f *desc.FileDescriptor) (problems []lint.Problem) { 45 opts := f.GetFileOptions() 46 for _, dep := range f.GetDependencies() { 47 // We only need to look at files that are in the same package 48 // as the proto we are linting. 49 if dep.GetPackage() != f.GetPackage() { 50 continue 51 } 52 53 // The file package options should all match between this file 54 // and the file being imported. 55 // 56 // We will naively complain on *this* file, even though either one 57 // might be the one that is wrong, and trust the API producer to do 58 // the right thing. 59 depOpts := dep.GetFileOptions() 60 for opt, valueFunc := range consistentOptions { 61 if valueFunc(opts) != valueFunc(depOpts) { 62 problems = append(problems, lint.Problem{ 63 Message: fmt.Sprintf("Option %q should be consistent throughout the package.", opt), 64 Descriptor: f, 65 Location: locations.FilePackage(f), 66 }) 67 68 // Sort the problems. It does not matter for actual use, but 69 // testing is hard without it since maps are iterated in randomized 70 // order. 71 sort.Slice(problems, func(i, j int) bool { 72 return problems[i].Message < problems[j].Message 73 }) 74 } 75 } 76 } 77 return 78 }, 79 }