computeErrorLocation implements a heuristic to find the location in the user code where the error occurred. It walks back the callstack until the file doesn't match "/goa/design/*.go" or one of the DSL package paths. When successful it returns the file name and line number, empty string and 0 otherw
()
| 67 | // When successful it returns the file name and line number, empty string and |
| 68 | // 0 otherwise. |
| 69 | func computeErrorLocation() (file string, line int) { |
| 70 | shouldSkip := func(file, name string) bool { |
| 71 | if strings.HasSuffix(file, "_test.go") { // Be nice with tests |
| 72 | return false |
| 73 | } |
| 74 | if isGoaSourceFile(file) { |
| 75 | return true |
| 76 | } |
| 77 | file = filepath.ToSlash(file) |
| 78 | normalized := normalizeFileForPackageMatch(file) |
| 79 | for _, pkg := range Context.dslPackages { |
| 80 | if strings.Contains(file, pkg) || strings.Contains(normalized, pkg) || strings.Contains(name, pkg) { |
| 81 | return true |
| 82 | } |
| 83 | } |
| 84 | return false |
| 85 | } |
| 86 | |
| 87 | // Start scanning just above computeErrorLocation itself. This is robust to |
| 88 | // inlining and avoids hardcoding assumptions about the exact call depth. |
| 89 | const skip = 2 |
| 90 | pcs := make([]uintptr, 32) |
| 91 | n := runtime.Callers(skip, pcs) |
| 92 | frames := runtime.CallersFrames(pcs[:n]) |
| 93 | for { |
| 94 | frame, more := frames.Next() |
| 95 | if frame.File == "" || frame.Line == 0 { |
| 96 | if !more { |
| 97 | break |
| 98 | } |
| 99 | continue |
| 100 | } |
| 101 | if !shouldSkip(frame.File, frame.Function) { |
| 102 | return relativeToWorkdir(frame.File), frame.Line |
| 103 | } |
| 104 | if !more { |
| 105 | break |
| 106 | } |
| 107 | } |
| 108 | return "", 0 |
| 109 | } |
| 110 | |
| 111 | // isGoaSourceFile reports whether file points into the Goa module sources. |
| 112 | // |
no test coverage detected