Example #1
0
// growSpan expands the span for the object to contain the instance represented
// by the identifier.
func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) {
	if *strictShadowing {
		return // No need
	}
	pos := ident.Pos()
	end := ident.End()
	span, ok := pkg.spans[obj]
	if ok {
		if span.min > pos {
			span.min = pos
		}
		if span.max < end {
			span.max = end
		}
	} else {
		span = Span{pos, end}
	}
	pkg.spans[obj] = span
}
Example #2
0
func completeCalltip(src []byte, fn string, offset int) []gocode.GoSublimeGocodeCandidate {
	fset := token.NewFileSet()
	af, _ := parser.ParseFile(fset, fn, src, 0)

	if af != nil {
		vis := &calltipVisitor{
			offset: offset,
			fset:   fset,
		}
		ast.Walk(vis, af)

		if vis.x != nil {
			var id *ast.Ident

			switch v := vis.x.Fun.(type) {
			case *ast.Ident:
				id = v
			case *ast.SelectorExpr:
				id = v.Sel
			}

			if id != nil && id.End().IsValid() {
				line := offsetLine(fset, af, offset)
				cp := fset.Position(id.End())
				cr := cp.Offset
				cl := gocode.GoSublimeGocodeComplete(src, fn, cr)

				if (cp.Line == line || line == 0) && len(cl) > 0 {
					for i, c := range cl {
						if strings.EqualFold(id.Name, c.Name) {
							return cl[i : i+1]
						}
					}
				}
			}
		}
	}

	return []gocode.GoSublimeGocodeCandidate{}
}
Example #3
0
// Returns true if unused
func checkObj(expr *ast.Ident, object types.Object, prog *loader.Program, ssaprog *ssa.Program, fset *token.FileSet) (unused bool) {
	if _, ok := object.(*types.Var); !ok {
		if debug {
			fmt.Println("Skipping object", object)
		}
		return false
	}
	pkg, node, _ := prog.PathEnclosingInterval(expr.Pos(), expr.End())
	spkg := ssaprog.Package(pkg.Pkg)
	f := ssa.EnclosingFunction(spkg, node)
	if f == nil {
		if debug {
			fmt.Printf("Unknown function %v %v %v %v\n", fset.Position(expr.Pos()), object, pkg, prog)
		}
		return false
	}
	value, _ := f.ValueForExpr(expr)
	// Unwrap unops and grab the value inside
	if v, ok := value.(*ssa.UnOp); ok {
		if debug {
			fmt.Println("Unwrapping unop")
		}
		value = v.X
	}
	if debug {
		fmt.Printf("%v %v: %v      %#v\n", fset.Position(expr.Pos()), expr, object, value)
	}
	if _, ok := value.(*ssa.Global); ok {
		if debug {
			fmt.Printf("     is global\n")
		}
		return false
	}
	if value == nil {
		if debug {
			fmt.Println("Value is nil", object)
		}
		return false
	}
	refs := value.Referrers()
	if refs == nil {
		if debug {
			fmt.Println("Referrers is nil", object)
		}
		return false
	}
	if debug {
		fmt.Printf("   (refs) %v\n", refs)
	}
	hasRef := false
	for _, r := range *refs {
		_, ok := r.(*ssa.DebugRef)
		hasRef = hasRef || !ok
		if debug && !ok {
			fmt.Printf("%v %v: %v      %v\n", fset.Position(expr.Pos()), expr, object, r)
		}
	}
	if !hasRef {
		unused = true
	}
	return unused
}
Example #4
0
// NewDef creates a new Def.
func (g *Grapher) NewDef(obj types.Object, declIdent *ast.Ident) (*Def, error) {
	// Find the AST node that declares this def.
	var declNode ast.Node
	_, astPath, _ := g.program.PathEnclosingInterval(declIdent.Pos(), declIdent.End())
	for _, node := range astPath {
		switch node.(type) {
		case *ast.FuncDecl, *ast.GenDecl, *ast.ValueSpec, *ast.TypeSpec, *ast.Field, *ast.DeclStmt, *ast.AssignStmt:
			declNode = node
			goto found
		}
	}
found:
	if declNode == nil {
		return nil, fmt.Errorf("On ident %s at %s: no DeclNode found (using PathEnclosingInterval)", declIdent.Name, g.program.Fset.Position(declIdent.Pos()))
	}

	key, info, err := g.defInfo(obj)
	if err != nil {
		return nil, err
	}

	si := definfo.DefInfo{
		Exported: info.exported,
		PkgScope: info.pkgscope,
		PkgName:  obj.Pkg().Name(),
		Kind:     defKind(obj),
	}

	if typ := obj.Type(); typ != nil {
		si.TypeString = typ.String()
		if utyp := typ.Underlying(); utyp != nil {
			si.UnderlyingTypeString = utyp.String()
		}
	}

	switch obj := obj.(type) {
	case *types.Var:
		if obj.IsField() {
			if fieldStruct, ok := g.structFields[obj]; ok {
				if struct_, ok := fieldStruct.parent.(*types.Named); ok {
					si.FieldOfStruct = struct_.Obj().Name()
				}
			}
		}
	case *types.Func:
		sig := obj.Type().(*types.Signature)
		if recv := sig.Recv(); recv != nil && recv.Type() != nil {
			// omit package path; just get receiver type name
			si.Receiver = strings.Replace(recv.Type().String(), obj.Pkg().Path()+".", "", 1)
		}
	}

	return &Def{
		Name: obj.Name(),

		DefKey: key,

		File:      g.program.Fset.Position(declIdent.Pos()).Filename,
		IdentSpan: makeSpan(g.program.Fset, declIdent),
		DeclSpan:  makeSpan(g.program.Fset, declNode),

		DefInfo: si,
	}, nil
}