// ParseQueryPos parses the source query position pos. // If needExact, it must identify a single AST subtree; // this is appropriate for queries that allow fairly arbitrary syntax, // e.g. "describe". // func ParseQueryPos(iprog *loader.Program, posFlag string, needExact bool) (*QueryPos, error) { filename, startOffset, endOffset, err := parsePosFlag(posFlag) if err != nil { return nil, err } start, end, err := findQueryPos(iprog.Fset, filename, startOffset, endOffset) if err != nil { return nil, err } info, path, exact := iprog.PathEnclosingInterval(start, end) if path == nil { return nil, fmt.Errorf("no syntax here") } if needExact && !exact { return nil, fmt.Errorf("ambiguous selection within %s", astutil.NodeDescription(path[0])) } return &QueryPos{iprog.Fset, start, end, path, exact, info}, nil }
func findFromObjectsInFile(iprog *loader.Program, spec *spec) ([]types.Object, error) { var fromObjects []types.Object for _, info := range iprog.AllPackages { // restrict to specified filename // NB: under certain proprietary build systems, a given // filename may appear in multiple packages. for _, f := range info.Files { thisFile := iprog.Fset.File(f.Pos()) if !sameFile(thisFile.Name(), spec.filename) { continue } // This package contains the query file. if spec.offset != 0 { // Search for a specific ident by file/offset. id := identAtOffset(iprog.Fset, f, spec.offset) if id == nil { // can't happen? return nil, fmt.Errorf("identifier not found") } obj := info.Uses[id] if obj == nil { obj = info.Defs[id] if obj == nil { // Ident without Object. // Package clause? pos := thisFile.Pos(spec.offset) _, path, _ := iprog.PathEnclosingInterval(pos, pos) if len(path) == 2 { // [Ident File] // TODO(adonovan): support this case. return nil, fmt.Errorf("cannot rename %q: renaming package clauses is not yet supported", path[1].(*ast.File).Name.Name) } // Implicit y in "switch y := x.(type) {"? if obj := typeSwitchVar(&info.Info, path); obj != nil { return []types.Object{obj}, nil } // Probably a type error. return nil, fmt.Errorf("cannot find object for %q", id.Name) } } if obj.Pkg() == nil { return nil, fmt.Errorf("cannot rename predeclared identifiers (%s)", obj) } fromObjects = append(fromObjects, obj) } else { // do a package-wide query objects, err := findObjects(info, spec) if err != nil { return nil, err } // filter results: only objects defined in thisFile var filtered []types.Object for _, obj := range objects { if iprog.Fset.File(obj.Pos()) == thisFile { filtered = append(filtered, obj) } } if len(filtered) == 0 { return nil, fmt.Errorf("no object %q declared in file %s", spec.fromName, spec.filename) } else if len(filtered) > 1 { return nil, ambiguityError(iprog.Fset, filtered) } fromObjects = append(fromObjects, filtered[0]) } break } } if len(fromObjects) == 0 { // can't happen? return nil, fmt.Errorf("file %s was not part of the loaded program", spec.filename) } return fromObjects, nil }