// errorf reports an error (e.g. conflict) and prevents file modification. func (r *renamer) errorf(pos token.Pos, format string, args ...interface{ … } // check performs safety checks of the renaming of the 'from' object to r.to. func (r *renamer) check(from types.Object) { … } // checkInFileBlock performs safety checks for renames of objects in the file block, // i.e. imported package names. func (r *renamer) checkInFileBlock(from *types.PkgName) { … } // checkInPackageBlock performs safety checks for renames of // func/var/const/type objects in the package block. func (r *renamer) checkInPackageBlock(from types.Object) { … } // checkInLexicalScope performs safety checks that a renaming does not // change the lexical reference structure of the specified package. // // For objects in lexical scope, there are three kinds of conflicts: // same-, sub-, and super-block conflicts. We will illustrate all three // using this example: // // var x int // var z int // // func f(y int) { // print(x) // print(y) // } // // Renaming x to z encounters a "same-block conflict", because an object // with the new name already exists, defined in the same lexical block // as the old object. // // Renaming x to y encounters a "sub-block conflict", because there exists // a reference to x from within (what would become) a hole in its scope. // The definition of y in an (inner) sub-block would cast a shadow in // the scope of the renamed variable. // // Renaming y to x encounters a "super-block conflict". This is the // converse situation: there is an existing definition of the new name // (x) in an (enclosing) super-block, and the renaming would create a // hole in its scope, within which there exist references to it. The // new name shadows the existing definition of x in the super-block. // // Removing the old name (and all references to it) is always safe, and // requires no checks. func (r *renamer) checkInLexicalScope(from types.Object) { … } // deeper reports whether block x is lexically deeper than y. func deeper(x, y *types.Scope) bool { … } // forEachLexicalRef calls fn(id, block) for each identifier id in package // pkg that is a reference to obj in lexical scope. block is the // lexical block enclosing the reference. If fn returns false the // iteration is terminated and findLexicalRefs returns false. func forEachLexicalRef(pkg *cache.Package, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool { … } // enclosingBlock returns the innermost block logically enclosing the // specified AST node (an ast.Ident), specified in the form of a path // from the root of the file, [file...n]. func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope { … } func (r *renamer) checkLabel(label *types.Label) { … } // checkStructField checks that the field renaming will not cause // conflicts at its declaration, or ambiguity or changes to any selection. func (r *renamer) checkStructField(from *types.Var) { … } // checkSelections checks that all uses and selections that resolve to // the specified object would continue to do so after the renaming. func (r *renamer) checkSelections(from types.Object) { … } func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) { … } // checkMethod performs safety checks for renaming a method. // There are three hazards: // - declaration conflicts // - selection ambiguity/changes // - entailed renamings of assignable concrete/interface types. // // We reject renamings initiated at concrete methods if it would // change the assignability relation. For renamings of abstract // methods, we rename all methods transitively coupled to it via // assignability. func (r *renamer) checkMethod(from *types.Func) { … } func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool { … } // satisfy returns the set of interface satisfaction constraints. func (r *renamer) satisfy() map[satisfy.Constraint]bool { … } // recv returns the method's receiver. func recv(meth *types.Func) *types.Var { … } // someUse returns an arbitrary use of obj within info. func someUse(info *types.Info, obj types.Object) *ast.Ident { … } func objectKind(obj types.Object) string { … } // NB: for renamings, blank is not considered valid. func isValidIdentifier(id string) bool { … } // isLocal reports whether obj is local to some function. // Precondition: not a struct field or interface method. func isLocal(obj types.Object) bool { … } func isPackageLevel(obj types.Object) bool { … } func isLetter(ch rune) bool { … } func isDigit(ch rune) bool { … }