AspectC++ Language Reference

Olaf Spinczyk and

pure-systems GmbH
Version 2.2, March 10, 2017

Table of Contents

About

This document is intended to be used as a reference book for the AspectC++ language elements. It describes in-depth the use and meaning of each element providing examples. For experienced users the contents of this document are summarized in the AspectC++ Quick Reference. Detailed information about the AspectC++ compiler ac++ can be looked up in the AspectC++ Compiler Manual.
AspectC++ is an aspect-oriented extension to the C++ language. It is similar to AspectJ but, due to the nature of C++, in some points completely different. The first part of this document introduces the basic concepts of the AspectC++ language. The in-depth description of each language element is subject of the second part.

Basic Concepts

2.1 Pointcuts

Aspects in AspectC++ implement crosscutting concerns in a modular way. With this in mind the most important element of the AspectC++ language is the pointcut. Pointcuts describe a set of join points by determining on which condition an aspect shall take effect. Thereby each join point can either refer to a function, a type/class, a variable, or a point from which a join point is accessed so that this condition can be for instance the event of reaching a designated code position or the allocation of a variable with a certain value. Depending on the kind of pointcuts, they are evaluated at compile time or at runtime.

2.1.1 Match Expressions

There are two types of pointcuts in AspectC++: code pointcuts and name pointcuts. Name pointcuts describe a set of (statically) known program entities like types/classes, variables, functions, or namespaces. All name pointcuts are based on match expressions. A match expression can be understood as a search pattern . In such a search pattern the special character “%” is interpreted as a wildcard for names or parts of a signature. The special character sequence “…” matches any number of parameters in a function signature or any number of scopes in a qualified name. A match expression is a quoted string.

Example: match expressions (name pointcuts)

"int C::%(...)"
 
matches all member functions of the class C that return an int
"%List"
 
matches any namespace, class, struct, union, or enum whose name ends with List. In case of a matched namespace or class the match expression also matches entities inside the namespace resp. class. For more information see section
3.2.
"%
printf(const char *, ...)"  
matches the function printf (defined in the global scope) having at least one parameter of type const char * and returning any type
"const %& ...::%(...)"
 
matches all functions that return a reference to a constant object
Match expressions select program entities with respect to their definition scope, their type, and their name. A detailed description of the match expression semantics follows in section 3. The grammar which defines syntactically valid match expressions is shown in appendix B.

2.1.2 Pointcut Expressions

The other type of pointcuts, the code pointcuts , describe an intersection through the set of the points in the control flow of a program. A code pointcut can refer to a call or execution point of a function, to a call of a built-in operator or and to write and read points of member variables and global variables. They can only be created with the help of name pointcuts because all join points supported by AspectC++ require at least one name to be defined. This is done by calling predefined pointcut functions in a pointcut expression that expect a pointcut as argument. Such a pointcut function is for instance within(pointcut), which filters all join points that are within the functions or classes in the given pointcut.
Name and code pointcuts can be combined in pointcut expressions by using the algebraic operators “&&”, “||”, and “!”.

Example: pointcut expressions

"%List" && !derived("Queue")
 
