Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2023-03-02 10:53:13 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2023-03-02 11:41:21 +0300
commitd7a5f22faf841819669d29ccf4e431fc3b2d9b76 (patch)
treea1002bae46450a9974609ee9ec3995f5c3d8d384 /tools/golangci-lint/gitaly/matcher.go
parentc7695bd902060be80b3499ffd2bd9e86d89c4f4f (diff)
tools: Fix incompatible dependencies for new Gitaly linter
In d1c74493a (Add golangci-lint custom linter infrastructure, 2023-02-15), we have added a Gitaly-specific custom linter that is plugged into golangci-lint. For the time being, we agreed to just make it use the same `go.mod` as the main module, mostly because we wanted `make test` to also execute its tests. This is causing problems already, though. The Renovate bot has decided to immediately try and upgrade the new dependency on golang.org/x/tools to the most recent version. But this causes CI failures now because golangci-lint requires all plugins to always use the same version of that package as it uses itself. Fix this by moving the Gitaly-specific linting infrastructure into a subpackage of `tools/golangci-lint` and make it reuse the `go.mod` file. This ensures that they always use compatible versions and that the main production-level `go.mod` file is not tied to a specific dependency version.
Diffstat (limited to 'tools/golangci-lint/gitaly/matcher.go')
-rw-r--r--tools/golangci-lint/gitaly/matcher.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/tools/golangci-lint/gitaly/matcher.go b/tools/golangci-lint/gitaly/matcher.go
new file mode 100644
index 000000000..9b180a726
--- /dev/null
+++ b/tools/golangci-lint/gitaly/matcher.go
@@ -0,0 +1,88 @@
+package main
+
+import (
+ "go/ast"
+ "go/types"
+ "regexp"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+// Matcher implements some helper methods to filter relevant AST nodes for linter checks. It depends
+// on the TypeInfo of analysis.Pass object passed in the analyzer.
+type Matcher struct {
+ typesInfo *types.Info
+}
+
+// NewMatcher creates a new Matcher object from the input analysis pass.
+func NewMatcher(pass *analysis.Pass) *Matcher {
+ return &Matcher{
+ typesInfo: pass.TypesInfo,
+ }
+}
+
+var funcNamePattern = regexp.MustCompile(`^\(?([^\\)].*)\)?\.(.*)$`)
+
+// MatchFunction returns true if the input call expression matches any of the list of input rules.
+// A rule is a human-friend full name of a function. Some examples:
+// - A public package function:
+// "fmt.Errorf"
+// - Match all package functions:
+// "fmt.*"
+// - A public function of a dependent package:
+// "gitlab.com/gitlab-org/gitaly/v15/internal/structerr.NewInternal",
+// - A function of a struct inside a package:
+// "(*gitlab.com/gitlab-org/gitaly/v15/internal/structerr.Error).Unwrap",
+//
+// This Matcher doesn't support interface match (yet).
+func (m *Matcher) MatchFunction(call *ast.CallExpr, rules []string) bool {
+ name := m.functionName(call)
+ if name == "" {
+ return false
+ }
+ for _, rule := range rules {
+ if m.matchRule(name, rule) {
+ return true
+ }
+ }
+ return false
+}
+
+func (m *Matcher) matchRule(name, rule string) bool {
+ nameMatches := funcNamePattern.FindStringSubmatch(name)
+ if len(nameMatches) == 0 {
+ return false
+ }
+
+ ruleMatches := funcNamePattern.FindStringSubmatch(rule)
+ if len(ruleMatches) == 0 {
+ return false
+ }
+
+ if nameMatches[1] != ruleMatches[1] {
+ return false
+ }
+
+ return ruleMatches[2] == "*" || nameMatches[2] == ruleMatches[2]
+}
+
+func (m *Matcher) functionName(call *ast.CallExpr) string {
+ fn, ok := m.getFunction(call)
+ if !ok {
+ return ""
+ }
+
+ return fn.FullName()
+}
+
+func (m *Matcher) getFunction(call *ast.CallExpr) (*types.Func, bool) {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return nil, false
+ }
+ fn, ok := m.typesInfo.ObjectOf(sel.Sel).(*types.Func)
+ if !ok {
+ return nil, false
+ }
+ return fn, true
+}