github.com/googleapis/api-linter@v1.65.2/lint/rule_enabled.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 lint 16 17 import ( 18 "strings" 19 20 "github.com/jhump/protoreflect/desc" 21 dpb "google.golang.org/protobuf/types/descriptorpb" 22 ) 23 24 // defaultDisabledRules is the list of rules or groups that are by default 25 // disabled, because they are scoped to a very specific set of AIPs. 26 var defaultDisabledRules = []string{"cloud"} 27 28 // Disable all rules for deprecated descriptors. 29 func disableDeprecated(d desc.Descriptor) bool { 30 switch v := d.(type) { 31 case *desc.EnumDescriptor: 32 return v.GetEnumOptions().GetDeprecated() 33 case *desc.EnumValueDescriptor: 34 return v.GetEnumValueOptions().GetDeprecated() 35 case *desc.FieldDescriptor: 36 return v.GetFieldOptions().GetDeprecated() 37 case *desc.FileDescriptor: 38 return v.GetFileOptions().GetDeprecated() 39 case *desc.MessageDescriptor: 40 return v.GetMessageOptions().GetDeprecated() 41 case *desc.MethodDescriptor: 42 return v.GetMethodOptions().GetDeprecated() 43 case *desc.ServiceDescriptor: 44 return v.GetServiceOptions().GetDeprecated() 45 } 46 return false 47 } 48 49 // Provide methods that are able to disable rules. 50 // 51 // This pattern is a hook for internal extension, by creating an additional 52 // file in this package that can add an additional check: 53 // 54 // func disableForInternalReason(d desc.Descriptor) bool { ... } 55 // 56 // func init() { 57 // descriptorDisableChecks = append(descriptorDisableChecks, disableForInternalReason) 58 // } 59 var descriptorDisableChecks = []func(d desc.Descriptor) bool{ 60 disableDeprecated, 61 } 62 63 // ruleIsEnabled returns true if the rule is enabled (not disabled by the comments 64 // for the given descriptor or its file), false otherwise. 65 // 66 // Note, if the given source code location is not nil, it will be used to 67 // augment the set of commentLines. 68 func ruleIsEnabled(rule ProtoRule, d desc.Descriptor, l *dpb.SourceCodeInfo_Location, 69 aliasMap map[string]string, ignoreCommentDisables bool) bool { 70 // If the rule is disabled because of something on the descriptor itself 71 // (e.g. a deprecated annotation), address that. 72 for _, mustDisable := range descriptorDisableChecks { 73 // The only thing the disable functions can do is force a rule to 74 // be disabled. (They can not force a rule to be enabled.) 75 if mustDisable(d) { 76 return false 77 } 78 } 79 80 if !ignoreCommentDisables { 81 if ruleIsDisabledByComments(rule, d, l, aliasMap) { 82 return false 83 } 84 } 85 86 // The rule may have been disabled on a parent. (For example, a field rule 87 // may be disabled at the message level to cover all fields in the message). 88 // 89 // Do not pass the source code location here, the source location in relation 90 // to the parent is not helpful. 91 if parent := d.GetParent(); parent != nil { 92 return ruleIsEnabled(rule, parent, nil, aliasMap, ignoreCommentDisables) 93 } 94 95 return true 96 } 97 98 // ruleIsDisabledByComments returns true if the rule has been disabled 99 // by comments in the file or leading the element. 100 func ruleIsDisabledByComments(rule ProtoRule, d desc.Descriptor, l *dpb.SourceCodeInfo_Location, aliasMap map[string]string) bool { 101 // Some rules have a legacy name. We add it to the check list. 102 ruleName := string(rule.GetName()) 103 names := []string{ruleName, aliasMap[ruleName]} 104 105 commentLines := []string{} 106 if l != nil { 107 commentLines = append(commentLines, strings.Split(l.GetLeadingComments(), "\n")...) 108 } 109 if f, ok := d.(*desc.FileDescriptor); ok { 110 commentLines = append(commentLines, strings.Split(fileHeader(f), "\n")...) 111 } else { 112 commentLines = append(commentLines, strings.Split(getLeadingComments(d), "\n")...) 113 } 114 disabledRules := []string{} 115 for _, commentLine := range commentLines { 116 r := extractDisabledRuleName(commentLine) 117 if r != "" { 118 disabledRules = append(disabledRules, r) 119 } 120 } 121 122 for _, name := range names { 123 if matchRule(name, disabledRules...) { 124 return true 125 } 126 } 127 128 return false 129 }