Skip to content

Commit

Permalink
Merge pull request #2625 from onflow/bastian/suggest-optional-chaining
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Jul 13, 2023
2 parents 1869acb + 5a8f426 commit 316e8a9
Showing 1 changed file with 43 additions and 6 deletions.
49 changes: 43 additions & 6 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,7 @@ type NotDeclaredMemberError struct {
var _ SemanticError = &NotDeclaredMemberError{}
var _ errors.UserError = &NotDeclaredMemberError{}
var _ errors.SecondaryError = &NotDeclaredMemberError{}
var _ HasSuggestedFixes = &NotDeclaredMemberError{}

func (*NotDeclaredMemberError) isSemanticError() {}

Expand All @@ -1036,20 +1037,56 @@ func (e *NotDeclaredMemberError) Error() string {
)
}

func (e *NotDeclaredMemberError) findOptionalMember() string {
optionalType, ok := e.Type.(*OptionalType)
if !ok {
return ""
}

members := optionalType.Type.GetMembers()
name := e.Name
_, ok = members[name]
if !ok {
return ""
}

return name
}

func (e *NotDeclaredMemberError) SecondaryError() string {
if optionalType, ok := e.Type.(*OptionalType); ok {
members := optionalType.Type.GetMembers()
name := e.Name
if _, ok := members[name]; ok {
return fmt.Sprintf("type is optional, consider optional-chaining: ?.%s", name)
}
if optionalMember := e.findOptionalMember(); optionalMember != "" {
return fmt.Sprintf("type is optional, consider optional-chaining: ?.%s", optionalMember)
}
if closestMember := e.findClosestMember(); closestMember != "" {
return fmt.Sprintf("did you mean `%s`?", closestMember)
}
return "unknown member"
}

func (e *NotDeclaredMemberError) SuggestFixes(_ string) []SuggestedFix {
optionalMember := e.findOptionalMember()
if optionalMember == "" {
return nil
}

accessPos := e.Expression.AccessPos

return []SuggestedFix{
{
Message: "use optional chaining",
TextEdits: []TextEdit{
{
Insertion: "?",
Range: ast.Range{
StartPos: accessPos,
EndPos: accessPos,
},
},
},
},
}
}

// findClosestMember searches the names of the members on the accessed type,
// and finds the name with the smallest edit distance from the member the user
// tried to access. In cases of typos, this should provide a helpful hint.
Expand Down

0 comments on commit 316e8a9

Please sign in to comment.