contract

package
v0.0.0-...-5dce4d2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 13, 2019 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package contract defines the extension points for creating new contracts.

Contracts are associated with a specific object by using a magic comment of the form

contract:SomeContractName

It is acceptable for multiple contracts to be applied to the same object.

Additional configuration may be provided to contract instances by writing a json object, which will be unmarshalled into an instance of the contract struct.

contract:ConfigurableContract { "someKey" : "someValue", ... }

The entirety of the json literal must occur within the same comment. A multiline configuration can be specified when using the /* comment syntax:

/*
  contract:ConfigurableContract {
    "someKey" : "someValue"
  }
*/

There is a one-to-one mapping of an instance of a Contract with a contract declaration in the underlying source code. The specific objects returned from Context.Declaration() and Context.Objects() will vary based on where the contract declaration occurs.

In the simplest case, a contract declared directly upon a struct type will have a single *ssa.Type upon which the contract is enforced.

// contract:FooContract
type SomeStruct struct { ... }
context.Declaration() := SomeStruct
context.Objects() := [ SomeStruct ]

Similarly, contract declarations placed upon individual function or method declarations will have a singleton *ssa.Function presented.

// contract:SomeContract
func (r Receiver) MyMethod() { ... }
context.Declaration() := MyMethod
context.Objects() := [ MyMethod ]

In the case of interfaces, all structs that implement the interface and which have a type-asserting assignment will be aggregated. In the following example, the objects presented would be *ssa.Type instances for both Impl1 and Impl2. Note that because there is no explicit type assertion for NotSeen, it will not be part of the collection.

// contract:FooContract
type SomeIntf interface { ... }
var (
  _ SomeIntf = Impl1{}
  _ SomeIntf = Impl2{}
)
type Impl1 struct { ... }
type Impl2 struct { ... }
type NotSeen struct { ... }
context.Declaration() := SomeIntf
context.Objects() := [ Impl1, Impl2 ]

Contract declarations placed upon an interface method declaration will aggregate all implementing methods and present them as a slice of *ssa.Function. As with the interface case above, only (*Impl1).SomeMethod() and (*Impl2).SomeMethod() will be presented, because an explicit type assertion for those structs exist.

type SomeIntf {
  // controct:FooContract
  SomeMethod()
}
var (
  _ SomeIntf = &Impl1{}
  _ SomeIntf = &Impl2{}
)
func (*Impl1) SomeMethod() { ... }
func (*Impl2) SomeMethod() { ... }
func (*NotSeen) SomeMethod() { ... }
context.Declaration() := (SomeIntf).SomeMethod()
context.Objects() := [ (*Impl1).SomeMethod(), (*Impl2).SomeMethod() ]

Reusable contracts may be declared by declaring a type derived from Contract.

//contract:ReturnConcrete { "AllowedTypeNames" : ["github.../mypackage.Error"], "TargetInterface":"error" }
type ReturnMyError Contract

TODO: Contracts may be placed on a package

Lastly, failing to abide by a contract results in BigEddie being unhappy. You wouldn't want BigEddie to be unhappy, would you?

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Assertions

type Assertions map[types.Object][]types.Object

Assertions define type relationships that have been explicitly asserted in source. Generally, these are declarations of the form

var _ A = B{}

type Context

type Context interface {
	context.Context
	// The name of the contract.
	Contract() string
	// Declaration returns the object that the contract declaration is
	// defined on. See additional discussion on the Contract type.
	Declaration() ssa.Member
	// Hints returns a reference to a shared hint store that allows
	// contracts to store and share information.
	Hints() *Hints
	// Kind returns the kind of contract to be enforced.
	Kind() Kind
	// Objects returns a collection of objects that a specific contract
	// declaration maps to. In general, this will contain at least one
	// element, the value returned from Declaration(). See additional
	// discussion on the Kind type.
	Objects() []ssa.Member
	// Oracle returns a reference to a shared TypeOracle for answering
	// questions about the program's typesystem.
	Oracle() *TypeOracle
	// Program returns the SSA Program object which is driving the
	// analysis.
	Program() *ssa.Program
	// By default, the Context will associate any messages with the
	// Declaration's position.
	Reporter() Reporter
}

Context defines the interface between a Contract and the supporting framework.

type Contract

type Contract interface {
	// Enforce will be called on an instance of the Contract automatically
	// by the runtime. Any error returned by this method will be reported
	// against the declaration object.
	Enforce(ctx Context) error
}

