annogo

package module
v0.0.0-...-5f54df4 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2020 License: Apache-2.0 Imports: 4 Imported by: 0

README

Anno-Go

Build Status Go Report Card GoDoc

Annotations and annotation processing for Go!

NOTE: Still Under Construction!

Annotations

Annotations take the shape of specially-formatted content in Go doc comments. They can appear on types declarations, interface elements (embedded interfaces and methods), struct fields, and other top-level program elements like consts, vars, and funcs (including methods).

Annotation values are strongly-typed and structured using syntax familiar to Go programmers:

Any type that has the @annogo.Annotation "meta-annotation" can be used as an annotation type.

// @annogo.Annotation
type MyNewAnnotation struct {
    Foo int
    Bar []string
}

And it can then be referenced in annotations on other program elements:

// @MyNewAnnotation{Foo: 123, Bar: {"a", "b", "c"}}
var AnnotatedThing = 1

Annotation Processing

This repo includes a program, aptgo, that can be used in a go:generate directive to perform annotation processing.

Its default behavior is to generate *.annos.go source code that contains init functions that register all runtime-visible annotation values. This allows programs to introspect, at runtime, on the annotations present on a program element.

It also allows for invoking other processors that may perform custom logic to validate annotations and/or perform extra code generation based on the annotations.

To that end, this repo includes the processor sub-package, which provides APIs used by annotation processors for querying annotations from source. This is similar to Java's annotation processing functionality, and this also includes an AnnotationMirror type, which allows processors to inspect and interact with annotation values that are defined in source, even for values whose types are not known to the processor.

Documentation

Overview

Package annogo provides runtime support for Go annotations. This package is referenced from code generated by aptgo, for providing runtime access to annotation values that are intended to be runtime-visible.

The various Register* functions should not be called directly, but instead only called from generated code. The other functions can then be used to inspect runtime-visible annotation values (which were registered from said generated code during package initialization).

It also provides the foundational meta-annotations, which Go developers use to define their own annotations.

Annotation Syntax

Annotations on constructs in Go source code take the form of specially-formatted comments. At the end of normal Go doc, add annotations by writing annotation values, starting with an at sign ("@") in front of each annotation type (similar to annotation syntax in Java). Any comment line that starts with such an at sign is assumed by annotation processors to be the first line of annotations, and all comment lines following it are also assumed to be part of the annotations.

So, for packages with annotations (e.g. those on which you might run the aptgo tool or other processing tools), it is important that no Go doc for any element have a line that starts with the at sign ("@") unless that line is the start of the doc'ed element's annotations.

Like a statement in the Go language, an annotation should be all on a single line or break lines after characters that do not break expressions (such as open braces, open parentheses, binary operators, commas, etc).

// An annotation on a single line
// @annogo.Annotation{AllowedElements: Types}

// An annotation that spans multiple lines
// @annogo.Annotation{
//     AllowedElements: Types, // not trailing comma, like in other Go code
// }

Multiple annotations go on multiple lines, though they can all be crammed on a single line if they are separated with semicolons (again, like normal statements in the Go language).

// Multiple annotations on multiple lines
// @annogo.Required
// @annogo.DefaultValue(123)

// Or multiple annotations on a single line
// @annogo.Required; @annogo.DefaultValue(123)

As seen in the examples above, a single annotation starts with the at sign ("@") followed by the name of the annotation type, including a package qualifier.

// @annogo.Annotation

With just the annotation name, the annotation's value is its zero value with one important exception: if the annotation type is a struct and it has any field with a @annogo.DefaultValue annotation, that field will have the specified default value (not the field's zero value).

If the annotation type is a struct and has any fields with a @annogo.Required annotation, values *must* be indicated in the annotation, so this syntax (annotation type without a value) will not be allowed.

Annotations that indicate values can use one of two syntaxes:

  1. If the annotation type is a scalar, the value must be in parenthesis, just like a type conversion expression in normal Go code.

  2. If the annotation type is a composite type (struct, array, slice, or map), the values are in curly braces, just like the syntax for composite literals in normal Go code.

    // Scalar value @pkg.IntegerAnnotation(123) // Composite value @pkg.SliceAnnotation{123, 456, 789}

