Esempio n. 1
0
// valPos tries to find a position for the given value
// even if the value doesn't have one.
func valPos(val ssa.Value) token.Pos {
	if pos := val.Pos(); pos.IsValid() {
		return pos
	}
	instr, ok := val.(ssa.Instruction)
	if !ok {
		return token.NoPos
	}
	for _, op := range instr.Operands(nil) {
		if pos := (*op).Pos(); pos.IsValid() {
			return pos
		}
	}
	return token.NoPos
}
Esempio n. 2
0
func (ctxt *context) getErrorInfo(v ssa.Value, member int, enclosingPos token.Pos, seen map[ssa.Value]bool) (result *errorInfo) {
	if !enclosingPos.IsValid() {
		panicf("getErrorInfo with invalid pos; %T %s", v, v)
	}
	//	log.Printf("getErrorInfo[%d] %T %v {", member, v, v)
	//	defer func() {
	//		log.Printf("} -> %+v", result)
	//	}()

	if seen[v] {
		return &errorInfo{}
	}
	seen[v] = true
	defer delete(seen, v)
	if pos := v.Pos(); pos.IsValid() {
		enclosingPos = pos
	}
	terminate := func() []errorTermination {
		return []errorTermination{{
			val: v,
			pos: enclosingPos,
		}}
	}
	switch v := v.(type) {
	case *ssa.Call:
		if member > 0 && member != v.Type().(*types.Tuple).Len()-1 {
			log.Printf("error from non-final member of function")
			return &errorInfo{unknown: terminate()}
		}
		return &errorInfo{nested: []*ssa.Call{v}}
	case *ssa.ChangeInterface:
		return ctxt.getErrorInfo(v.X, 0, enclosingPos, seen)
	case *ssa.Extract:
		return ctxt.getErrorInfo(v.Tuple, v.Index, enclosingPos, seen)
	case *ssa.Field:
		return &errorInfo{unknown: terminate()}
	case *ssa.Index:
		return &errorInfo{unknown: terminate()}
	case *ssa.Lookup:
		return &errorInfo{unknown: terminate()}
	case *ssa.Const:
		if v.Value != nil {
			panicf("non-nil constant cannot make error, surely?")
		}
		return &errorInfo{}
	case *ssa.MakeInterface:
		// TODO look into components of v.X
		return &errorInfo{nonNil: terminate()}
	case *ssa.Next:
		return &errorInfo{unknown: terminate()}
	case *ssa.Parameter:
		return &errorInfo{unknown: terminate()}
	case *ssa.Phi:
		var info errorInfo
		for _, edge := range v.Edges {
			info.add(ctxt.getErrorInfo(edge, member, enclosingPos, seen))
		}
		return &info
	case *ssa.Select:
		return &errorInfo{unknown: terminate()}
	case *ssa.TypeAssert:
		if v.CommaOk {
			return &errorInfo{unknown: terminate()}
		}
		return ctxt.getErrorInfo(v.X, 0, enclosingPos, seen)
	case *ssa.UnOp:
		switch v.Op {
		case token.ARROW:
			return &errorInfo{unknown: terminate()}
		case token.MUL:
			if _, isGlobal := v.X.(*ssa.Global); isGlobal {
				// Assume that if we're returning a global variable, it's a
				// global non-nil error, such as os.ErrInvalid.
				return &errorInfo{nonNil: terminate()}
			}
			return &errorInfo{unknown: terminate()}
		default:
			panicf("unexpected unary operator %s at %s", v, ctxt.lprog.Fset.Position(enclosingPos))
		}
	}
	panicf("unexpected value found for error: %T; %v", v, v)
	panic("not reached")
}