diff --git a/MODULE.bazel b/MODULE.bazel index 8bdc850e3271..1ae226f0e89b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -273,7 +273,7 @@ use_repo( ) go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") -go_sdk.download(version = "1.26.4") +go_sdk.download(version = "1.27rc1") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//go/extractor:go.mod") diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index b73c9d7e6e97..814c39f90103 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -17,7 +17,7 @@ .NET 5, .NET 6, .NET 7, .NET 8, .NET 9, .NET 10","``.sln``, ``.slnx``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" GitHub Actions,"Not applicable",Not applicable,"``.github/workflows/*.yml``, ``.github/workflows/*.yaml``, ``**/action.yml``, ``**/action.yaml``" - Go (aka Golang), "Go up to 1.26", "Go 1.11 or more recent", ``.go`` + Go (aka Golang), "Go up to 1.27", "Go 1.11 or more recent", ``.go`` Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [7]_",``.java`` diff --git a/go/actions/test/action.yml b/go/actions/test/action.yml index 3cc3334d39ed..05184dae1d8e 100644 --- a/go/actions/test/action.yml +++ b/go/actions/test/action.yml @@ -4,7 +4,7 @@ inputs: go-test-version: description: Which Go version to use for running the tests required: false - default: "~1.26.4" + default: "1.27.0-rc.1" run-code-checks: description: Whether to run formatting, code and qhelp generation checks required: false diff --git a/go/extractor/autobuilder/build-environment.go b/go/extractor/autobuilder/build-environment.go index c660373205b2..bd7fc0adabe1 100644 --- a/go/extractor/autobuilder/build-environment.go +++ b/go/extractor/autobuilder/build-environment.go @@ -12,7 +12,7 @@ import ( ) var minGoVersion = util.NewSemVer("1.11") -var maxGoVersion = util.NewSemVer("1.26") +var maxGoVersion = util.NewSemVer("1.27") type versionInfo struct { goModVersion util.SemVer // The version of Go found in the go directive in the `go.mod` file. diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 158f0029704d..98497b0e680d 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -32,7 +32,13 @@ import ( ) var MaxGoRoutines int -var typeParamParent map[*types.TypeParam]types.Object = make(map[*types.TypeParam]types.Object) + +type typeParamParentEntry struct { + parent types.Object + index int +} + +var typeParamParent map[*types.TypeParam]typeParamParentEntry = make(map[*types.TypeParam]typeParamParentEntry) func init() { // this sets the number of threads that the Go runtime will spawn; this is separate @@ -530,8 +536,10 @@ func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label) // do not appear as objects in any scope, so they have to be dealt // with separately in extractMethods. if funcObj, ok := obj.(*types.Func); ok { - populateTypeParamParents(funcObj.Type().(*types.Signature).TypeParams(), obj) - populateTypeParamParents(funcObj.Type().(*types.Signature).RecvTypeParams(), obj) + typeParams := funcObj.Type().(*types.Signature).TypeParams() + populateTypeParamParents(typeParams, obj, 0) + recvTypeParams := funcObj.Type().(*types.Signature).RecvTypeParams() + populateTypeParamParents(recvTypeParams, obj, typeParams.Len()) } // Populate type parameter parents for defined types and alias types. if typeNameObj, ok := obj.(*types.TypeName); ok { @@ -542,9 +550,9 @@ func extractObjects(tw *trap.Writer, scope *types.Scope, scopeLabel trap.Label) // careful with alias types because before Go 1.24 they would // return the underlying type. if tp, ok := typeNameObj.Type().(*types.Named); ok && !typeNameObj.IsAlias() { - populateTypeParamParents(tp.TypeParams(), obj) + populateTypeParamParents(tp.TypeParams(), obj, 0) } else if tp, ok := typeNameObj.Type().(*types.Alias); ok { - populateTypeParamParents(tp.TypeParams(), obj) + populateTypeParamParents(tp.TypeParams(), obj, 0) } } extractObject(tw, obj, lbl) @@ -570,8 +578,10 @@ func extractMethod(tw *trap.Writer, meth *types.Func) trap.Label { if !exists { // Populate type parameter parents for methods. They do not appear as // objects in any scope, so they have to be dealt with separately here. - populateTypeParamParents(meth.Type().(*types.Signature).TypeParams(), meth) - populateTypeParamParents(meth.Type().(*types.Signature).RecvTypeParams(), meth) + typeParams := meth.Type().(*types.Signature).TypeParams() + populateTypeParamParents(typeParams, meth, 0) + recvTypeParams := meth.Type().(*types.Signature).RecvTypeParams() + populateTypeParamParents(recvTypeParams, meth, typeParams.Len()) extractObject(tw, meth, methlbl) } @@ -1660,7 +1670,8 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { // parent scope, so they are not dealt with by `extractScopes` for i := 0; i < origintp.NumMethods(); i++ { meth := origintp.Method(i).Origin() - + typeParams := tp.Method(i).Type().(*types.Signature).TypeParams() + populateTypeParamParents(typeParams, meth, 0) extractMethod(tw, meth) } @@ -1684,9 +1695,9 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { } case *types.TypeParam: kind = dbscheme.TypeParamType.Index() - parentlbl := getTypeParamParentLabel(tw, tp) + parentlbl, idx := getTypeParamParentLabel(tw, tp) constraintLabel := extractType(tw, tp.Constraint()) - dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, tp.Index()) + dbscheme.TypeParamTable.Emit(tw, lbl, tp.Obj().Name(), constraintLabel, parentlbl, idx) case *types.Union: kind = dbscheme.TypeSetLiteral.Index() for i := 0; i < tp.Len(); i++ { @@ -1826,8 +1837,7 @@ func getTypeLabel(tw *trap.Writer, tp types.Type) (trap.Label, bool) { } lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%s};definedtype", entitylbl)) case *types.TypeParam: - parentlbl := getTypeParamParentLabel(tw, tp) - idx := tp.Index() + parentlbl, idx := getTypeParamParentLabel(tw, tp) lbl = tw.Labeler.GlobalID(fmt.Sprintf("{%v},%d,%s;typeparamtype", parentlbl, idx, tp.Obj().Name())) case *types.Union: var b strings.Builder @@ -2013,10 +2023,10 @@ func extractTypeParamDecls(tw *trap.Writer, fields *ast.FieldList, parent trap.L } // populateTypeParamParents sets `parent` as the parent of the elements of `typeparams` -func populateTypeParamParents(typeparams *types.TypeParamList, parent types.Object) { +func populateTypeParamParents(typeparams *types.TypeParamList, parent types.Object, offset int) { if typeparams != nil { for idx := 0; idx < typeparams.Len(); idx++ { - setTypeParamParent(typeparams.At(idx), parent) + setTypeParamParent(typeparams.At(idx), parent, idx+offset) } } } @@ -2065,24 +2075,24 @@ func trackInstantiatedStructFields(tw *trap.Writer, tp, origintp *types.Named) { } } -func getTypeParamParentLabel(tw *trap.Writer, tp *types.TypeParam) trap.Label { - parent, exists := typeParamParent[tp] +func getTypeParamParentLabel(tw *trap.Writer, tp *types.TypeParam) (trap.Label, int) { + entry, exists := typeParamParent[tp] if !exists { log.Fatalf("Parent of type parameter does not exist: %s %s", tp.String(), tp.Constraint().String()) } - parentlbl, _ := tw.Labeler.ScopedObjectID(parent, func() trap.Label { + parentlbl, _ := tw.Labeler.ScopedObjectID(entry.parent, func() trap.Label { log.Fatalf("getTypeLabel() called for parent of type parameter %s", tp.String()) return trap.InvalidLabel }) - return parentlbl + return parentlbl, entry.index } -func setTypeParamParent(tp *types.TypeParam, newobj types.Object) { - obj, exists := typeParamParent[tp] +func setTypeParamParent(tp *types.TypeParam, newobj types.Object, idx int) { + entry, exists := typeParamParent[tp] if !exists { - typeParamParent[tp] = newobj - } else if newobj != obj { - log.Fatalf("Parent of type parameter '%s %s' being set to a different value: '%s' vs '%s'", tp.String(), tp.Constraint().String(), obj, newobj) + typeParamParent[tp] = typeParamParentEntry{newobj, idx} + } else if entry.parent != newobj || entry.index != idx { + log.Fatalf("Parent of type parameter '%s %s' being set to a different value: '%s' vs '%s'", tp.String(), tp.Constraint().String(), entry.parent, newobj) } } diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 5de56683a3e0..e986a0706d14 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -1,8 +1,8 @@ module github.com/github/codeql-go/extractor -go 1.26 +go 1.27 -toolchain go1.26.4 +toolchain go1.27rc1 // when updating this, run // bazel run @rules_go//go -- mod tidy diff --git a/go/extractor/toolchain/toolchain_test.go b/go/extractor/toolchain/toolchain_test.go index 8a6b38318cb9..a62c9016a700 100644 --- a/go/extractor/toolchain/toolchain_test.go +++ b/go/extractor/toolchain/toolchain_test.go @@ -8,9 +8,9 @@ import ( func TestParseGoVersion(t *testing.T) { tests := map[string]string{ - "go version go1.18.9 linux/amd64": "go1.18.9", - "go version go1.26.3-X:nodwarf5 linux/amd64": "go1.26.3", - "go version go1.26.3rc1 linux/amd64": "go1.26.3rc1", + "go version go1.18.9 linux/amd64": "go1.18.9", + "go version go1.26.3-X:nodwarf5 linux/amd64": "go1.26.3", + "go version go1.26.3rc1 linux/amd64": "go1.26.3rc1", "warning: GOPATH set to GOROOT (/usr/local/go) has no effect\ngo version go1.18.9 linux/amd64": "go1.18.9", } for input, expected := range tests { diff --git a/go/extractor/trap/labels.go b/go/extractor/trap/labels.go index 473e2e761f2e..ca43bc370252 100644 --- a/go/extractor/trap/labels.go +++ b/go/extractor/trap/labels.go @@ -187,7 +187,7 @@ func findMethodOnTypeWithGivenReceiver(tp types.Type, object types.Object) *type if definedType, ok := tp.(*types.Named); ok { for i := 0; i < definedType.NumMethods(); i++ { meth := definedType.Method(i) - if object == meth.Type().(*types.Signature).Recv() { + if object == meth.Type().(*types.Signature).Recv().Origin() { return meth } } diff --git a/go/ql/lib/change-notes/2026-06-25-go-1.27.md b/go/ql/lib/change-notes/2026-06-25-go-1.27.md new file mode 100644 index 000000000000..b1998aee7f54 --- /dev/null +++ b/go/ql/lib/change-notes/2026-06-25-go-1.27.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Go 1.27 is now supported. diff --git a/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected b/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected index 6528a0ae7f3d..5c01d626b28a 100644 --- a/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected +++ b/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected @@ -6,3 +6,5 @@ | genericFunctions.go:45:6:45:50 | generic function instantiation expression | genericFunctions.go:45:6:45:33 | GenericFunctionTwoTypeParams | 1 | genericFunctions.go:45:43:45:49 | float64 | | genericFunctions.go:141:6:141:41 | generic function instantiation expression | genericFunctions.go:141:6:141:33 | GenericFunctionInAnotherFile | 0 | genericFunctions.go:141:35:141:40 | string | | genericFunctions.go:146:6:146:55 | generic function instantiation expression | genericFunctions.go:146:6:146:47 | selection of GenericFunctionInAnotherPackage | 0 | genericFunctions.go:146:49:146:54 | string | +| genericMethods.go:13:2:13:23 | generic function instantiation expression | genericMethods.go:13:2:13:18 | selection of GenericMethod1 | 0 | genericMethods.go:13:20:13:22 | int | +| genericMethods.go:14:2:14:26 | generic function instantiation expression | genericMethods.go:14:2:14:18 | selection of GenericMethod2 | 0 | genericMethods.go:14:20:14:25 | string | diff --git a/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected b/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected index bda7c1517975..838528965070 100644 --- a/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected +++ b/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected @@ -19,6 +19,9 @@ numberOfTypeParameters | genericFunctions.go:150:6:150:36 | multipleAnonymousTypeParamsFunc | 3 | | genericFunctions.go:152:6:152:36 | multipleAnonymousTypeParamsType | 3 | | genericFunctions.go:154:51:154:51 | f | 3 | +| genericMethods.go:5:33:5:46 | GenericMethod1 | 1 | +| genericMethods.go:7:6:7:28 | StructForGenericMethod2 | 1 | +| genericMethods.go:9:36:9:49 | GenericMethod2 | 2 | #select | codeql-go-tests/function.EdgeConstraint | 0 | Node | interface { } | | codeql-go-tests/function.Element | 0 | S | interface { } | @@ -44,6 +47,10 @@ numberOfTypeParameters | codeql-go-tests/function.New | 0 | Node | NodeConstraint | | codeql-go-tests/function.New | 1 | Edge | EdgeConstraint | | codeql-go-tests/function.NodeConstraint | 0 | Edge | interface { } | +| codeql-go-tests/function.StructForGenericMethod1.GenericMethod1 | 0 | P | interface { } | +| codeql-go-tests/function.StructForGenericMethod2 | 0 | P | interface { } | +| codeql-go-tests/function.StructForGenericMethod2.GenericMethod2 | 0 | Q | interface { } | +| codeql-go-tests/function.StructForGenericMethod2.GenericMethod2 | 1 | P | interface { } | | codeql-go-tests/function.multipleAnonymousTypeParamsFunc | 0 | _ | interface { } | | codeql-go-tests/function.multipleAnonymousTypeParamsFunc | 1 | _ | interface { string } | | codeql-go-tests/function.multipleAnonymousTypeParamsFunc | 2 | _ | interface { } | diff --git a/go/ql/test/library-tests/semmle/go/Function/genericMethods.go b/go/ql/test/library-tests/semmle/go/Function/genericMethods.go new file mode 100644 index 000000000000..19c98a2f1cfb --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/Function/genericMethods.go @@ -0,0 +1,19 @@ +package main + +type StructForGenericMethod1 struct{} + +func (*StructForGenericMethod1) GenericMethod1[P any](x P) {} + +type StructForGenericMethod2[P any] struct{} + +func (*StructForGenericMethod2[P]) GenericMethod2[Q any](x Q) {} + +func generic_methods(s1 StructForGenericMethod1, s2 StructForGenericMethod2[int]) { + // Call the generic method specifying the type + s1.GenericMethod1[int](1) + s2.GenericMethod2[string]("hello") + + // Call the generic method without specifying the type + s1.GenericMethod1("hello") + s2.GenericMethod2(42) +} diff --git a/go/ql/test/library-tests/semmle/go/Function/getParameter.expected b/go/ql/test/library-tests/semmle/go/Function/getParameter.expected index 80171d5e79a6..38b3d78b50df 100644 --- a/go/ql/test/library-tests/semmle/go/Function/getParameter.expected +++ b/go/ql/test/library-tests/semmle/go/Function/getParameter.expected @@ -11,6 +11,10 @@ | genericFunctions.go:138:29:138:40 | ShortestPath | 1 | genericFunctions.go:138:48:138:49 | to | | genericFunctions.go:138:29:138:40 | ShortestPath | -1 | genericFunctions.go:138:7:138:7 | g | | genericFunctions.go:154:51:154:51 | f | -1 | genericFunctions.go:154:7:154:7 | x | +| genericMethods.go:5:33:5:46 | GenericMethod1 | 0 | genericMethods.go:5:55:5:55 | x | +| genericMethods.go:9:36:9:49 | GenericMethod2 | 0 | genericMethods.go:9:58:9:58 | x | +| genericMethods.go:11:6:11:20 | generic_methods | 0 | genericMethods.go:11:22:11:23 | s1 | +| genericMethods.go:11:6:11:20 | generic_methods | 1 | genericMethods.go:11:50:11:51 | s2 | | main.go:7:6:7:7 | f1 | 0 | main.go:7:9:7:9 | x | | main.go:9:12:9:13 | f2 | 0 | main.go:9:15:9:15 | x | | main.go:9:12:9:13 | f2 | 1 | main.go:9:18:9:18 | y | diff --git a/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected b/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected index 27a89adf95e2..83270b9db3d3 100644 --- a/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected +++ b/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected @@ -19,3 +19,6 @@ | genericFunctions.go:152:6:152:69 | type declaration specifier | TypeSpec | 0 | genericFunctions.go:152:38:152:42 | type parameter declaration | 0 | genericFunctions.go:152:38:152:38 | _ | genericFunctions.go:152:40:152:42 | any | interface { } | | genericFunctions.go:152:6:152:69 | type declaration specifier | TypeSpec | 1 | genericFunctions.go:152:45:152:52 | type parameter declaration | 0 | genericFunctions.go:152:45:152:45 | _ | genericFunctions.go:152:47:152:52 | string | interface { string } | | genericFunctions.go:152:6:152:69 | type declaration specifier | TypeSpec | 2 | genericFunctions.go:152:55:152:59 | type parameter declaration | 0 | genericFunctions.go:152:55:152:55 | _ | genericFunctions.go:152:57:152:59 | any | interface { } | +| genericMethods.go:5:1:5:61 | function declaration | MethodDecl | 0 | genericMethods.go:5:48:5:52 | type parameter declaration | 0 | genericMethods.go:5:48:5:48 | P | genericMethods.go:5:50:5:52 | any | interface { } | +| genericMethods.go:7:6:7:44 | type declaration specifier | TypeSpec | 0 | genericMethods.go:7:30:7:34 | type parameter declaration | 0 | genericMethods.go:7:30:7:30 | P | genericMethods.go:7:32:7:34 | any | interface { } | +| genericMethods.go:9:1:9:64 | function declaration | MethodDecl | 0 | genericMethods.go:9:51:9:55 | type parameter declaration | 0 | genericMethods.go:9:51:9:51 | Q | genericMethods.go:9:53:9:55 | any | interface { } | diff --git a/go/ql/test/library-tests/semmle/go/Function/go.mod b/go/ql/test/library-tests/semmle/go/Function/go.mod index 85d3db5c5a37..9c06e02b0eda 100644 --- a/go/ql/test/library-tests/semmle/go/Function/go.mod +++ b/go/ql/test/library-tests/semmle/go/Function/go.mod @@ -1,6 +1,8 @@ module codeql-go-tests/function -go 1.18 +go 1.27 + +toolchain go1.27rc1 require github.com/anotherpkg v0.0.0-20200203000000-0000000000000