There are two exceptions to these rules:

  1. If the annotation type is a struct with a single field names "Value" then the value can be written as if it were a scalar, and the scalar value will be promoted to a struct with that its singular field value.
  2. If the annotation type is a slice of scalar values or an array of length one, then the value can be written as if it were a scalar, and it will be promoted to a single-element slice or array.

These promotions are syntactic sugar to make annotation values more concise.

The first case, an annotation type that is a struct with a single field named "Value", is useful when using annotations that only allow annotation fields as the kind of annotated element. If the annotation type were defined as a scalar type, the value of that scalar type could not have this sort of annotation on it (since they would be on a type element, not a field). So you can work around this by instead declaring the annotation as a single-field struct and then apply the annotations to the one field.

// Example annotations
// @annogo.Annotation
type SimpleAnno struct {
    // @annogo.DefaultValue("foobar")
    Value string
}
// @annogo.Annotation
type SliceAnno []string

// Uses of these annotations may use scalar syntax:
// @SimpleAnno("frobnitz")
// @SliceAnno("abc")

// The above annotations are equivalent to these:
// @SimpleAnno{Value: "frobnitz"}
// @SliceAnno{"abc"} // subtle: braces instead of parentheses

Annotation Expressions

The syntax of annotation values is the same as the syntax for constant expressions in normal Go code with a few additions:

  1. Annotation expressions may use composite literals (slices, arrays, maps, and structs).
  2. Annotation expressions may use literal nils. They can be used to express typed nils, too, but not for channel or interface types, only for slice, map, function, and pointer types.
  3. Annotation expressions may refer to top-level functions by name, not just to constants. This includes qualified names of methods of top-level named types and interfaces.
  4. While composite literals can be typed (e.g. include explicit type), the types can be omitted in most cases: type are inferred based on the known structure of the expression's type. For example, with a struct literal, the types of the struct's fields are known, so it is not necessary to state them in the annotation expression.

Channel values cannot be expressed with annotation expressions other than via untyped literal nils.

Expressions in annotation values do not support pointer operations such as pointer-dereference (*) or address-of (&). However, pointer types are allowed and operations, such as address-of, are handled transparently.

// Here's an annotation with a pointer field
// @annogo.Annotation
type MyAnno struct {
    PtrField *int
}

// Here's how we use it:
// @MyAnno{PtrField: 123}
var SomeAnnotatedElement int
// When reified (during processing or at runtime, for runtime-visible
// annotations), the value will be a pointer, and the pointed-to value will
// be 123. As mentioned, the address-of (&) operator has been applied
// transparently.

Like in constant expressions in normal Go code, function calls are disallowed except for a few special builtin functions for manipulating complex values: imag(c), real(c), and complex(fr, fi).

Annotations and Element Types

TODO

Meta-Annotations

This package contains some meta-annotations, including the one that defines all other annotations: @annogo.Annotation. A meta-annotation is an annotation that is used only on other annotations (or their fields). They are used to define characteristics of other annotations.

In addition to to @annogo.Annotation, there are some other meta-annotations in this package worth knowing about:

  • @annogo.Required: This annotation is used on fields of annotation structs and indicates that the annotated field will not use a zero or default value. It is required that uses of the annotation provide a value for the field.
  • @annogo.DefaultValue: This annotation is used on fields of annotation structs and indicates the default value to use for the field when a use of annotation does not provide a value. Typically, default values, just like in normal Go code, will zero values of their respective types. But this annotation provides a way to indicate non-zero values as defaults. It is an error to annotate a field with both the Required and DefaultValue annotations -- if it has an explicit default, it makes no sense to also be required.

Runtime-Visible Annotations

Querying annotation values at runtime (for annotations that are visible at runtime) is done using functions in this package, too. (There are numerous Register* functions, which record the annotation values during package initialization. But these should only be used by the code that is generated by the aptgo tool.)

