report cycle when visiting a grey analyzer
Fixes golang/go#40408
Change-Id: I04cd852f816f072e0e89c8ed5af636b09d0b54b4
GitHub-Last-Rev: 627dd414eb90d239cab9fce38454d43be133276e
GitHub-Pull-Request: golang/tools#244
Reviewed-on: https://go-review.googlesource.com/c/tools/+/244799
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
diff --git a/go/analysis/validate.go b/go/analysis/validate.go
index be98143..ad0e727 100644
--- a/go/analysis/validate.go
+++ b/go/analysis/validate.go
@@ -3,6 +3,7 @@
import (
"fmt"
"reflect"
+ "strings"
"unicode"
)
@@ -58,14 +59,28 @@
}
// recursion
- for i, req := range a.Requires {
+ for _, req := range a.Requires {
if err := visit(req); err != nil {
- return fmt.Errorf("%s.Requires[%d]: %v", a.Name, i, err)
+ return err
}
}
color[a] = black
}
+ if color[a] == grey {
+ stack := []*Analyzer{a}
+ inCycle := map[string]bool{}
+ for len(stack) > 0 {
+ current := stack[len(stack)-1]
+ stack = stack[:len(stack)-1]
+ if color[current] == grey && !inCycle[current.Name] {
+ inCycle[current.Name] = true
+ stack = append(stack, current.Requires...)
+ }
+ }
+ return &CycleInRequiresGraphError{AnalyzerNames: inCycle}
+ }
+
return nil
}
for _, a := range analyzers {
@@ -95,3 +110,17 @@
}
return name != ""
}
+
+type CycleInRequiresGraphError struct {
+ AnalyzerNames map[string]bool
+}
+
+func (e *CycleInRequiresGraphError) Error() string {
+ var b strings.Builder
+ b.WriteString("cycle detected involving the following analyzers:")
+ for n := range e.AnalyzerNames {
+ b.WriteByte(' ')
+ b.WriteString(n)
+ }
+ return b.String()
+}