|
| 1 | +package java |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + |
| 6 | + lib "github.com/nedpals/errgoengine" |
| 7 | +) |
| 8 | + |
| 9 | +type noSuchElementExceptionCtx struct { |
| 10 | + parentNode lib.SyntaxNode |
| 11 | + grandParentNode lib.SyntaxNode |
| 12 | +} |
| 13 | + |
| 14 | +var NoSuchElementException = lib.ErrorTemplate{ |
| 15 | + Name: "NoSuchElementException", |
| 16 | + Pattern: runtimeErrorPattern("java.util.NoSuchElementException", ""), |
| 17 | + OnAnalyzeErrorFn: func(cd *lib.ContextData, m *lib.MainError) { |
| 18 | + ctx := noSuchElementExceptionCtx{} |
| 19 | + query := `(method_invocation object: (_) name: (identifier) @fn-name arguments: (argument_list) (#eq? @fn-name "next")) @call` |
| 20 | + for q := m.Nearest.Query(query); q.Next(); { |
| 21 | + if q.CurrentTagName() != "fn-name" { |
| 22 | + continue |
| 23 | + } |
| 24 | + |
| 25 | + node := q.CurrentNode() |
| 26 | + // nCtx.ArrayExprNode = node |
| 27 | + // m.Nearest = node.ChildByFieldName("dimensions").NamedChild(0) |
| 28 | + m.Nearest = node |
| 29 | + } |
| 30 | + |
| 31 | + ctx.parentNode = m.Nearest.Parent() // expr -> method_invocation |
| 32 | + |
| 33 | + // get grandparent node |
| 34 | + ctx.grandParentNode = ctx.parentNode.Parent() |
| 35 | + if !ctx.grandParentNode.IsNull() { |
| 36 | + if ctx.grandParentNode.Type() == "expression_statement" || ctx.grandParentNode.Type() == "variable_declarator" { |
| 37 | + ctx.grandParentNode = ctx.grandParentNode.Parent() |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + m.Context = ctx |
| 42 | + }, |
| 43 | + OnGenExplainFn: func(cd *lib.ContextData, gen *lib.ExplainGenerator) { |
| 44 | + gen.Add("This error occurs when attempting to retrieve an element from an empty collection using an iterator.") |
| 45 | + }, |
| 46 | + OnGenBugFixFn: func(cd *lib.ContextData, gen *lib.BugFixGenerator) { |
| 47 | + ctx := cd.MainError.Context.(noSuchElementExceptionCtx) |
| 48 | + // TODO: detect the statements that are using the variable to expand the position range of the if statement |
| 49 | + |
| 50 | + gen.Add("Check if the iterator has next elements before calling `next()`", func(s *lib.BugFixSuggestion) { |
| 51 | + step := s.AddStep("Ensure that the iterator has elements before attempting to retrieve the next one.") |
| 52 | + gpLocation := ctx.grandParentNode.Location() |
| 53 | + parentName := ctx.parentNode.ChildByFieldName("object").Text() |
| 54 | + // TODO: detect the statements that are using the variable to expand the position range of the if statement |
| 55 | + wrapWithCondStatement( |
| 56 | + step, |
| 57 | + cd.MainError.Document, |
| 58 | + "if", |
| 59 | + fmt.Sprintf("%s.hasNext()", parentName), |
| 60 | + gpLocation, |
| 61 | + false, |
| 62 | + ) |
| 63 | + |
| 64 | + wrapWithCondStatement( |
| 65 | + step, |
| 66 | + cd.MainError.Document, |
| 67 | + "else", |
| 68 | + "", |
| 69 | + lib.Location{ |
| 70 | + StartPos: gpLocation.EndPos, |
| 71 | + EndPos: gpLocation.EndPos, |
| 72 | + }, |
| 73 | + true, |
| 74 | + ) |
| 75 | + |
| 76 | + space := getSpace( |
| 77 | + cd.MainError.Document, |
| 78 | + gpLocation.StartPos.Line, 0, gpLocation.StartPos.Column, true) |
| 79 | + |
| 80 | + step.AddFix(lib.FixSuggestion{ |
| 81 | + NewText: indentSpace(space, 1) + `System.out.println("No elements in the list.")`, |
| 82 | + StartPosition: lib.Position{ |
| 83 | + Line: gpLocation.EndPos.Line - 2, |
| 84 | + }, |
| 85 | + EndPosition: lib.Position{ |
| 86 | + Line: gpLocation.EndPos.Line - 2, |
| 87 | + }, |
| 88 | + }) |
| 89 | + }) |
| 90 | + }, |
| 91 | +} |
0 commit comments