The other functions take three shapes:

  1. GetAnnotationsFor*: These functions return annotations of a given type for a particular element. There is one function for each kind of annotated element, and each has its own way for calling code to identify the element.
  2. GetAllAnnotationsFor*: These functions are similar to the previous set but do not take an annotation type. Instead, they return all annotations on a given element, for all annotation types.
  3. GetAnnotated*OfType: These functions are for querying vars and consts of a given type that have annotations. This is most useful for types that are effectively enums, as it provides a way to query for all of the consts (presumably the enum values). However, it only returns elements that have annotations.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetAnnotationsForField

func GetAnnotationsForField(t reflect.Type, fieldName string, annoType reflect.Type) []reflect.Value

GetAnnotationsForField returns all recorded annotations of the given type for the given field.

type foo struct {
  // @MyAnnotation{fiz:"buzz"}
  // @SomeAnnotation(42)
  // @SomeOtherAnnotation
  bar string
  baz string
}

// pass field name as string
annos := annogo.GetAnnotationsForField(
    reflect.TypeOf(foo{}), "bar", reflect.TypeOf(MyAnnotation{}))

func GetAnnotationsForFunction

func GetAnnotationsForFunction(function interface{}, annoType reflect.Type) []reflect.Value

GetAnnotationsForFunction returns recorded annotations of the given type for the given function.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
func foo(bar int) bool {
  return bar == 24
}

// pass the function itself
annos := annogo.GetAnnotationsForFunction(foo, reflect.TypeOf(MyAnnotation{}))

func GetAnnotationsForInterfaceEmbed

func GetAnnotationsForInterfaceEmbed(t, embedType, annoType reflect.Type) []reflect.Value

GetAnnotationsForInterfaceEmbed returns all recorded annotations of the given type for the given interface embed.

func GetAnnotationsForInterfaceMethod

func GetAnnotationsForInterfaceMethod(t reflect.Type, methodName string, annoType reflect.Type) []reflect.Value

GetAnnotationsForInterfaceMethod returns all recorded annotations of the given type for the given interface method.

func GetAnnotationsForType

func GetAnnotationsForType(t reflect.Type, annoType reflect.Type) []reflect.Value

GetAnnotationsForType returns all recorded annotations of the given annotation type for the given annotated type.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
type foo struct {
  bar, baz string
}

annos := annogo.GetAnnotationsForType(reflect.TypeOf(foo{}), reflect.TypeOf(MyAnnotation{}))

func GetAnnotationsForValue

func GetAnnotationsForValue(val ValueDesc, annoType reflect.Type) []reflect.Value

GetAnnotationsForValue returns all recorded annotations of the given type for the given value (which describes either a var or a const).

package fff; // import "github.com/foobar/fff"
// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
var foo = bar{a: "b", c: 'd', e: 111}

valDesc := annogo.ValueDesc{
    Type:        reflect.TypeOf(bar{}),
    PackagePath: "github.com/foobar/fff",
    ValueName:   "foo",
}
annos := annogo.GetAnnotationsForValue(valDesc, reflect.TypeOf(MyAnnotation{}))

func GetAnnotationsForVar

func GetAnnotationsForVar(varAddr interface{}, annoType reflect.Type) []reflect.Value

GetAnnotationsForVar returns all recorded annotations of the given type for the given var. This will return no annotations, even if the var is annotated, if the given var has a storage size of zero. For zero-size vars, GetAnnotationsForValue must be used instead.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
var foo = bar{a: "b", c: 'd', e: 111}

// pass the address of the var
annos := annogo.GetAllAnnotationsForVar(&foo, reflect.TypeOf(MyAnnotation{}))

func GetUnderlyingFunction

func GetUnderlyingFunction(fn interface{}) interface{}

GetUnderlyingFunction retrieves the actual underlying function that is wrapped by the given adapter function. If the given function is not known to be an adapter for any function value used in an annotation, it is returned as is (e.g. its underlying function is itself).

Due to signature adaptation, the returned function may have a different signature than the given function: occurrences of annogo.AnyType or annogo.SelfType may be replaced with other types in the returned function's signature.

