diff --git a/error_templates/java/array_required_type_error.go b/error_templates/java/array_required_type_error.go index c263423..afe7c9d 100644 --- a/error_templates/java/array_required_type_error.go +++ b/error_templates/java/array_required_type_error.go @@ -1,6 +1,9 @@ package java import ( + "fmt" + "strings" + lib "github.com/nedpals/errgoengine" ) @@ -8,11 +11,66 @@ var ArrayRequiredTypeError = lib.ErrorTemplate{ Name: "ArrayRequiredTypeError", Pattern: comptimeErrorPattern(`array required, but (?P\S+) found`), StackTracePattern: comptimeStackTracePattern, + OnAnalyzeErrorFn: func(cd *lib.ContextData, err *lib.MainError) { + query := strings.NewReader("(array_access array: (identifier) index: ((_) @index (#eq? @index \"0\")))") + lib.QueryNode(cd.MainError.Nearest, query, func(ctx lib.QueryNodeCtx) bool { + match := ctx.Cursor.FilterPredicates(ctx.Match, []byte(cd.MainError.Nearest.Doc.Contents)) + for _, c := range match.Captures { + node := lib.WrapNode(cd.MainError.Nearest.Doc, c.Node) + err.Nearest = node + return false + } + return true + }) + }, OnGenExplainFn: func(cd *lib.ContextData, gen *lib.ExplainGenerator) { - // TODO: - gen.Add("You are calling an index notation on a variable with type %s", cd.Variables["foundType"]) + parent := cd.MainError.Nearest.Parent() + varNode := parent.ChildByFieldName("array") + indexNode := cd.MainError.Nearest + + gen.Add( + "This error occurs because the variable `%s` is declared as an `%s` rather than an array. You're attempting to access an index (`%s`) on a variable that's not an array.", + varNode.Text(), + cd.Variables["foundType"], + indexNode.Text(), + ) }, OnGenBugFixFn: func(cd *lib.ContextData, gen *lib.BugFixGenerator) { - // TODO: + parent := cd.MainError.Nearest.Parent() + varNode := parent.ChildByFieldName("array") + // indexNode := cd.MainError.Nearest + tree := cd.InitOrGetSymbolTree(cd.MainDocumentPath()) + + gen.Add("Change variable type to an array", func(s *lib.BugFixSuggestion) { + fmt.Printf("%v\n", tree.GetNearestScopedTree(varNode.StartPosition().Index).Symbols["number"]) + declSym := tree.GetSymbolByNode(getIdentifierNode(varNode)) + declNode := lib.WrapNode( + cd.MainError.Document, + cd.MainError.Document.Tree.RootNode().NamedDescendantForPointRange( + declSym.Location().Point(), + declSym.Location().Point(), + )).Parent() + + valueNode := declNode.ChildByFieldName("value") + declNode = declNode.Parent() + + s.AddStep("Declare the variable `%s` as an array of `%s`.", varNode.Text(), cd.Variables["foundType"]). + AddFix(lib.SuggestedFix{ + NewText: fmt.Sprintf("%s[] %s = {%s}", cd.Variables["foundType"], varNode.Text(), valueNode.Text()), + StartPosition: declNode.StartPosition(), + EndPosition: declNode.EndPosition(), + Replace: true, + }) + }) + + gen.Add("Initialize an array and access its index", func(s *lib.BugFixSuggestion) { + s.AddStep(""). + AddFix(lib.SuggestedFix{ + NewText: "number[0] = 5a", + StartPosition: cd.MainError.Nearest.StartPosition(), + EndPosition: cd.MainError.Nearest.EndPosition(), + Description: "These changes will rectify the error by ensuring the variable is treated as an array when accessing elements by index.", + }) + }) }, } diff --git a/error_templates/java/java.go b/error_templates/java/java.go index 823ea04..deb1536 100644 --- a/error_templates/java/java.go +++ b/error_templates/java/java.go @@ -44,3 +44,12 @@ func comptimeErrorPattern(pattern string, endPattern_ ...string) string { } return fmt.Sprintf(`$stacktrace: error: %s%s`, pattern, endPattern) } + +// TODO: +func getIdentifierNode(node lib.SyntaxNode) lib.SyntaxNode { + currentNode := node + for currentNode.Type() != "identifier" { + return currentNode + } + return currentNode +} diff --git a/error_templates/java/test_files/array_required_type_error/test.txt b/error_templates/java/test_files/array_required_type_error/test.txt index df7f41e..d08a242 100644 --- a/error_templates/java/test_files/array_required_type_error/test.txt +++ b/error_templates/java/test_files/array_required_type_error/test.txt @@ -8,31 +8,33 @@ NotArray.java:4: error: array required, but int found template: "Java.ArrayRequiredTypeError" --- # ArrayRequiredTypeError -This error occurs because you're trying to access an index of an integer variable `number` as if it were an array, but `number` is just an integer, not an array. - +This error occurs because the variable `number` is declared as an `int` rather than an array. You're attempting to access an index (`[0]`) on a variable that's not an array. +``` + int number = 5; + int value = number[0]; + ^ + } +} +``` ## Steps to fix -1. **Understand the issue:** In Java, you can only use square brackets to access elements in an array, not on an individual integer variable. - +### 1. Change variable type to an array ```diff public class NotArray { public static void main(String[] args) { -- int number = 5; -+ int[] number = {5}; // Define 'number' as an array with a single element. -- int value = number[0]; // Access the first (and only) element of the 'number' array. -+ int value = number[0]; +- int number = 5; ++ int[] number = {5}; + int value = number[0]; } } ``` - -2. **Fix the code:** Change the `number` variable to an array by using square brackets and assign the value you wish to access in the array. Then, you can access the first element using square brackets as intended for arrays. This allows you to access the first element of the array correctly. - +### 2. Initialize an array and access its index ```diff public class NotArray { public static void main(String[] args) { -- int number = 5; -+ int[] number = {5}; // Define 'number' as an array with a single element. -- int value = number[0]; // Access the first (and only) element of the 'number' array. -+ int value = number[0]; + int[] number = {5}; ++ number[0] = 5; + int value = number[0]; } } ``` +These changes will rectify the error by ensuring the variable is treated as an array when accessing elements by index. \ No newline at end of file diff --git a/error_templates/java/test_files/unknown_variable_error/test.txt b/error_templates/java/test_files/unknown_variable_error/test.txt index c8a3372..b27ff1e 100644 --- a/error_templates/java/test_files/unknown_variable_error/test.txt +++ b/error_templates/java/test_files/unknown_variable_error/test.txt @@ -17,7 +17,15 @@ The program cannot find variable "a" ^ } } - ``` ## Steps to fix -Nothing to fix +### Create a variable. +Create a variable named "a". For example: +```diff +public class Program { + public static void main(String[] args) { +- System.out.println(a); ++ String a = ""; + System.out.println(a); + } +``` diff --git a/error_templates/java/unknown_variable_error.go b/error_templates/java/unknown_variable_error.go index 4f0dd1d..c808bc9 100644 --- a/error_templates/java/unknown_variable_error.go +++ b/error_templates/java/unknown_variable_error.go @@ -39,7 +39,7 @@ var UnknownVariableError = lib.ErrorTemplate{ variable := cd.Variables["variable"] gen.Add("Create a variable.", func(s *lib.BugFixSuggestion) { - s.AddStep("(%s) Create a variable named \"%s\". For example: ", ctx.parentNode.Type(), variable). + s.AddStep("Create a variable named \"%s\". For example:", variable). // TODO: use variable type from the inferred parameter AddFix(lib.SuggestedFix{ NewText: fmt.Sprintf("String %s = \"\";", variable), diff --git a/output_gen.go b/output_gen.go index 44c68d3..615b211 100644 --- a/output_gen.go +++ b/output_gen.go @@ -77,7 +77,7 @@ func (gen *OutputGenerator) Generate(cd *ContextData, explain *ExplainGenerator, } gen.generateFromExp(1, explain) - doc := cd.MainError.Document + doc := cd.MainError.Document.CopyContentsOnly() if gen.IsTesting { startRow := cd.MainError.Nearest.StartPoint().Row diff --git a/source.go b/source.go index d4bea3e..eb16faa 100644 --- a/source.go +++ b/source.go @@ -15,6 +15,12 @@ type Position struct { Index int } +func (a Position) Eq(b Position) bool { + return a.Column == b.Column && + a.Line == b.Line && + a.Index == b.Index +} + func (pos Position) String() string { return fmt.Sprintf("[%d,%d | %d]", pos.Line, pos.Column, pos.Index) } @@ -46,6 +52,19 @@ func (loc Location) Range() sitter.Range { } } +type Changeset struct { + NewText string + StartPos Position + EndPos Position + IsReplace bool +} + +type TempDocument struct { + *Document + lines []string + changesets []Changeset +} + type Document struct { Path string Contents string @@ -54,6 +73,40 @@ type Document struct { Tree *sitter.Tree } +func (doc *TempDocument) ApplyEdit(newText string, startPos Position, endPos Position) { + isReplace := !startPos.Eq(endPos) + doc.changesets = append(doc.changesets, Changeset{ + NewText: newText, + StartPos: startPos, + EndPos: endPos, + IsReplace: isReplace, + }) + + if isReplace { + if startPos.Column == 0 && endPos.Column == 0 { + doc.cachedLines[startPos.Line] = newText + } else { + line := startPos.Line + left := doc.cachedLines[line][:startPos.Column] + right := doc.cachedLines[line][endPos.Column:] + doc.cachedLines[line] = left + newText + right + } + } else { + doc.cachedLines = append(doc.cachedLines[:startPos.Line+1], doc.cachedLines[endPos.Line:]...) + doc.cachedLines[startPos.Line] = newText + } +} + +func (doc *Document) CreateTempDoc() TempDocument { + lines := make([]string, len(doc.Lines())) + copy(lines, doc.Lines()) + + return TempDocument{ + Document: doc, + lines: lines, + } +} + func (doc *Document) LineAt(idx int) string { if doc.cachedLines == nil { doc.cachedLines = strings.Split(doc.Contents, "\n")