Skip to content

Commit e968368

Browse files
authored
Block renaming a symbol to an existing symbol name (#4229)
1 parent 1cae155 commit e968368

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

private/buf/buflsp/symbol.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,12 +312,18 @@ func (s *symbol) Rename(newName string) (*protocol.WorkspaceEdit, error) {
312312
var edits protocol.WorkspaceEdit
313313
switch s.kind.(type) {
314314
case *referenceable:
315+
if err := checkRenameConflicts(s, newName); err != nil {
316+
return nil, err
317+
}
315318
changes, err := renameChangesForReferenceableSymbol(s, newName)
316319
if err != nil {
317320
return nil, err
318321
}
319322
edits.Changes = changes
320323
case *static:
324+
if err := checkRenameConflicts(s, newName); err != nil {
325+
return nil, err
326+
}
321327
edits.Changes = map[protocol.DocumentURI][]protocol.TextEdit{
322328
s.file.uri: {{
323329
Range: reportSpanToProtocolRange(s.span),
@@ -328,6 +334,9 @@ func (s *symbol) Rename(newName string) (*protocol.WorkspaceEdit, error) {
328334
// For references, we attempt to rename the definition symbol, if resolved. This would
329335
// include this reference symbol.
330336
if s.def != nil {
337+
if err := checkRenameConflicts(s.def, newName); err != nil {
338+
return nil, err
339+
}
331340
changes, err := renameChangesForReferenceableSymbol(s.def, newName)
332341
if err != nil {
333342
return nil, err
@@ -362,6 +371,46 @@ func renameChangesForReferenceableSymbol(s *symbol, newName string) (map[protoco
362371
return changes, nil
363372
}
364373

374+
// checkRenameConflicts takes the symbol and desired new name and checks if this conflicts
375+
// with an existing symbol in the same scope and returns an error if a conflict is found.
376+
func checkRenameConflicts(target *symbol, newName string) error {
377+
parent := target.ir.FullName().Parent()
378+
if parent != "" {
379+
var existing source.Span
380+
newFullName := parent.Append(newName)
381+
containsFunc := func(s *symbol) bool {
382+
existing = s.span
383+
return s.ir.FullName() == newFullName
384+
}
385+
// We check all files in the workspace for a conflict, since a package can span an arbitrary
386+
// number of files.
387+
// We first check the current symbol's file.
388+
if slices.ContainsFunc(target.file.symbols, containsFunc) {
389+
return fmt.Errorf(
390+
"Renaming %q to %q would conflict with existing symbol at %s:%d:%d",
391+
target.ir.FullName().Name(),
392+
newName,
393+
target.file.ir.Path(),
394+
existing.StartLoc().Line,
395+
existing.StartLoc().Column,
396+
)
397+
}
398+
for _, file := range target.file.workspace.PathToFile() {
399+
if slices.ContainsFunc(file.symbols, containsFunc) {
400+
return fmt.Errorf(
401+
"Renaming %q to %q would conflict with existing symbol at %s:%d:%d",
402+
target.ir.FullName().Name(),
403+
newName,
404+
file.ir.Path(),
405+
existing.StartLoc().Line,
406+
existing.StartLoc().Column,
407+
)
408+
}
409+
}
410+
}
411+
return nil
412+
}
413+
365414
func protowireTypeForPredeclared(name predeclared.Name) protowire.Type {
366415
switch name {
367416
case predeclared.Bool, predeclared.Int32, predeclared.Int64, predeclared.UInt32,

0 commit comments

Comments
 (0)