func IsAnnotationType

func IsAnnotationType(t reflect.Type) bool

IsAnnotationType determines if the given type can be used as an annotation. Annotation types are those that are themselves annotated with annogo.Annotation.

func RegisterAdaptedFunction

func RegisterAdaptedFunction(adapter, underlying interface{})

RegisterAdaptedFunction is used to associated an underlying function with an adapter function. An adapter function is one that may have instances of annogo.AnyType or annogo.SelfType in its signature, whereas the underlying function may have some other type in those same locations. Adapters are created for annotation values that are functions where annogo.AnyType and/or annogo.SelfType is in the annotation signature, but may not be in the underlying function's signature.

func RegisterConstAnnotation

func RegisterConstAnnotation(constType reflect.Type, pkgPath, constName string, annoType reflect.Type, annotation interface{})

RegisterConstAnnotation records the given annotations for the given const. This should only be used by init() functions generated by aptgo.

func RegisterFieldAnnotation

func RegisterFieldAnnotation(t reflect.Type, fieldName string, annoType reflect.Type, annotation interface{})

RegisterFieldAnnotation records the given annotations for the given field. This should only be used by init() functions generated by aptgo.

func RegisterFunctionAnnotation

func RegisterFunctionAnnotation(function interface{}, annoType reflect.Type, annotation interface{})

RegisterFunctionAnnotation records the given annotations for the given function. This should only be used by init() functions generated by aptgo.

func RegisterInterfaceEmbedAnnotation

func RegisterInterfaceEmbedAnnotation(t, embedType, annoType reflect.Type, annotation interface{})

RegisterInterfaceEmbedAnnotation records the given annotations for the given interface embed. This should only be used by init() functions generated by aptgo.

func RegisterInterfaceMethodAnnotation

func RegisterInterfaceMethodAnnotation(t reflect.Type, methodName string, annoType reflect.Type, annotation interface{})

RegisterInterfaceMethodAnnotation records the given annotations for the given interface method. This should only be used by init() functions generated by aptgo.

func RegisterTypeAnnotation

func RegisterTypeAnnotation(t, annoType reflect.Type, annotation interface{})

RegisterTypeAnnotation records the given annotations for the given type. This should only be used by init() functions generated by aptgo.

func RegisterVarAnnotation

func RegisterVarAnnotation(varAddr interface{}, pkgPath, varName string, annoType reflect.Type, annotation interface{})

RegisterVarAnnotation records the given annotations for the given var. This should only be used by init() functions generated by aptgo.

Types

type Annotation

type Annotation struct {
	// RuntimeVisible indicates that the annotation is queryable at runtime
	// using APIs in this package. This field is effectively ignored if
	// AllowedElements disallows all element types.
	//
	//   @DefaultValue(true)
	RuntimeVisible bool

	// AllowedElements indicates the kinds of elements that can be annotated. If
	// it is empty, the annotation can be used on any kind of element.
	AllowedElements []ElementType

	// AllowRepeated indicates whether an element can have more than one
	// annotation of this type on it.
	AllowRepeated bool
}

Annotation is a meta-annotation. Other types that will be used as annotations should be annotated with it. For example:

// @annogo.Annotation
type MyNewAnnotation struct {
    Foo int
    Bar []string
}

Running the annotation processor on the package containing this type will generate code for accessing the runtime-visible annotations. Only annotations on top-level elements (and fields and methods of top-level types) are accessible. Annotations on constants are not accessible unless they are typed constants (then accessible via type and constant name). Annotations on variables are accessible using the variable's address unless the variable's storage size is zero. (This applies to variables whose type is an empty struct or an array of empty structs.) Otherwise, the variables are accessible using the variable's type and name.

Annotations on constructs defined inside of function and method bodies (types and fields thereof) are not allowed.

@Annotation{AllowedElements: Types}

type AnnotationValue

type AnnotationValue struct {
	Type  reflect.Type
	Value reflect.Value
}

AnnotationValue describes a single annotation, its type and its value.