describes the set of classes with names that end with “List” and that are not derived from the class Queue
call("void
draw()") && within("Shape")  
describes the set of calls to the function draw that are within methods of the class Shape

2.1.3 Types of Join Points

According to the two types of pointcuts supported by AspectC++ there are also two coarse types of join points: name join points and code join points. As diagramed in figure 1 both of these have sub join point types. The types Any, Name, Code and Access are abstract types and exist just for categorizing the other join point types.

Figure 1 is extracted from the AspectC++ project repository hierarchy, that can be found in appendix C.
Based on a short code fragment the differences and relations between the types of join points shall be clarified.
class Shape { /*...*/ };
void draw(Shape& shape) { /*...*/ }

namespace Circle { 
  typedef int PRECISION;
  
  class S_Circle : public Shape {
    PRECISION m_radius;
    public:
      void radius(PRECISION r) {
        m_radius = r;
      }
      ~S_Circle() { /*...*/ }
  };
  
  void draw(PRECISION r) {
    S_Circle circle;
    circle.radius(r);
    draw(circle);
  }
}

int main() {
  Circle::draw(10);
  return 0;
}
Code join points are used to form code pointcuts and name join points (i.e. names) are used to form name pointcuts. Figure 2 shows join points of the code fragment above and how they correlate. Built-in constructors, destructors and uncalled operators are not shown. Additionally appendix D shows the contents of the project repository for the code fragment.
Every execution join point is associated with the name of an executable function. Pure virtual functions are not executable. Thus, advice code for execution join points would never be triggered for this kind of function. However, the call of such a function, i.e. a call join point with this function as target, is absolutely possible. Furthermore there are no execution join points for built-in operator functions.
Every call or builtin join point is associated with two names: the name of the source and the target function (in case of builtin this is the global built-in operator function) of a function call. As there can be multiple function calls within the same function, each function name can be associated with a list of call join points and builtin join points . The same holds for set and get join points, which represent write resp. read operations on data members or global variables. Each of these join points is associated with the name of the function that contains the join point and the name of the accessed member variable or global variable. A construction join point means the class specific instruction sequence executed when an instance is created. In analogy, a destruction join point means the object destruction.

2.1.4 Pointcut declarations

AspectC++ provides the possibility to name pointcut expressions with the help of pointcut declarations. This makes it possible to reuse pointcut expressions in different parts of a program. They are allowed where C++ declarations are allowed. Thereby the usual C++ name lookup and inheritance rules are also applicable for pointcut declarations.
A pointcut declaration is introduced by the keyword pointcut.

Example: pointcut declaration

pointcut lists() = derived("List");
 
lists can now be used everywhere in a program where a pointcut expression can be used to refer to derived("List")
Furthermore pointcut declarations can be used to define pure virtual pointcuts . This enables the possibility of having re-usable abstract aspects that are discussed in section 2.5. The syntax of pure virtual pointcut declarations is the same as for usual pointcut declarations except the keyword virtual following pointcut and that the pointcut expression is “0”.

Example: pure virtual pointcut declaration

pointcut virtual methods() = 0;
 
methods is a pure virtual pointcut that has to be redefined in a derived aspect to refer to the actual pointcut
expression

2.2 Attributes

Based on the C++11 attribute syntax AspectC++ provides an annotation mechanism for join points. All join points annotated with the same attribute “a”, e.g. class [[a]] C {…}, can be referred to in a pointcut expression as a(). Further information can be found in section 5.

2.3 Slices

A slice is a fragment of a C++ language element that defines a scope. It can be used by advice to extend the static structure of the program. For example, the elements of a class slice can be merged into one or more target classes by introduction advice. The following example shows a simple class slice declaration.

Example: class slice declaration

slice class Chain {
Chain *_next;
public:
Chain *next () const { return _next; }
};

2.4 Advice Code

To a code join point so-called advice code can be bound. Advice code can be understood as an action activated by an aspect when a corresponding code join point in a program is reached. The activation of the advice code can happen before , after , or before and after the code join point is reached. The AspectC++ language element to specify advice code is the advice declaration . It is introduced by the keyword advice followed by a pointcut expression defining where and under which conditions the advice code shall be activated.

Example: advice declaration

advice execution("void login(...)") : before() {
cout << "Logging in." << endl;
}
The code fragment :before() following the pointcut expression determines that the advice code shall be activated directly before the code join point is reached. It is also possible here to use :after() which means after reaching the code join point respectively :around() which means that the advice code shall be executed instead of the code described by the code join point. In an around advice the advice code can explicitly trigger the execution of the program code at the join point so that advice code can be executed before and after the join point. There are no special access rights of advice code regarding to program code at a join point.
Beside the pure description of join points pointcuts can also bind variables to context information of a join point. Thus for instance the actual argument values of a function call can be made accessible to the advice code.

Example: advice declaration with access to context information

pointcut new_user(const char *name) =
execution("void login(...)") && args(name);
advice new_user(name) : before(const char *name) {
cout << "User " << name << " is logging in." << endl;
}
In the example above at first the pointcut new_user is defined including a context variable name that is bound to it. This means that a value of type const char* is supplied every time the join point described by the pointcut new_user is reached. The pointcut function args used in the pointcut expression delivers all join points in the program where an argument of type const char* is used. Therefore args(name) in touch with the execution join point binds name to the first and only parameter of the function login.
The advice declaration in the example above following the pointcut declaration binds the execution of advice code to the event when a join point described in new_user is reached. The context variable that holds the actual value of the parameter of the reached join point has to be declared as a formal parameter of before, after, or around. This parameter can be used in the advice code like an oridinary function parameter.
Beside the pointcut function args the binding of context variables is performed by that , target , and result . At the same time these pointcut functions act as filters corresponding to the type of the context variable. For instance args in the example above filters all join points having an argument of type const char*.

2.4.1 Introductions

The second type of advice supported by AspectC++ are the introductions. Introductions are used to extend program code and data structures in particular. The following example extends two classes each by a member variable and a member function.

Example: introductions

pointcut shapes() = "Circle" || "Polygon";
advice shapes() : slice class {
bool m_shaded;
void shaded(bool state) {
m_shaded = state;
}
};

Example: base class introduction

2.4.2 Advice Ordering

Example: advice ordering

If advice of both aspects (see 2.5) Encrypt and Log should be run when the function send(...) is called this order declaration defines that the advice of Encrypt has a higher precedence. More details on advice ordering and precedence can be found in section 9.

2.5 Aspects

Example: aspect declaration

aspect Counter {
static int m_count;
pointcut counted() = "Circle" || "Polygon";
advice counted() : slice struct {
class Helper {
Helper() { Counter::m_count++; }
} m_counter;
};
advice execution("% main(...)") : after() {
cout << "Final count: " << m_count << " objects"
<< endl;
}
};
... and at an appropriate place
#include "Counter.ah"
int Counter::m_count = 0;

Example: abstract aspect

aspect Counter {
static int m_count;
Counter() : m_count(0) {}
pointcut virtual counted() = 0;
...
};

Example: reused abstract aspect

2.5.1 Aspect Instantiation

Example: aspect instantiation using aspectof

aspect ThreadCounter : public Counter {
pointcut counted() = "Thread";
advice counted() : ThreadCounter m_instance;
static ThreadCounter *aspectof() {
return tjp->target()->m_instance;
}
};

2.6 Runtime Support

2.6.1 Support for Advice Code

Example: re-usable trace aspect

aspect Trace {
pointcut virtual methods() = 0;
advice execution(methods()) : around() {
cout << "before " << JoinPoint::signature() << "(";
for (unsigned i = 0; i < JoinPoint::args(); i++)
printvalue(tjp->arg(i), JoinPoint::argtype(i));
cout << ")" << endl;
tjp->proceed();
cout << "after" << endl;
}
};

2.6.2 Actions

2.6.3 Support for Introductions

Example: static type identification using introductions

aspect TypeInfo {
pointcut virtual typed() = 0;
advice typed() : static unsigned type_id() {
return JoinPoint::id();
}
advice typed() : virtual unsigned type() {
return type_id();
}
};

Example: extended thread counting

Match Expressions

3.1 Commonly Used Matching Mechanisms

The grammar used for match expression parsing is shown in appendix B. The following subsections separately describe the name, scope, and type matching mechanisms. All of them are used in match expressions of functions and variables, while match expressions of namespaces and classes only uses name and scope matching.

3.1.1 Name Matching

Example: simple name patterns

3.1.2 Scope Matching

Example: scope patterns

3.1.3 Type Matching

Example: type patterns with the wildcard character
Matching of Named Types
Matching of “Pointer to Member” Types
Matching of Qualified Types (const/volatile)
Example: type patterns with const and volatile
Handling of Conversion Function Types
Ellipses in Function Type Patterns
Matching Virtual Functions
Example: type patterns with virtual
Matching Static Functions
Example: type patterns with static
Argument Type Adjustment

3.2 Namespace and Class Match Expressions

Example: scope and name parts of a namespace or class match expression

scope:
the scope in which the namespace or class is defined has to match Puma::...::
name:
the name of the namespace or class has to match the name pattern Parser%
Please note that local classes inside functions or member functions are never matched.

3.3 Function Match Expressions

Example: type, scope, and name parts of a function match expression

name:
the function name has to match the name pattern parse_%
scope:
the scope in which the function is defined has to match Puma::...::
type:
the function type has to match const %(Token *)
Common descriptions of name, scope and type matching can be found in section 3.1. The following sections additionally describe the name matching of special functions.

3.3.1 Operator Function and Conversion Function Name Matching

Example: operator name patterns
Example: conversion function name patterns

3.3.2 Constructors and Destructors

3.4 Variable Match Expressions

Example: type, scope, and name parts of a variable match expression

name:
the variable name has to match the name pattern parsed_%
scope:
the scope in which the variable is defined has to match Puma::...::
type:
the variable type has to match const %

Predefined Pointcut Functions

4.1 Types

base(pointcut)
N C,F,V N C,F,V
returns a pointcut p b of name join points created as follows
p b { all base classes of classes in pointcut but not the classes in pointcut } ,
p b p b ||{ all member functions and data members of classes in p b } ,
p b p b ||{ all previous definitions of member functions in pointcut but not the member functions in pointcut } ,
p b p b ||{ all previous definitions of data members in pointcut but not the data members in pointcut }
derived(pointcut)
N C,F,V N C,F,V
returns a pointcut p d of name join points created as follows
p d { all classes in pointcut and all classes derived from them } ,
p d p d ||{ all member functions and data members of classes in p d } ,
p d p d ||{ all member functions in pointcut and all redefinitions of these member functions in derived classes } ,
p d p d ||{ all data members in pointcut and all redefinitions of these data members in derived classes }

Example: derived function matching

Example: type matching

aspect Scale {
pointcut scalable() = "Rectangle" ||
(base("Rectangle") && derived("Point"));
advice "Point" : slice class : public Scalable;
advice scalable() : slice class {
void scale(int value) { ... }
};
};

4.2 Control Flow

cflow(pointcut)
C C
captures join points occurring in the dynamic execution context of join points in pointcut. Currently the language features being used in the argument pointcut are restricted. The argument is not allowed to contain any context variable bindings (see
4.8) or other pointcut functions which have to be evaluated at runtime like cflow(pointcut) itself.

Example: control flow dependant advice activation

aspect BusIntSync {
  pointcut critical() = execution("% Bus::%(...)");
  advice critical() && !cflow(execution("% os::int_handler()")) : around() {
    os::disable_ints();
    tjp->proceed();
    os::enable_ints();
  }
};

4.3 Scope

within(pointcut)
N C
returns all code join points that are located directly inside or at a name join point in pointcut
member(pointcut)
N N
maps the scopes given in pointcut to any contained named entities. Thus a class name for example is mapped to all contained member functions, variables and nested types.

Example: matching in scopes

aspect Logger {
pointcut calls() =
call("void transmit()") && within("Transmitter");
advice calls() : around() {
cout << "transmitting ... " << flush;
tjp->proceed();
cout << "finished." << endl;
}
};

4.4 Functions

call(pointcut)
N F C C
returns all code join points where a user provided function or member function in pointcut is called. The resulting join points are located in the scope of the resp. caller meaning where the function or member functions is called. The pointcut does not include join points at calls to built-in operators.
execution(pointcut)
N F C E
returns all code join points where a function or member function in pointcut is executed. The resulting join points are located in the scope of the callee meaning where the function or member function is defined/implemented.

Example: function matching

aspect Debug {
  pointcut fct() = "% MemPool::dealloc(void*)";
  pointcut exec() = execution(fct());
  pointcut calls() = call(fct());

  advice exec() && args(ptr) : before(void *ptr) {
    assert(ptr && "argument is NULL");
  }
  advice calls() : before() {
    assert(tjp->target() && "'this' is NULL");
  }
};

4.5 Built-in Operators

builtin(pointcut)
N F C B
returns all code join points where a built-in operator in pointcut is called.
This pointcut function does not return join points at constructor or destructor calls. See section
Section 4.6 (4.6) to find out how to describe these join points.
The builtin pointcut function is a new feature that was introduced in version 2.0 and is therefore not enabled by default to avoid compatibility issues (e.g., if someone named a pointcut “builtin”). The command-line argument enables the described functionality.

Example: operator matching

aspect ProblemReporter {
  advice builtin("% operator *(%)") : before() {
    if(*tjp->arg<0>() == 0) {    
      cerr << tjp->filename() << " (Line " << tjp->line() << "): dereferencing of null-pointer!" << endl;
    }
  }
};

4.5.1 Limitations

Some built-in operators could not be fully supported. For example, weaving advice code for built-in operators in constant expressions would destroy the constancy of the expressions and inhibit evaluation at compile time. Therefore, operators in constant expressions are not matched. The following code listing gives some examples for operators in constant expressions.A further limitation results from the fact, that the C++-standard forbids pointers and references to bit-fields. Thus all operators that refer to a bit-field (e.g. the assignment- or increment-/decrement-operator needs a reference as first argument) are not supported.

Moreover any operator that has an anonymous/unnamed or local type or a type with no linkage as argument or result is not supported (because these types shall not be used as a template argument which makes weaving impossible in most cases).

Additionally postfix increment/decrement operators have a second implicit argument of type int to distinguish between pre- and postfix operators. So e.g. “% operator ++(%, int)” matches the postfix increment operator and “% operator ++(%)” matches the prefix increment operator.

Also the address-of operator & is not supported, if the argument is a data member or member function, because these types do not exist as type of a variable.

Furthermore the C++-standard states that if the result of .* or ->* is a function, that result can be used only as the operand for the function call operator (). Therefore the pointer to member operators .* and ->*
that get a member function pointer as second argument are not supported, because a caching of the result is not possible.

At last there are some limitations with the short-circuiting
operators &&, || and ?:. If the second or third argument is not evaluated, tjp->args() will return a null-pointer for the corresponding argument. Additionally the result of the args pointcut function (see 4.8) is determined at runtime, if an short-circuit argument is bound with the args pointcut function . Thus the advice code in the following example is only executed, if the first argument evaluates to true so that the second argument is available. In case of || the first argument have to be false to make the second argument available and in case of ?: the first argument makes the decision about the availability of the second resp. third argument. A complete list with all limitations and not supported operators can be found in the next section 4.5.2.
class ExampleClass {
  static const int const_member = 5 * 2;
  unsigned int bitfield : 4 / 2;
}; 
const int const_two = 3 - 1;
static char char_array[const_two + 5];
enum ExampleEnum {
  ENUM_VALUE = const_two + 1
};
switch(const int const_temp = 1) {
  case const_temp + 1: {
    // ...
    break;
  }
}
advice builtin("% operator &&(bool, bool)") && args("%", b2) : before(bool b2) {
  // advice code
}

4.5.2 Supported And Not Supported Operators

This section contains information about the builtin pointcut function in terms of supported operators.
Table
3 shows all operators that are fully or partly supported and indicates the special characteristics of these operators, if available. For more information see section 4.5.1.
Table 4 shows not supported operators.

4.6 Object Construction and Destruction

construction(pointcut)
N C C Cons
returns all code join points where an instance of a class in pointcut is constructed. The construction join point begins after all base class and member construction join points. It can be imagined as the execution of the constructor. However, advice for construction join points work, even if there is no constructor defined explicitly. A construction join point has arguments and argument types, which can be exposed or filtered, e.g. by using the args pointcut function.
destruction(pointcut)
N C C Des
returns all code join points where an instance of a class in pointcut is destructed. The destruction join point ends before the destruction join point of all members and base classes. It can be imagined as the execution of the destructor, although a destructor does not to be defined explicitly. A destruction join point has an empty argument list.

Example: instance counting

4.7 Variables

get(pointcut)
N V C G
returns all code join points where a global variable or data member in pointcut is read. The get join points are located at implicit lvalue-to-rvalue conversions according to the C++ standard. In addition, the get join points are located within all built-in compound-assignment operators, and within the built-in increment and decrement operators.
set(pointcut)
N V C S
returns all code join points where a global variable or data member in pointcut is modified. The set join points are located within all built-in assignment operators, and within the built-in increment and decrement operators. The initialization of a global variable or data member provides no set join point.
ref(pointcut)
N V C R
provides all join points where a reference (reference type or pointer) to a global variable or data member in the pointcut is created. The ref join points are located within the built-in address-of operator &, if the operand is a global variable or data member. In addition, the ref join points are located before the initialization of a variable of reference type, including return values. Moreover, the binding of a reference parameter of a function, including default values, provides ref join points. The ref join points are also located within implicit array-to-pointer conversions according to the C++ standard.

Example: variable matching

aspect IntegerModification {
  advice set("int ...::%") : after() {
    cout << "Setting variable "
         << tjp->signature() << " to "
         << *tjp->entity() << endl;
  }
};

4.7.1 Limitations

4.7.2 Compatibility

4.8 Context

that(type pattern)
N T C
returns all code join points where the current C++ this pointer refers to an object which is an instance of a type that is compatible to the type described by type pattern
target(type pattern)
N T C
returns all code join points where the target object of a call/set/get is an instance of a type that is compatible to the type described by type pattern
result(type pattern)
N T C
returns all code join points where the type of the return value of a call/builtin/execution/get is matched by type pattern
args(type pattern, ...)
(N T ,...) C
returns all code join points where the types of the arguments of a call/builtin/execution/set are matched by the corresponding type patterns.

Example: context matching

4.9 Algebraic Operators

pointcut && pointcut
(N,N) N, (C,C) C
returns the intersection of the join points in the pointcuts
pointcut || pointcut
(N,N) N, (C,C) C
returns the union of the join points in the pointcuts
! pointcut
N N, C C
returns all name resp. code join points that are not included in pointcut

Example: combining pointcut expressions

Attributes

5.1 Attribute declarations

Example: attribute declaration

Example: using attributes to annotate program elements

5.2 Supported code-elements

Table 6 shows the code elements, for which annotations with attributes are supported, and the possible attribute locations. Positions of attributes are marked by [[..]].

5.3 Attributes and pointcut expressions

Example: using attributes in pointcut expressions

Slices

6.1 Class Slice Declarations

Advice

7.1 Advice for Dynamic Join Points

before(...)
 
the advice code is executed before the join points in the pointcut
after(...)
 
the advice code is executed after the join points in the pointcut
around(...)
 
the advice code is executed in place of the join points in the pointcut

7.2 Advice for Static Join Points

baseclass(classname)
 
a new base class is introduced to the classes in the pointcut
introduction declaration
 
a new member variable, member function, or type is introduced

JoinPoint API

8.1 API for Dynamic Join Points

8.1.1 Types and Constants

Result
 
result type of a function
Res::Type,
Res::ReferredType  
result type of the affected function or entity access
Arg<i>::Type,
Arg<i>::ReferredType  
type of the argument of the affected join point (with )
ARGS
   
number of arguments
That
 
object type (object initiating a call)
Target
 
target object type (target object of a call)
Entity
 
type of the primary referenced entity (function or variable)
MemberPtr
 
type of the member pointer for entity or void * for nonmembers
Array
 
type of the accessed array
Dim<i>::Idx
 
type of the ith dimension of the accessed array (with )
Dim<i>::Size
 
size of the ith dimension of the accessed array (with )
DIMS
   
number of dimensions of an accessed array or 0 otherwise
Aspect
 
type of the aspect (only available in introductions)

Example: type usage

8.1.2 Functions

static AC::Type type()
 
returns the encoded type for the join point conforming with the C++ ABI V3 specification
static int args()
 
returns the number of arguments of a function for call and execution join points
static AC::Type argtype(int number)
 
returns the encoded type of an argument conforming with the C++ ABI V3 specification
static const char *signature()
 
gives a textual description of the join point (function name, class name, ...)
static unsigned int id()
 
returns a unique numeric identifier for this join point
static const char *filename()
 
returns the name of the file in which the join point (shadow) is located
static int line()
 
the number of the line in which the join point (shadow) is located
static AC::Type resulttype()
 
returns the encoded type of the result type conforming with the C++ ABI V3 specification
static AC::JPType jptype()
 
returns a unique identifier describing the type of the join point

Example: static function usage

void *arg(int number)
 
returns a pointer to the memory position holding the argument value with index number
Result *result()
 
returns a pointer to the memory location designated for the result value or 0 if the function has no result value
That *that()
 
returns a pointer to the object initiating a call or 0 if it is a static method or a global function
Target *target()
 
returns a pointer to the object that is the target of a call or 0 if it is a static method or a global function
Entity *entity()
 
returns a pointer to the accessed entity (function or variable) or 0 for member functions or builtin operators
MemberPtr *memberptr()
 
returns a member pointer to entity or 0 for nonmembers
Array *array()
 
returns a typed pointer to the accessed array
Dim<i>::Idx idx<i>()
 
returns the value of the ith index used for the array access
void proceed()
 
executes the original join point code in an around advice by calling action().trigger()
AC::Action &action()
 
returns the runtime action object containing the execution environment to execute the original functionality encapsulated by an around advice

Example: non-static function usage

8.2 API for Static Join Points

static const char *signature()
 
returns the target class name as a string
That
 
The (incomplete) target type of the introduction
HASHCODE
 
integer hash value of the target type
BASECLASSES
 
number of base classes of the target class
BaseClass<I>::Type
 
type of the base class
BaseClass<I>::prot, BaseClass<I>::spec
 
Protection level (AC::PROT_NONE /PRIVATE /PROTECTED /PUBLIC) and additional specifiers (AC::SPEC_NONE /VIRTUAL) of the base class
MEMBERS
 
number of data members of the target class
Member<I>::Type, Member<I>::ReferredType
 
type of the member variable of the target class
Member<I>::prot, Member<I>::spec
 
Protection level (see BaseClass<I>::prot) and additional member variable specifiers (AC::SPEC_NONE /STATIC /MUTABLE)
static ReferredType *Member<I>::pointer(T *obj=0)
 
returns a typed pointer to the member variable (obj is needed for non-static member variables)
static const char *Member<I>::name()
 
returns the name of the member variable
FUNCTIONS
 
number of member functions of the target class
Function<I>::prot, Function<I>::spec
 
Protection level (see BaseClass<I>::prot) and additional member variable specifiers (AC::SPEC_NONE /STATIC /VIRTUAL)
CONSTRUCTORS
 
number of user-defined constructors of the target class
Constructor<I>::prot, Constructor<I>::spec
 
Protection level (see BaseClass<I>::prot) and additional member variable specifiers (AC::SPEC_NONE)
DESTRUCTORS
 
number (zero or one) of user-defined destructors of the target class
Destructor<I>::prot, Destructor<I>::spec
 
Protection level (see BaseClass<I>::prot) and additional member variable specifiers (AC::SPEC_NONE /VIRTUAL)

Advice Ordering

9.1 Aspect Precedence

order declaration:
if the programmer provides an order declaration, which defines the precedence relationship between two aspects for a join point, the compiler will obey this definition or abort with a compile-time error if there is a cycle in the precedence graph. Order declarations have the following syntax:
advice
pointcut-expr : order ( high, ...low )
The argument list of order has to contain at least two elements. Each element is a pointcut expression, which describes a set of aspects. Each aspect in a certain set has a higher precedence than all aspects, which are part of a set following later in the list (on the right hand side). For example '("A1"||"A2","A3"||"A4")' means that A1 has precedence over A3 and A4 and that A2 has precedence over A3 and A4. This order directive does not define the relation between A1 and A2 or A3 and A4. Of course, the pointcut expressions in the argument list of order may contain named pointcuts and even pure virtual pointcuts.
inheritance relation:
if there is no order declaration given and one aspect has a base aspect the derived aspect has a higher precedence than the base aspect.

9.2 Advice Precedence

9.3 Effects of Advice Precedence

Class Join Points

Code Join Points

For example, consider an aspect that defines advice in the following order: BE1, AF1, AF2, AR1, BE2, AR2, AF3. As described in section 9.2 the declaration order also defines the precedence: BE1 has the highest and AF3 the lowest. The result is the following advice code execution sequence:
  1. BE1 (highest precedence)
  2. AR1 (the indented advice will only be executed if proceed() is called!)
    1. BE2 (before AR2, buts depends on AR1)
    2. AR2 (the indented code will only be executed if proceed() is called!)
      1. original code under the join point
      2. AF3
  3. AF2 (does not depend on AR1 and AR2, because of higher precedence)
  4. AF1 (run after AF2, because it has a higher precedence)

List of Examples

Grammar

class-key:
 
aspect
declaration:
 
pointcut-declaration
slice-declaration
advice-declaration
attribute-declaration
member-declaration:
 
pointcut-declaration
slice-declaration
advice-declaration
attribute-declaration
pointcut-declaration:
 
pointcut  declaration
pointcut-expression:
 
constant-expression
advice-declaration:
 
advice  pointcut-expression  :  order-declaration
advice  pointcut-expression  :  slice-reference
advice  pointcut-expression  :  declaration
order-declaration:
 
order (  pointcur-expression-seq )
slice-reference:
 
slice :: opt  nested-name-specifier opt unqualified-id ;
slice-declaration:  
slice
declaration
attribute-declaration:
 
attribute  unqualified-id ( ) ;

Match Expression Grammar

match-expression:
 
match-declaration
match-id:
 
%
nondigit
match-id %
match-id nondigit
match-id digit
match-declaration:
 
match-decl-specifier-seq opt match-declarator
match-decl-specifier-seq:
 
match-decl-specifier-seq opt match-decl-specifier
match-decl-specifier:
 
nested-match-name-specifier opt match-id
cv-qualifier
match-function-specifier
char
wchar_t
bool
short
int
long
signed
unsigned
float
double
void
match-function-specifier:
 
virtual
static
nested-match-name-specifier:
 
match-id :: nested-match-name-specifier opt
... :: nested-match-name-specifier opt
match-declarator:
 
direct-match-declarator
match-ptr-declarator match-declarator
abstract-match-declarator:
 
direct-abstract-match-declarator
match-ptr-declarator abstract-match-declarator
direct-match-declarator:
 
match-declarator-id
direct-match-declarator
( match-parameter-declaration-clause ) cv-qualifier-seq opt
direct-match-declarator
[ match-array-size ]
direct-abstract-match-declarator:
 
direct-abstract-match-declarator
( match-parameter-declaration-clause ) cv-qualifier-seq opt
direct-abstract-match-declarator
[ match-array-size ]
match-array-size:
 
%
decimal-literal
match-ptr-operator:
 
* cv-qualifier-seq opt
&
nested-match-name-specifier * cv-qualifier-seq opt
match-parameter-declaration-clause:
 
...
match-parameter-declaration-list opt
match-parameter-declaration-list
, ...
match-parameter-declaration-list:
 
match-parameter-declaration
match-parameter-declaration-list
, match-parameter-declaration
match-parameter-declaration:
 
matct-decl-specifier-seq match-abstract-declarator opt
match-declarator-id:
 
nested-match-name-specifier opt match-id
nested-match-name-specifier opt match-operator-function-id
nested-match-name-specifier opt match-conversion-function-id
match-operator-function-id:
 
operator %
operator match-operator
match-operator:
one of
match-conversion-function-id:
 
operator match-conversion-type-id
match-conversion-type-id:
 
match-type-specifier-seq match-conversion-declarator opt
match-conversion-declarator:
 
match-ptr-operator match-conversion-declarator opt

Structure Of The Project Repository

Figure 3 shows the internal structure of the AspectC++ model and the AspectC++ project repository. The distinction between name and code join points and also the inheritance hierarchy is visible.

Project Repository File For Example elsewhere

<?xml version="1.0"?>
<ac-model version="1.2" ids="7">
  <files>
    <TUnit filename="shape.cpp" len="42" time="1442951698" id="0"/>
  </files>
  <root>
    <Namespace name="::">
      <children>
        <Class name="Shape" id="1">
          <children>
            <Function kind="8" cv_qualifiers="0" name="~Shape" builtin="true">
              <children>
                <Destruction/>
              </children>
            </Function>
            <Function kind="7" cv_qualifiers="0" name="Shape" builtin="true">
              <children>
                <Construction/>
              </children>
            </Function>
            <Function kind="7" cv_qualifiers="0" name="Shape" builtin="true">
              <arg_types>
                <Type signature="const Shape &amp;"/>
              </arg_types>
              <children>
                <Construction/>
              </children>
            </Function>
          </children>
          <source>
            <Source kind="1" file="0" line="1" len="1"/>
            <Source kind="2" file="0" line="1" len="1"/>
          </source>
        </Class>
        <Namespace name="Circle">
          <children>
            <Class bases="1" name="S_Circle" id="4">
              <children>
                <Function kind="7" cv_qualifiers="0" name="S_Circle" builtin="true">
                  <children>
                    <Construction/>
                  </children>
                </Function>
                <Function kind="7" cv_qualifiers="0" name="S_Circle" builtin="true">
                  <arg_types>
                    <Type signature="const Circle::S_Circle &amp;"/>
                  </arg_types>
                  <children>
                    <Construction/>
                  </children>
                </Function>
                <Variable kind="3" name="m_radius">
                  <type>
                    <Type signature="int"/>
                  </type>
                  <source>
                    <Source kind="1" file="0" line="8" len="1"/>
                  </source>
                </Variable>
                <Function kind="3" cv_qualifiers="0" name="radius" id="3">
                  <result_type>
                    <Type signature="void"/>
                  </result_type>
                  <arg_types>
                    <Type signature="int"/>
                  </arg_types>
                  <children>
                    <Execution/>
                    <Builtin target="2" lid="0">
                      <source>
                        <Source kind="0" file="0" line="11" len="1"/>
                      </source>
                    </Builtin>
                  </children>
                  <source>
                    <Source kind="1" file="0" line="10" len="3"/>
                  </source>
                </Function>
                <Function kind="8" cv_qualifiers="0" name="~S_Circle">
                  <children>
                    <Destruction/>
                  </children>
                  <source>
                    <Source kind="1" file="0" line="13" len="1"/>
                  </source>
                </Function>
              </children>
              <source>
                <Source kind="1" file="0" line="7" len="8"/>
                <Source kind="2" file="0" line="7" len="1"/>
              </source>
            </Class>
            <Function kind="1" cv_qualifiers="0" name="draw" id="6">
              <result_type>
                <Type signature="void"/>
              </result_type>
              <arg_types>
                <Type signature="int"/>
              </arg_types>
              <children>
                <Execution/>
                <Call target="3" lid="0" target_class="4">
                  <source>
                    <Source kind="0" file="0" line="18" len="1"/>
                  </source>
                </Call>
                <Call target="5" lid="1">
                  <source>
                    <Source kind="0" file="0" line="19" len="1"/>
                  </source>
                </Call>
              </children>
              <source>
                <Source kind="1" file="0" line="16" len="5"/>
              </source>
            </Function>
          </children>
          <source>
            <Source kind="0" file="0" line="4" len="18"/>
          </source>
        </Namespace>
        <Function kind="1" cv_qualifiers="0" name="draw" id="5">
          <result_type>
            <Type signature="void"/>
          </result_type>
          <arg_types>
            <Type signature="Shape &amp;"/>
          </arg_types>
          <children>
            <Execution/>
          </children>
          <source>
            <Source kind="1" file="0" line="2" len="1"/>
          </source>
        </Function>
        <Function kind="1" cv_qualifiers="0" name="operator =" builtin="true" tunits="0" id="2">
          <result_type>
            <Type signature="int &amp;"/>
          </result_type>
          <arg_types>
            <Type signature="int &amp;"/>
            <Type signature="int"/>
          </arg_types>
        </Function>
        <Function kind="1" cv_qualifiers="0" name="main">
          <result_type>
            <Type signature="int"/>
          </result_type>
          <children>
            <Execution/>
            <Call target="6" lid="0">
              <source>
                <Source kind="0" file="0" line="24" len="1"/>
              </source>
            </Call>
          </children>
          <source>
            <Source kind="1" file="0" line="23" len="4"/>
          </source>
        </Function>
      </children>
    </Namespace>
  </root>
</ac-model>