diff --git a/.custom-gcl.yml b/.custom-gcl.yml index 311dc036bd..6d623f2eb4 100644 --- a/.custom-gcl.yml +++ b/.custom-gcl.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://golangci-lint.run/jsonschema/custom-gcl.jsonschema.json -version: v2.5.0 +version: v2.6.0 destination: ./_tools diff --git a/.golangci.yml b/.golangci.yml index d08578a81b..469b2bbbb1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -33,6 +33,7 @@ linters: - makezero - mirror - misspell + - modernize - musttag - nakedret - nolintlint diff --git a/internal/ast/ast.go b/internal/ast/ast.go index 2971ef562d..9924378ac3 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -24,7 +24,7 @@ func visit(v Visitor, node *Node) bool { } func visitNodes(v Visitor, nodes []*Node) bool { - for _, node := range nodes { + for _, node := range nodes { //nolint:modernize if v(node) { return true } diff --git a/internal/binder/binder.go b/internal/binder/binder.go index 1824ffcac1..edb632d504 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -2640,7 +2640,7 @@ func isNarrowableReference(node *ast.Node) bool { func hasNarrowableArgument(expr *ast.Node) bool { call := expr.AsCallExpression() - for _, argument := range call.Arguments.Nodes { + for _, argument := range call.Arguments.Nodes { //nolint:modernize if containsNarrowableReference(argument) { return true } diff --git a/internal/checker/grammarchecks.go b/internal/checker/grammarchecks.go index 644c4d9604..ff30650d5d 100644 --- a/internal/checker/grammarchecks.go +++ b/internal/checker/grammarchecks.go @@ -900,7 +900,7 @@ func (c *Checker) checkGrammarHeritageClause(node *ast.HeritageClause) bool { return c.grammarErrorAtPos(node.AsNode(), types.Pos(), 0, diagnostics.X_0_list_cannot_be_empty, listType) } - for _, node := range types.Nodes { + for _, node := range types.Nodes { //nolint:modernize if c.checkGrammarExpressionWithTypeArguments(node) { return true } diff --git a/internal/checker/mapper.go b/internal/checker/mapper.go index da13ffafb4..bc9bd9b00f 100644 --- a/internal/checker/mapper.go +++ b/internal/checker/mapper.go @@ -1,6 +1,10 @@ package checker -import "github.com/microsoft/typescript-go/internal/core" +import ( + "slices" + + "github.com/microsoft/typescript-go/internal/core" +) // TypeMapperKind @@ -158,10 +162,8 @@ func newArrayToSingleTypeMapper(sources []*Type, target *Type) *TypeMapper { } func (m *ArrayToSingleTypeMapper) Map(t *Type) *Type { - for _, s := range m.sources { - if t == s { - return m.target - } + if slices.Contains(m.sources, t) { + return m.target } return t } diff --git a/internal/checker/nodebuilderimpl.go b/internal/checker/nodebuilderimpl.go index 5ac9b95369..902173172f 100644 --- a/internal/checker/nodebuilderimpl.go +++ b/internal/checker/nodebuilderimpl.go @@ -2034,10 +2034,8 @@ func (b *nodeBuilderImpl) shouldUsePlaceholderForProperty(propertySymbol *ast.Sy return false } // (1) - for _, elem := range b.ctx.reverseMappedStack { - if elem == propertySymbol { - return true - } + if slices.Contains(b.ctx.reverseMappedStack, propertySymbol) { + return true } // (2) if len(b.ctx.reverseMappedStack) > 0 { diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index 9fbbc49057..8779739573 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -638,16 +638,22 @@ func getLibraryNameFromLibFileName(libFileName string) string { // lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable // lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown components := strings.Split(libFileName, ".") - var path string + var path strings.Builder + path.WriteString("@typescript/lib-") if len(components) > 1 { - path = components[1] + path.WriteString(components[1]) } i := 2 for i < len(components) && components[i] != "" && components[i] != "d" { - path += core.IfElse(i == 2, "/", "-") + components[i] + if i == 2 { + path.WriteByte('/') + } else { + path.WriteByte('-') + } + path.WriteString(components[i]) i++ } - return "@typescript/lib-" + path + return path.String() } func getInferredLibraryNameResolveFrom(options *core.CompilerOptions, currentDirectory string, libFileName string) string { diff --git a/internal/compiler/projectreferenceparser.go b/internal/compiler/projectreferenceparser.go index f6dd57b4af..482644805c 100644 --- a/internal/compiler/projectreferenceparser.go +++ b/internal/compiler/projectreferenceparser.go @@ -1,6 +1,8 @@ package compiler import ( + "maps" + "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/tsoptions" @@ -91,12 +93,8 @@ func (p *projectReferenceParser) initMapperWorker(tasks []*projectReferenceParse if task.resolved == nil || p.loader.projectReferenceFileMapper.opts.Config.ConfigFile == task.resolved.ConfigFile { continue } - for key, value := range task.resolved.SourceToProjectReference() { - p.loader.projectReferenceFileMapper.sourceToProjectReference[key] = value - } - for key, value := range task.resolved.OutputDtsToProjectReference() { - p.loader.projectReferenceFileMapper.outputDtsToProjectReference[key] = value - } + maps.Copy(p.loader.projectReferenceFileMapper.sourceToProjectReference, task.resolved.SourceToProjectReference()) + maps.Copy(p.loader.projectReferenceFileMapper.outputDtsToProjectReference, task.resolved.OutputDtsToProjectReference()) if p.loader.projectReferenceFileMapper.opts.canUseProjectReferenceSource() { declDir := task.resolved.CompilerOptions().DeclarationDir if declDir == "" { diff --git a/internal/core/core.go b/internal/core/core.go index e1a997199f..6c075d488d 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -160,7 +160,7 @@ func Same[T any](s1 []T, s2 []T) bool { } func Some[T any](slice []T, f func(T) bool) bool { - for _, value := range slice { + for _, value := range slice { //nolint:modernize if f(value) { return true } @@ -407,12 +407,9 @@ func ComputeECMALineStartsSeq(text string) iter.Seq[TextPos] { } func PositionToLineAndCharacter(position int, lineStarts []TextPos) (line int, character int) { - line = sort.Search(len(lineStarts), func(i int) bool { + line = max(sort.Search(len(lineStarts), func(i int) bool { return int(lineStarts[i]) > position - }) - 1 - if line < 0 { - line = 0 - } + })-1, 0) return line, position - int(lineStarts[line]) } diff --git a/internal/core/workgroup.go b/internal/core/workgroup.go index fcdd133226..73618a1a19 100644 --- a/internal/core/workgroup.go +++ b/internal/core/workgroup.go @@ -36,11 +36,9 @@ func (w *parallelWorkGroup) Queue(fn func()) { panic("Queue called after RunAndWait returned") } - w.wg.Add(1) - go func() { - defer w.wg.Done() + w.wg.Go(func() { fn() - }() + }) } func (w *parallelWorkGroup) RunAndWait() { diff --git a/internal/execute/tsctests/runner.go b/internal/execute/tsctests/runner.go index 7cb8c261bd..61f2b12163 100644 --- a/internal/execute/tsctests/runner.go +++ b/internal/execute/tsctests/runner.go @@ -119,7 +119,7 @@ func (test *tscInput) run(t *testing.T, scenario string) { baselineBuilder.WriteString(fmt.Sprintf("\n\nDiff:: %s\n", core.IfElse(do.expectedDiff == "", "!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!", do.expectedDiff))) baselineBuilder.WriteString(diff) if do.expectedDiff == "" { - unexpectedDiff += fmt.Sprintf("Edit [%d]:: %s\n!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!\n%s\n", index, do.caption, diff) + unexpectedDiff += fmt.Sprintf("Edit [%d]:: %s\n!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!\n%s\n", index, do.caption, diff) //nolint:perfsprint } } else if do.expectedDiff != "" { baselineBuilder.WriteString(fmt.Sprintf("\n\nDiff:: %s !!! Diff not found but explanation present, please review and remove the explanation !!!\n", do.expectedDiff)) diff --git a/internal/fourslash/baselineutil.go b/internal/fourslash/baselineutil.go index 6512ec5321..38f88ba606 100644 --- a/internal/fourslash/baselineutil.go +++ b/internal/fourslash/baselineutil.go @@ -591,7 +591,7 @@ func (t *textWithContext) sliceOfContent(start *int, end *int) string { return t.content[*start:*end] } -func (t *textWithContext) getIndex(i interface{}) *int { +func (t *textWithContext) getIndex(i any) *int { switch i := i.(type) { case *int: return i diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 7dcb546e2f..dd1c95c9c8 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -824,12 +824,7 @@ func (f *FourslashTest) verifyCompletionsAreExactly(t *testing.T, prefix string, func ignorePaths(paths ...string) cmp.Option { return cmp.FilterPath( func(p cmp.Path) bool { - for _, path := range paths { - if p.Last().String() == path { - return true - } - } - return false + return slices.Contains(paths, p.Last().String()) }, cmp.Ignore(), ) diff --git a/internal/fourslash/test_parser.go b/internal/fourslash/test_parser.go index fb9e2c924a..3215f5619f 100644 --- a/internal/fourslash/test_parser.go +++ b/internal/fourslash/test_parser.go @@ -407,13 +407,13 @@ func parseFileContent(fileName string, content string, fileOptions map[string]st func getObjectMarker(fileName string, location *locationInformation, text string) (*Marker, error) { // Attempt to parse the marker value as JSON - var v interface{} + var v any e := json.Unmarshal([]byte("{ "+text+" }"), &v) if e != nil { return nil, reportError(fileName, location.sourceLine, location.sourceColumn, "Unable to parse marker text "+text) } - markerValue, ok := v.(map[string]interface{}) + markerValue, ok := v.(map[string]any) if !ok || len(markerValue) == 0 { return nil, reportError(fileName, location.sourceLine, location.sourceColumn, "Object markers can not be empty") } diff --git a/internal/glob/glob.go b/internal/glob/glob.go index f54f691a0d..39df996428 100644 --- a/internal/glob/glob.go +++ b/internal/glob/glob.go @@ -217,7 +217,7 @@ func (g *Glob) Match(input string) bool { } func match(elems []element, input string) (ok bool) { - var elem interface{} + var elem any for len(elems) > 0 { elem, elems = elems[0], elems[1:] switch elem := elem.(type) { diff --git a/internal/ls/completions.go b/internal/ls/completions.go index b09040182d..7cbf947f92 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -2409,9 +2409,9 @@ func getFilterText( dotAccessor string, ) string { // Private field completion, e.g. label `#bar`. - if strings.HasPrefix(label, "#") { + if after, ok := strings.CutPrefix(label, "#"); ok { if insertText != "" { - if strings.HasPrefix(insertText, "this.#") { + if after, ok := strings.CutPrefix(insertText, "this.#"); ok { if wordStart == '#' { // `method() { this.#| }` // `method() { #| }` @@ -2419,7 +2419,7 @@ func getFilterText( } else { // `method() { this.| }` // `method() { | }` - return strings.TrimPrefix(insertText, "this.#") + return after } } } else { @@ -2429,7 +2429,7 @@ func getFilterText( } else { // `method() { this.| }` // `method() { | }` - return strings.TrimPrefix(label, "#") + return after } } } @@ -3187,7 +3187,7 @@ func isNamedImportsOrExports(node *ast.Node) bool { func generateIdentifierForArbitraryString(text string) string { needsUnderscore := false - identifier := "" + var identifier strings.Builder var ch rune var size int @@ -3202,9 +3202,9 @@ func generateIdentifierForArbitraryString(text string) string { } if size > 0 && validChar { if needsUnderscore { - identifier += "_" + identifier.WriteRune('_') } - identifier += string(ch) + identifier.WriteRune(ch) needsUnderscore = false } else { needsUnderscore = true @@ -3212,15 +3212,16 @@ func generateIdentifierForArbitraryString(text string) string { } if needsUnderscore { - identifier += "_" + identifier.WriteRune('_') } // Default to "_" if the provided text was empty - if identifier == "" { + id := identifier.String() + if id == "" { return "_" } - return identifier + return id } // Copied from vscode TS extension. diff --git a/internal/ls/lsutil/userpreferences.go b/internal/ls/lsutil/userpreferences.go index dd900658ce..054507dbaa 100644 --- a/internal/ls/lsutil/userpreferences.go +++ b/internal/ls/lsutil/userpreferences.go @@ -364,7 +364,7 @@ func (p *UserPreferences) Parse(item any) *UserPreferences { return nil } -func (p *UserPreferences) parseWorker(config map[string]interface{}) { +func (p *UserPreferences) parseWorker(config map[string]any) { // Process unstable preferences first so that they do not overwrite stable properties if unstable, ok := config["unstable"]; ok { // unstable properties must be named the same as userPreferences diff --git a/internal/ls/signaturehelp.go b/internal/ls/signaturehelp.go index b1d33260c8..8cc913ce57 100644 --- a/internal/ls/signaturehelp.go +++ b/internal/ls/signaturehelp.go @@ -3,6 +3,7 @@ package ls import ( "context" "fmt" + "slices" "strings" "github.com/microsoft/typescript-go/internal/ast" @@ -586,7 +587,7 @@ func isSyntacticOwner(startingToken *ast.Node, node *ast.CallLikeExpression, sou invocationChildren := getChildrenFromNonJSDocNode(node, sourceFile) switch startingToken.Kind { case ast.KindOpenParenToken, ast.KindCommaToken: - return containsNode(invocationChildren, startingToken) + return slices.Contains(invocationChildren, startingToken) case ast.KindLessThanToken: return containsPrecedingToken(startingToken, sourceFile, node.AsCallExpression().Expression) default: @@ -1102,15 +1103,6 @@ func getTokenFromNodeList(nodeList *ast.NodeList, nodeListParent *ast.Node, sour return tokens } -func containsNode(nodes []*ast.Node, node *ast.Node) bool { - for i := range nodes { - if nodes[i] == node { - return true - } - } - return false -} - func getArgumentListInfoForTemplate(tagExpression *ast.TaggedTemplateExpression, argumentIndex int, sourceFile *ast.SourceFile) *argumentListInfo { // argumentCount is either 1 or (numSpans + 1) to account for the template strings array argument. argumentCount := 1 diff --git a/internal/module/resolver_test.go b/internal/module/resolver_test.go index 37330dc8d5..42ca2f6cbb 100644 --- a/internal/module/resolver_test.go +++ b/internal/module/resolver_test.go @@ -315,11 +315,9 @@ func runTraceBaseline(t *testing.T, test traceTestCase) { var wg sync.WaitGroup for _, call := range test.calls { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { doCall(t, concurrentResolver, call, true /*skipLocations*/) - }() + }) } wg.Wait() diff --git a/internal/parser/parser.go b/internal/parser/parser.go index a51566f02d..951520f095 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -611,7 +611,7 @@ func (p *Parser) isInSomeParsingContext() bool { // We should be in at least one parsing context, be it SourceElements while parsing // a SourceFile, or JSDocComment when lazily parsing JSDoc. debug.Assert(p.parsingContexts != 0, "Missing parsing context") - for kind := ParsingContext(0); kind < PCCount; kind++ { + for kind := range PCCount { if p.parsingContexts&(1<