A Contract implements some correctness-checking logic.

type Hints

type Hints struct {
	// contains filtered or unexported fields
}

Hints allows contracts to store and to share information about program elements. Every contract instance defined in a program will be available through the hints mechanism, allowing contracts to make assumptions based solely on source-code declaration.

The methods on hints are safe to call from multiple goroutines, however no guarantees are made about the enclosed hint data.

func NewHints

func NewHints() *Hints

NewHints constructs a new Hints helper. Contract implementations should prefer to use the shared instance available from Context.

func (*Hints) Add

func (h *Hints) Add(member Located, hint interface{})

Add associates the hint with the program member.

Add panics if the supplied hint value cannot be dereferenced to a struct type.

func (*Hints) Get

func (h *Hints) Get(member Located, target interface{}) []interface{}

Get will retrieve the hints of the target type associated with a program member.

for _, intf := range hints.Get(member, &SomeHintType{}) {
  hint := intf.(SomeHintType)
}

Get will panic if the target is not an addressable pointer to a struct type.

type ImpliesHints

type ImpliesHints interface {
	ImpliedHints() []interface{}
}

ImpliesHints allows a hint or Contract to add additional hints when it is associated with an object.

type Kind

type Kind int

The Kind of a contract is a representation of how and where the contract binding was declared.

const (
	// A method declaration like:
	//   func (r Receiver) Foo() { ... }
	// presents just the function.
	KindMethod Kind = iota + 1
	// A top-level function declaration:
	//   func Foo () { .... }
	// presents just the function.
	KindFunction
	// An interface declaration:
	//   type I interface { ... }
	// presents the interface and all types which are known to
	// implement it.
	KindInterface
	// A method defined in an interface:
	//   type I interface { Foo() }
	// presents the interface method declaration and all functions which
	// are known to implement it.
	KindInterfaceMethod
	// All types other than interface declarations:
	//   type Foo int
	// presents the type declaration.
	KindType
)

The various kinds will inform the contract implementation as to what values it can expect to receive from the various Context methods.

| Kind             | Context.Declaration()     | Context.Objects()                 |
------------------------------------------------------------------------------------
| Method           | *ssa.Function             | { Declaration() }                 |
| Function         | *ssa.Function             | { Declaration() }                 |
| Interface        | *ssa.Type (the interface) | []*ssa.Type (implementations)     |
| InterfaceMethod  | *ssa.Type (the interface) | []*ssa.Function (implementations) |
| Type             | *ssa.Type                 | { Declaration() }                 |

func (Kind) String

func (i Kind) String() string

type Located

type Located interface{ Pos() token.Pos }

A Located object is associated with an opaque source location. Most types from the ssa package will implement this interface, as do all of the underlying AST objects.

type Provider

type Provider struct {
	Help string
	New  func() Contract
}

A Provider can construct new instances of a Contract.

type Providers

type Providers map[string]*Provider

Providers defines a lookup map of providers.

type Reporter

type Reporter interface {
	io.Writer
	// Detail creates a nested report to associate output with another
	// source location. It is valid to create a tree of reports.
	Detail(l Located) Reporter
	Print(args ...interface{})
	Printf(format string, args ...interface{})
	Println(args ...interface{})
}

A Reporter allows a contract to produce output messages that are associated with one or more source locations.

type TypeOracle

type TypeOracle struct {
	// contains filtered or unexported fields
}

A TypeOracle answers questions about a program's typesystem. All methods are safe to call from multiple goroutines.

func NewOracle

func NewOracle(pgm *ssa.Program, assertions Assertions) *TypeOracle

NewOracle constructs a TypeOracle. In general, contract implementations should prefer the shared instance provided by Context, rather than constructing a new one.

func (*TypeOracle) MethodImplementors

func (o *TypeOracle) MethodImplementors(
	intf *types.Interface, name string, assertedOnly bool,
) []*ssa.Function

MethodImplementors finds the named method on all types which implement the given interface.

func (*TypeOracle) TypeImplementors

func (o *TypeOracle) TypeImplementors(intf *types.Interface, assertedOnly bool) []types.Object

TypeImplementors returns the runtime times which implement the given interface, according to explicit assertions made by the user.

Directories

Path Synopsis
Package retcon defines a contract which requires
Package retcon defines a contract which requires

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL