Something went wrong. Try again.
A Thrift language server, formatter, and linter.
lsp linter helix vim vscode thrift
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990package analyzers
import ( "context" "fmt" "path" "path/filepath"
"github.com/karitham/thrift-ls/sema" "github.com/karitham/thrift-ls/syntax")
// AddIncludeFixer offers the include that makes an undefined type resolve:// the definition is searched across the workspace, so the fix works// project-wide. It fixes only "undefined-type" diagnostics.type AddIncludeFixer struct{}
func (f AddIncludeFixer) Fix(ctx context.Context, file sema.File, d sema.Diagnostic) []sema.Fix { if d.Code != sema.CodeUndefinedType { return nil }
// A file with parse errors is not safely editable. if len(file.PF.Errors()) > 0 { return nil }
name := undefinedTypeName(file.PF, d.Span) if name == "" { return nil }
def, err := file.Index().FindInWorkspace(ctx, name) if err != nil || def == nil || def.File == file.URI { return nil }
incPath, err := filepath.Rel(path.Dir(file.URI.Path()), def.File.Path()) if err != nil { return nil }
incPath = filepath.ToSlash(incPath)
content, err := file.PF.Content() if err != nil { return nil }
// Insert after the last include statement, or at the top of the file. insert := syntax.Position{Line: 1, Col: 1} if includes := file.PF.AST().Includes(); len(includes) > 0 { last := includes[len(includes)-1] _, end := file.PF.AST().Range(last) insert = sema.LineSpan(content, end).End }
return []sema.Fix{{ Title: fmt.Sprintf("Add include %q", incPath), Edits: []sema.Edit{{ Span: sema.Span{Start: insert, End: insert}, NewText: fmt.Sprintf("include %q\n", incPath), }}, }}}
// undefinedTypeName returns the type name the "undefined-type" diagnostic// at sp points at: the identifier whose reference failed to resolve. The// diagnostic's span covers that identifier exactly.func undefinedTypeName(pf interface { AST() *syntax.Document}, sp sema.Span,) string { path := pf.AST().SearchNodePathByPosition(sp.Start) if len(path) < 2 { return "" }
id, ok := path[len(path)-1].(*syntax.Identifier) if !ok { return "" }
if ft, ok := path[len(path)-2].(*syntax.FieldType); ok && ft.Ident == id { return sema.TypeReferenceName(ft) }
return ""}