-
Notifications
You must be signed in to change notification settings - Fork 18
fix: resolve conflicting edits for type assertion and error comparison (fixes #100) #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
fixes polyfloyd#100) - Implement conflict resolution when both type assertion and error comparison linting rules apply to the same line - Add support for else-if statement transformations using errors.As and errors.Is - Generate combined diagnostics with unified suggested fixes Signed-off-by: Kemal Akkoyun <[email protected]>
Testing this PR on the same code as in the error description, the comment lines were dropped. - } else if e, ok := err.(*os.PathError); ok && e.Err == syscall.ESRCH {
- // If the process exits while reading its /proc/$PID/maps, the kernel will
- // return ESRCH. Handle it as if the process did not exist.
- pm.mappingStats.errProcESRCH.Add(1)
+ } else {
+ e := &os.PathError{}
+ if errors.As(err, &e) && errors.Is(e.Err, syscall.ESRCH) {
+ pm.mappingStats.errProcESRCH.Add(1)
+ }
} Also (maybe a different issue), with the following change, the - if n == 0 || (err != nil && err != io.EOF) {
+ if n == 0 || (err != nil && !errors.Is(err, io.EOF)) { Let me know if this is unrelated and I'll open another issue. |
if strings.HasPrefix(targetTypeStr, "*") { | ||
baseType, _ := strings.CutPrefix(targetTypeStr, "*") | ||
return fmt.Sprintf("%s := &%s{}", assertion.varName, baseType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this?
if strings.HasPrefix(targetTypeStr, "*") { | |
baseType, _ := strings.CutPrefix(targetTypeStr, "*") | |
return fmt.Sprintf("%s := &%s{}", assertion.varName, baseType) | |
if baseType, found := strings.CutPrefix(targetTypeStr, "*") ; found { | |
return fmt.Sprintf("%s := &%s{}", assertion.varName, baseType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have remembered this one from your comments from the first PR 🙈 Muscle memory!
// nodeContainsPos checks if a node contains the given position | ||
func nodeContainsPos(node ast.Node, pos token.Pos) bool { | ||
return node.Pos() <= pos && pos < node.End() | ||
} | ||
|
||
// containingIf finds the if statement that contains the given node | ||
// by walking up the AST parent chain. | ||
func containingIf(extInfo *TypesInfoExt, node ast.Node) *ast.IfStmt { | ||
current := node | ||
for current != nil { | ||
if ifStmt, ok := current.(*ast.IfStmt); ok { | ||
return ifStmt | ||
} | ||
parent := extInfo.NodeParent[current] | ||
if parent == nil { | ||
break | ||
} | ||
current = parent | ||
} | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this to be consistent
// nodeContainsPos checks if a node contains the given position | |
func nodeContainsPos(node ast.Node, pos token.Pos) bool { | |
return node.Pos() <= pos && pos < node.End() | |
} | |
// containingIf finds the if statement that contains the given node | |
// by walking up the AST parent chain. | |
func containingIf(extInfo *TypesInfoExt, node ast.Node) *ast.IfStmt { | |
current := node | |
for current != nil { | |
if ifStmt, ok := current.(*ast.IfStmt); ok { | |
return ifStmt | |
} | |
parent := extInfo.NodeParent[current] | |
if parent == nil { | |
break | |
} | |
current = parent | |
} | |
return nil | |
} | |
// nodeContainsPos checks if a node contains the given position | |
func nodeContainsPos(node ast.Node, pos token.Pos) bool { | |
return node.Pos() <= pos && pos < node.End() | |
} | |
// statementContainsIf finds the if statement that contains the given node | |
// by walking up the AST parent chain. | |
func statementContainsIf(extInfo *TypesInfoExt, node ast.Node) *ast.IfStmt { | |
current := node | |
for current != nil { | |
if ifStmt, ok := current.(*ast.IfStmt); ok { | |
return ifStmt | |
} | |
parent := extInfo.NodeParent[current] | |
if parent == nil { | |
break | |
} | |
current = parent | |
} | |
return nil | |
} |
// context holds if statement context information | ||
type context struct { | ||
isElseIf bool | ||
bodyStmts []ast.Stmt | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's strange to call it context, especially because it shadows context package
ifInfo maybe?
const ( | ||
typeAssertionPattern = "type assertion on error" | ||
errorComparisonPattern = "comparing with" | ||
) | ||
|
||
// classifyDiagnostic determines the type of diagnostic based on its message | ||
func classifyDiagnostic(diagnostic analysis.Diagnostic) diagnosticType { | ||
msg := diagnostic.Message | ||
if strings.Contains(msg, typeAssertionPattern) { | ||
return typeAssertionDiag | ||
} | ||
if strings.Contains(msg, errorComparisonPattern) { | ||
return errorComparisonDiag | ||
} | ||
return otherDiag | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised the detection is made on the message.
Should we use this constant when raising the diagnostic? Maybe I missed something 🤔
Good catch. I have to make sure we preserve the comments (hard with stdlib). I will think ways to simplify the implementation. It is hard to rewrite control flow statements. |
Signed-off-by: Kemal Akkoyun [email protected]