Repository: google/go-flow-levee
Pull request #247 (2020-12-30 18:12:45)

Add tests for proto propagators
This PR depends on #246.

This PR adds a few tests covering patterns that are common in generated proto code.

- (N/A) [ ] Running against a large codebase such as [Kubernetes](https://github.com/kubernetes/kubernetes) does not error out. (See [DEVELOPING.md](https://github.com/google/go-flow-levee/blob/master/DEVELOPING.md) for instructions on how to do that.)
- (N/A) [ ] Appropriate changes to README are included in PR



Patch:
diff --git a/internal/pkg/fieldpropagator/analyzer.go b/internal/pkg/fieldpropagator/analyzer.go
index e93d75a..4d9fc0e 100644
--- a/internal/pkg/fieldpropagator/analyzer.go
+++ b/internal/pkg/fieldpropagator/analyzer.go
@@ -72,11 +72,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
 		if !ok || !conf.IsSourceType(utils.DecomposeType(ssaType.Type())) {
 			continue
 		}
-		methods := ssaProg.MethodSets.MethodSet(ssaType.Type())
-		for i := 0; i < methods.Len(); i++ {
-			if meth := ssaProg.MethodValue(methods.At(i)); meth != nil {
-				analyzeBlocks(pass, conf, taggedFields, meth)
-			}
+		for _, meth := range methods(ssaProg, ssaType.Type()) {
+			analyzeBlocks(pass, conf, taggedFields, meth)
 		}
 	}
 
@@ -87,6 +84,26 @@ func run(pass *analysis.Pass) (interface{}, error) {
 	return ResultType(isFieldPropagator), nil
 }
 
+func methods(ssaProg *ssa.Program, t types.Type) []*ssa.Function {
+	var methods []*ssa.Function
+	// The method sets of T and *T are disjoint.
+	// In Go code, a variable of type T has access to all
+	// the methods of type *T due to an implicit address operation.
+	methods = append(methods, methodValues(ssaProg, t)...)
+	return append(methods, methodValues(ssaProg, types.NewPointer(t))...)
+}
+
+func methodValues(ssaProg *ssa.Program, t types.Type) []*ssa.Function {
+	var methodValues []*ssa.Function
+	mset := ssaProg.MethodSets.MethodSet(t)
+	for i := 0; i < mset.Len(); i++ {
+		if meth := ssaProg.MethodValue(mset.At(i)); meth != nil {
+			methodValues = append(methodValues, meth)
+		}
+	}
+	return methodValues
+}
+
 func analyzeBlocks(pass *analysis.Pass, conf *config.Config, tf fieldtags.ResultType, meth *ssa.Function) {
 	// Function does not return anything
 	if res := meth.Signature.Results(); res == nil || (*res).Len() == 0 {


Test patch:
diff --git a/internal/pkg/fieldpropagator/testdata/src/proto/proto.go b/internal/pkg/fieldpropagator/testdata/src/proto/proto.go
new file mode 100644
index 0000000..51a21ec
--- /dev/null
+++ b/internal/pkg/fieldpropagator/testdata/src/proto/proto.go
@@ -0,0 +1,73 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package proto
+
+type KeyPair struct {
+	Public  []byte
+	Private []byte
+}
+
+func (kp *KeyPair) GetPublic() []byte {
+	if kp != nil {
+		return kp.Public
+	}
+	return nil
+}
+
+func (kp *KeyPair) GetPrivate() []byte { // want GetPrivate:"field propagator identified"
+	if kp != nil {
+		return kp.Private
+	}
+	return nil
+}
+
+type Certificate struct{}
+
+type TLS struct {
+	Flag *bool
+	Cert *Certificate
+}
+
+func (t *TLS) GetFlag() bool {
+	if t != nil && t.Flag != nil {
+		return *t.Flag
+	}
+	return false
+}
+
+func (t *TLS) GetCert() *Certificate { // want GetCert:"field propagator identified"
+	if t != nil {
+		return t.Cert
+	}
+	return nil
+}
+
+type BasicAuth struct {
+	Username, Password *string
+}
+
+func (ba *BasicAuth) GetUsername() string {
+	if ba != nil && ba.Username != nil {
+		return *ba.Username
+	}
+	return ""
+}
+
+func (ba *BasicAuth) GetPassword() string { // want GetPassword:"field propagator identified"
+	if ba != nil && ba.Password != nil {
+		return *ba.Password
+	}
+	return ""
+}
diff --git a/internal/pkg/fieldpropagator/testdata/src/source/test.go b/internal/pkg/fieldpropagator/testdata/src/source/test.go
index 6d1dbf2..493e45d 100644
--- a/internal/pkg/fieldpropagator/testdata/src/source/test.go
+++ b/internal/pkg/fieldpropagator/testdata/src/source/test.go
@@ -29,7 +29,11 @@ func (s Source) Secret() string { // want Secret:"field propagator identified"
 	return s.secret
 }
 
-func (s Source) Data() string { // want Data:"field propagator identified"
+func (s Source) DataValueReceiver() string { // want DataValueReceiver:"field propagator identified"
+	return s.data
+}
+
+func (s *Source) DataPointerReceiver() string { // want DataPointerReceiver:"field propagator identified"
 	return s.data
 }
 
diff --git a/internal/pkg/fieldpropagator/testdata/test-config.yaml b/internal/pkg/fieldpropagator/testdata/test-config.yaml
index 7716075..5079a51 100644
--- a/internal/pkg/fieldpropagator/testdata/test-config.yaml
+++ b/internal/pkg/fieldpropagator/testdata/test-config.yaml
@@ -16,3 +16,12 @@ Sources:
 - PackageRE: source
   TypeRE: "^Source$"
   FieldRE: "^data"
+- Package: proto
+  Type: KeyPair
+  Field: Private
+- Package: proto
+  Type: TLS
+  Field: Cert
+- Package: proto
+  Type: BasicAuth
+  Field: Password