func GetAllAnnotationsForField

func GetAllAnnotationsForField(t reflect.Type, fieldName string) []AnnotationValue

GetAllAnnotationsForField returns all recorded annotations for the given field.

type foo struct {
  // @MyAnnotation{fiz:"buzz"}
  // @SomeAnnotation(42)
  // @SomeOtherAnnotation
  bar string
  baz string
}

// pass field name as string
annos := annogo.GetAllAnnotationsForField(reflect.TypeOf(foo{}), "bar")

func GetAllAnnotationsForFunction

func GetAllAnnotationsForFunction(function interface{}) []AnnotationValue

GetAllAnnotationsForFunction returns all recorded annotations for the given function.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
func foo(bar int) bool {
  return bar == 24
}

// pass the function itself
annos := annogo.GetAllAnnotationsForFunction(foo)

func GetAllAnnotationsForInterfaceEmbed

func GetAllAnnotationsForInterfaceEmbed(t, embedType reflect.Type) []AnnotationValue

GetAllAnnotationsForInterfaceEmbed returns all recorded annotations for the given interface embed.

func GetAllAnnotationsForInterfaceMethod

func GetAllAnnotationsForInterfaceMethod(t reflect.Type, methodName string) []AnnotationValue

GetAllAnnotationsForInterfaceMethod returns all recorded annotations for the given interface method.

func GetAllAnnotationsForType

func GetAllAnnotationsForType(t reflect.Type) []AnnotationValue

GetAllAnnotationsForType returns all recorded annotations for the given type.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
type foo struct {
  bar, baz string
}

annos := annogo.GetAllAnnotationsForType(reflect.TypeOf(foo{}))

func GetAllAnnotationsForValue

func GetAllAnnotationsForValue(val ValueDesc) []AnnotationValue

GetAllAnnotationsForValue returns all recorded annotations for the given value (which describes either a var or a const). The value will typically have come from a call to GetAnnotatedVarsOfType, GetAnnotatedVarsOfTypeInPkg, GetAnnotatedConstsOfType, or GetAnnotatedConstsOfTypeInPkg,

package fff; // import "github.com/foobar/fff"
// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
var foo = bar{a: "b", c: 'd', e: 111}

valDesc := annogo.ValueDesc{
    Type:        reflect.TypeOf(bar{}),
    PackagePath: "github.com/foobar/fff",
    ValueName:   "foo",
}
annos := annogo.GetAllAnnotationsForValue(valDesc)

func GetAllAnnotationsForVar

func GetAllAnnotationsForVar(varAddr interface{}) []AnnotationValue

GetAllAnnotationsForVar returns all recorded annotations for the given var. This will return no annotations, even if the var is annotated, if the given var has a storage size of zero. For zero-size vars, GetAllAnnotationsForValue must be used instead.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
var foo = bar{a: "b", c: 'd', e: 111}

// pass the address of the var
annos := annogo.GetAllAnnotationsForVar(&foo)

type AnyType

type AnyType interface{}

AnyType is a special marker type that is used in annotation fields where one might use interface{} in an ordinary Go struct. The annotation parser allows any kind of value.

The kinds of values that the parser may assign to an AnyType field follow:

  1. Numeric types: int64, uint64, float64, or complex128
  2. Character types: string, rune
  3. Other scalars: bool
  4. Structs. This is the type used for values that appear to be structs. A value appears to be a struct if it has the shape of a map but all of its keys are unqualified identifiers, in which case the identifiers are taken to be field names. The concrete type of an AnyType with a struct value will be an unnamed struct type.
  5. Arrays of any supported type. The array's element type will be AnyType if the contents appear heterogenous. Note that struct elements may appear to be heterogenous since types are strictly inferred from the constants in the annotation data. So if one element has a field named "Foo" and an unsigned integer value, but another has a field of the same name with a signed (e.g. negative) integer value, they will be interpreted as heterogenous elements. Similarly, arrays of arrays appear heterogenous if the elements have different lengths. (AnyType values do not use slices, only arrays.)
  6. Maps whose keys and values are of any supported type. Like any other map in the Go language, maps cannot be used as keys in other maps. The map's key and/or value types will be AnyType if they appear heterogenous. See above remarks about heterogenous array elements for why struct values can appear heterogenous even when that is not the intent.

