From d519b0dee89c9525432ebc97eedec02f0abb8142 Mon Sep 17 00:00:00 2001 From: Ned Palacios Date: Tue, 12 Dec 2023 20:51:41 +0800 Subject: [PATCH] feat: implement Java.OperatorCannotBeAppliedError template --- error_templates/java/java.go | 1 + .../java/operator_cannot_be_applied_error.go | 75 +++++++++++++++++++ .../OperatorCannotBeApplied.java | 9 +++ .../operator_cannot_be_applied_error/test.txt | 44 +++++++++++ 4 files changed, 129 insertions(+) create mode 100644 error_templates/java/operator_cannot_be_applied_error.go create mode 100644 error_templates/java/test_files/operator_cannot_be_applied_error/OperatorCannotBeApplied.java create mode 100644 error_templates/java/test_files/operator_cannot_be_applied_error/test.txt diff --git a/error_templates/java/java.go b/error_templates/java/java.go index 4fffc36..6832351 100644 --- a/error_templates/java/java.go +++ b/error_templates/java/java.go @@ -22,6 +22,7 @@ func LoadErrorTemplates(errorTemplates *lib.ErrorTemplates) { errorTemplates.MustAdd(java.Language, SymbolNotFoundError) errorTemplates.MustAdd(java.Language, NonStaticMethodAccessError) errorTemplates.MustAdd(java.Language, UnclosedCharacterLiteralError) + errorTemplates.MustAdd(java.Language, OperatorCannotBeAppliedError) } func runtimeErrorPattern(errorName string, pattern string) string { diff --git a/error_templates/java/operator_cannot_be_applied_error.go b/error_templates/java/operator_cannot_be_applied_error.go new file mode 100644 index 0000000..25d0abe --- /dev/null +++ b/error_templates/java/operator_cannot_be_applied_error.go @@ -0,0 +1,75 @@ +package java + +import ( + "fmt" + "strings" + + lib "github.com/nedpals/errgoengine" +) + +type opCannotBeAppliedCtx struct { + Parent lib.SyntaxNode +} + +var OperatorCannotBeAppliedError = lib.ErrorTemplate{ + Name: "OperatorCannotBeAppliedError", + Pattern: comptimeErrorPattern("bad operand types for binary operator '(?P.)'", `first type\:\s+(?P\S+)\s+second type\:\s+(?P\S+)`), + StackTracePattern: comptimeStackTracePattern, + OnAnalyzeErrorFn: func(cd *lib.ContextData, m *lib.MainError) { + oCtx := opCannotBeAppliedCtx{} + operator := cd.Variables["operator"] + query := fmt.Sprintf(`((binary_expression) @binary_expr (#eq @binary_expr "%s"))`, operator) + lib.QueryNode(m.Nearest, strings.NewReader(query), func(ctx lib.QueryNodeCtx) bool { + match := ctx.Cursor.FilterPredicates(ctx.Match, []byte(m.Nearest.Doc.Contents)) + for _, c := range match.Captures { + node := lib.WrapNode(m.Nearest.Doc, c.Node) + oCtx.Parent = node + m.Nearest = node.Child(1) + return false + } + return true + }) + m.Context = oCtx + }, + OnGenExplainFn: func(cd *lib.ContextData, gen *lib.ExplainGenerator) { + gen.Add( + "This error occurs when you try to apply a binary operator to incompatible operand types, such as trying to use the '%s' operator between a %s and an %s.", + cd.Variables["operator"], + cd.Variables["firstType"], + cd.Variables["secondType"], + ) + }, + OnGenBugFixFn: func(cd *lib.ContextData, gen *lib.BugFixGenerator) { + ctx := cd.MainError.Context.(opCannotBeAppliedCtx) + left := ctx.Parent.ChildByFieldName("left") + right := ctx.Parent.ChildByFieldName("right") + + gen.Add(fmt.Sprintf("Use %s's compareTo method", cd.Variables["firstType"]), func(s *lib.BugFixSuggestion) { + + s.AddStep( + "Since you are comparing a %s and an %s, you need to use the `compareTo` method to compare their values.", + cd.Variables["firstType"], + cd.Variables["secondType"], + ).AddFix(lib.FixSuggestion{ + NewText: ".compareTo(String.valueOf(" + right.Text() + "))", + StartPosition: left.EndPosition(), + EndPosition: left.EndPosition(), + Description: "The `compareTo` method returns a negative integer if the calling string is lexicographically less than the argument string.", + }) + }) + + gen.Add(fmt.Sprintf("Convert %s to %s for direct comparison", cd.Variables["secondType"], cd.Variables["firstType"]), func(s *lib.BugFixSuggestion) { + s.AddStep( + "If you want to compare them directly, convert the %s to %s using `%s.valueOf()`.", + cd.Variables["secondType"], + cd.Variables["firstType"], + cd.Variables["firstType"], + ).AddFix(lib.FixSuggestion{ + Description: "This ensures both operands are of the same type for comparison.", + NewText: ".equals(" + cd.Variables["firstType"] + ".valueOf(" + right.Text() + "))", + StartPosition: left.EndPosition(), + EndPosition: ctx.Parent.EndPosition(), + }) + }) + }, +} diff --git a/error_templates/java/test_files/operator_cannot_be_applied_error/OperatorCannotBeApplied.java b/error_templates/java/test_files/operator_cannot_be_applied_error/OperatorCannotBeApplied.java new file mode 100644 index 0000000..baf95c1 --- /dev/null +++ b/error_templates/java/test_files/operator_cannot_be_applied_error/OperatorCannotBeApplied.java @@ -0,0 +1,9 @@ +public class OperatorCannotBeApplied { + public static void main(String[] args) { + String text = "Hello"; + int number = 5; + + // Operator '<' cannot be applied to String and int + if (text < number) {} + } +} diff --git a/error_templates/java/test_files/operator_cannot_be_applied_error/test.txt b/error_templates/java/test_files/operator_cannot_be_applied_error/test.txt new file mode 100644 index 0000000..9daf707 --- /dev/null +++ b/error_templates/java/test_files/operator_cannot_be_applied_error/test.txt @@ -0,0 +1,44 @@ +template: "Java.OperatorCannotBeAppliedError" +--- +OperatorCannotBeApplied.java:7: error: bad operand types for binary operator '<' + if (text < number) {} + ^ + first type: String + second type: int +1 error +=== +template: "Java.OperatorCannotBeAppliedError" +--- +# OperatorCannotBeAppliedError +This error occurs when you try to apply a binary operator to incompatible operand types, such as trying to use the '<' operator between a String and an int. +``` + // Operator '<' cannot be applied to String and int + if (text < number) {} + ^ + } +} +``` +## Steps to fix +### 1. Use String's compareTo method +Since you are comparing a String and an int, you need to use the `compareTo` method to compare their values. +```diff + + // Operator '<' cannot be applied to String and int +- if (text < number) {} ++ if (text.compareTo(String.valueOf(number)) < number) {} + } +} +``` +The `compareTo` method returns a negative integer if the calling string is lexicographically less than the argument string. + +### 2. Convert int to String for direct comparison +If you want to compare them directly, convert the int to String using `String.valueOf()`. +```diff + + // Operator '<' cannot be applied to String and int +- if (text < number) {} ++ if (text.equals(String.valueOf(number))) {} + } +} +``` +This ensures both operands are of the same type for comparison.