Note that this marker type can also be used inside function types and has a special meaning in that context. For example, consider the following annotation type:

// @annogo.Annotation
type Foo struct {
    Make     func(string) annogo.AnyType
    Registry func(map[string]annogo.AnyType) error
}

In this case, an annotation value can refer to any function that accepts a string and returns one value, regardless of the actual return type, for the field named "Make". Similarly, the value for the field named "Registry" can refer to any function that accepts a map with string keys and returns error, regardless of the map's value type. Note that channels of, pointers to, and structs with AnyTypes are not supported this way; only array, slice, and map types are.

When used this way, the actual underlying function and its signature type can be queried using annogo.GetUnderlyingFunction. The actual annotation value will be a synthetic function that delegates to the correct one. For functions that accept or return an array, slice, or map type that references AnyType, the synthetic function will have to copy the arguments/return values to translate between the declared and actual signatures.

type DefaultValue

type DefaultValue struct {
	//   @Required
	Value SelfType
}

DefaultValue is an annotation that indicates a default value for an annotation field. It is not valid to use on types or methods. It is also not valid to use with fields in structs that are not themselves annotations.

@Annotation{AllowedElements: AnnotationFields}

type ElementType

type ElementType int

ElementType is an enumeration of the kinds of elements that can be annotated.

const (
	// AnnotationTypes are type elements that are themselves annotations (e.g.
	// annotated with @annogo.Annotation).
	//
	// Only top-level, named types can be annotated. Types defined inside of
	// functions and methods cannot be annotated.
	AnnotationTypes ElementType = iota

	// AnnotationFields are fields of annotation types that are structs. Only
	// fields of top-level, named types can be annotated.
	AnnotationFields

	// Types are type elements. This is a superset of AnnotationTypes and is
	// also the union of ConcreteTypes and Interfaces.
	//
	// Only top-level, named types can be annotated. Types defined inside of
	// functions and methods cannot be annotated.
	Types

	// ConcreteTypes are type elements that are *not* interfaces. This is a
	// subset of Types. This is the complement of Interfaces. The union of
	// ConcreteTypes and Interfaces is the same as Types.
	//
	// Only top-level, named types can be annotated.
	ConcreteTypes

	// Interfaces are type elements that are defined to be interfaces. This is a
	// subset of Types. This is the complement of ConcreteTypes. The union of
	// ConcreteTypes and Interfaces is the same as Types.
	//
	// Only top-level, named interfaces can be annotated.
	Interfaces

	// Fields are fields of struct type elements. Only fields of top-level,
	// named types can be annotated. Annotations that allow fields will also
	// allow annotation fields (e.g. fields of annotation types).
	Fields

	// Methods are method elements. Only methods of top-level, named types
	// can be annotated. This element type only applies to methods that have
	// bodies: interface methods are not allowed unless InterfaceMethods is also
	// used.
	Methods

	// InterfaceMethods are the methods that comprise an interface. Only methods
	// of top-level, named interfaces can be annotated.
	InterfaceMethods

	// InterfaceEmbeds are the interface types embedded in another interface.
	// Only the embeds of top-level, named interfaces can be annotated.
	InterfaceEmbeds

	// Functions are top-level, named functions. Methods for named types are
	// functions, too. So an annotation that allows function elements also allows
	// such method elements. However, this only applies to methods that have
	// bodies: interface methods are not allowed unless InterfaceMethods is also
	// used.
	Functions

	// Variables are top-level (e.g. package-level) variables. Variables inside
	// function and method bodies cannot be annotated.
	Variables

	// Constants are top-level (e.g. package-level) constants. Constants that
	// are defined inside of function and method bodies cannot be annotated.
	Constants
)

func (ElementType) String

func (et ElementType) String() string

type FactoryFunc

type FactoryFunc func(AnyType) SelfType

FactoryFunc names a function that produces values for the annotated type or field. The function should take a single argument (which represents the structure of the annotation's value) and return a single value, which must have the same type as the annotated type or field.

Factories are necessary for types that need to maintain extra invariants or provide stronger encapsulation. For example, an immutable value must use a factory function since, to provide immutability, its fields/contents must be unexported.

@Annotation{AllowedElements: {Types, Fields}}

type Required

type Required bool

Required is an annotation that indicates an annotation field that must be defined in an annotation. When this annotation is not present, fields that are not defined in a given annotation will use the zero value for the field's type or a DefaultValue if that annotation is present. But when this annotation is present, they may not assume a default value; the annotation must explicitly define a value.

@Annotation{AllowedElements: AnnotationFields}

type SelfType

type SelfType interface{}

SelfType is a special marker type. When an annotation is a struct that contains a field of this type, the value of that field will be the same type as the annotated type. This can only be used to annotate types and fields (in which case it refers to the field's type). It cannot be used in annotations on methods.

Note that the kinds of values that can actually be described in an annotation are limited. For example, function types can only refer to named functions. Channels aren't supported at all.

Like AnyType, this marker type can also be used inside function types and has a similar special meaning in that context.

type ValueDesc

type ValueDesc struct {
	Type        reflect.Type
	PackagePath string
	ValueName   string
}

ValueDesc describes a value declaration, a var or a const.

func GetAnnotatedConstsOfType

func GetAnnotatedConstsOfType(varType reflect.Type) []ValueDesc

GetAnnotatedConstsOfType returns descriptions for all consts of the given type that have annotations.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
const foo = bar(123123) // typed constants only

// "foo" returned in this list, along with any other annotated consts
consts := annogo.GetAnnotatedConstsOfType(reflect.TypeOf(bar(0)))

func GetAnnotatedConstsOfTypeInPkg

func GetAnnotatedConstsOfTypeInPkg(varType reflect.Type, pkgName string) []ValueDesc

GetAnnotatedConstsOfTypeInPkg returns descriptions for all consts of the given type defined in the given package that have annotations.

package fff; // import "github.com/foobar/fff"
// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
const foo = bar(123123) // typed constants only

// "foo" returned in this list, along with any other annotated consts
// must pass package import path, not package name
consts := annogo.GetAnnotatedConstsOfTypeInPkg(
    reflect.TypeOf(bar(0)), "github.com/foobar/fff")

func GetAnnotatedVarsOfType

func GetAnnotatedVarsOfType(varType reflect.Type) []ValueDesc

GetAnnotatedVarsOfType returns descriptions for all vars of the given type that have annotations.

// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
var foo = bar{a: "b", c: 'd', e: 111}

// "foo" returned in this list, along with any other annotated vars
vars := annogo.GetAnnotatedVarsOfType(reflect.TypeOf(bar{}))

func GetAnnotatedVarsOfTypeInPkg

func GetAnnotatedVarsOfTypeInPkg(varType reflect.Type, pkgName string) []ValueDesc

GetAnnotatedVarsOfTypeInPkg returns descriptions for all vars of the given type defined in the given package that have annotations.

package fff; // import "github.com/foobar/fff"
// @MyAnnotation{fiz:"buzz"}
// @SomeAnnotation(42)
// @SomeOtherAnnotation
var foo = bar{a: "b", c: 'd', e: 111}

// "foo" returned in this list, along with any other annotated vars
// must pass package import path, not package name
vars := annogo.GetAnnotatedVarsOfTypeInPkg(
    reflect.TypeOf(bar{}), "github.com/foobar/fff")

Directories

Path Synopsis
cmd
aptgo
Command aptgo is the annotation processing tool for Go.
Command aptgo is the annotation processing tool for Go.
Package parser implements a parser for Go annotations.
Package parser implements a parser for Go annotations.
Package processor contains the runtime library used by code that processes annotations.
Package processor contains the runtime library used by code that processes annotations.

Jump to

Keyboard shortcuts

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