• Aucun résultat trouvé

S3

//@assert E <vf;

}

13.3 Assert Statements

The syntax of assert and redundant assert statements is as follows.

assert-statement ::=assertexpression [:expression ];

| assertpredicate [:expression ];

assert-redundantly-statement ::=assert_redundantlypredicate [:expression ];

Note that Java (as of J2SDK 1.4) also has its own assert statement. For this reason JML distinguishes between assert statements that occur inside and outside annotations.

Outside an annotation, an assert statement is a Java assert statement, whose syntax follows the first assert-statement production above. Thus in such an assert statement, the first expression can have side effects (potentially, although it shouldn’t). The second expression is supposed to have type String, and will be used in a message should the assertion fail.

Inside an annotation, an assert statement is a JML assert statement, and the second syntax is used forassert-statement. Thus instead of anexpressionbefore the optional colon, there is a JMLpredicate. This predicate cannot have side effects, but can use the various JML extensions to the Java expression syntax (seeSection 12.2 [Specification Expressions], page 90, for details.) As in a Java assert statement, the optional expression that follows the colon must be aString, which is printed if the assertion fails.

An assert statements tells JML to check that the specified predicateis true at the given point in the program. The runtime assertion checker checks such assertions during execution of the program, when control reaches the assert statement. Other tools, such as verification tools, will try to prove that the assertion always holds at that program point, for every possible execution.

The assert-redundantly-statement must appear in an annotation. It has the same se-mantics as the JML form of an assert statement, but is marked as redundant. Thus it would be used to call attention to some property, but need not be checked.

13.4 JML Annotation Statements

The following gives the syntax of JML annotation statements. These can appear any-where in normal Java code, but must be enclosed in annotations. See Section 13.3 [Assert Statements], page 113, for the syntax of theassert-redundantly-statement. See Chapter 15 [Model Programs], page 122, for the syntax of additional statements that can only be used in model programs.

jml-annotation-statement ::=assert-redundantly-statement

Chapter 13: Statements and Annotation Statements 114

|assume-statement

|hence-by-statement

|set-statement

|refining-statement

|unreachable-statement

|debug-statement

13.4.1 Assume Statements

The syntax of an assume statement is as follows. As in a Java assert statement, the optional expression that follows the colon must be aString, which is printed if the assumption fails.

assume-statement ::=assume-keyword predicate [:expression ];

assume-keyword ::=assume | assume_redundantly

In runtime assertion checking, assumptions are checked in the same way that assert statements are checked (see Section 13.3 [Assert Statements], page 113).

However, in static analysis tools, the assume statement is used to tell the tool that the given predicate is assumed to be true, and thus need not be checked.

13.4.2 Set Statements

The syntax of a set statement is as follows. SeeSection 12.3 [Expressions], page 90, for the syntax ofassignment-expr.

set-statement ::=set assignment-expr ;

A set statement is the equivalent of an assignment statement but is within an annotation.

It is used to assign a value to a ghost variable or to a ghost field. A set statement serves to assist the static checker in reasoning about the execution of the routine body in which it appears. Note that:

• the target of the set statement must be a ghost variable or a ghost field, and

• the right-hand-side of theassignment-expr must be a pure expression (i.e., it must not have side effects).

Examples:

//@ set i = 0;

//@ set collection.elementType = \type(int);

The reason that right hand side of the assignment-expr must be pure is because set-statements are not part of the normal Java code, but only occur in annotations. Hence they must not affect normal Java code execution, but only have side effects on the ghost field or ghost variable being assigned. This restriction is a conservative way to guarantee that property.

13.4.3 Refining Statements

The syntax of a refining statement is as follows. SeeSection 15.6 [Specification Statements], page 125, for the syntax ofspec-statementandgeneric-spec-statement-case. SeeChapter 13 [Statements and Annotation Statements], page 108, for the syntax ofstatement.

Chapter 13: Statements and Annotation Statements 115

refining-statement ::=refiningspec-statement statement

| refininggeneric-spec-statement-case statement

A refining statement allows one to annotate a specification with a specification. It has two parts, aspecificationand abody. The specification part can be either aspec-statement (see Section 15.6 [Specification Statements], page 125), which includes the grammar for a heavyweight specification case, or a generic-spec-statement-case (see Section 15.6 [Specifi-cation Statements], page 125), which includes the grammar for a lightweight specifi[Specifi-cation case. The body is simply a statement. In particular, the body can be acompound-statement or a jml-annotation-statement, including a nestedrefining-statement.

Annotating the body with a specification is a way of collecting all the specification information about the statement in one place. Giving such an annotation is especially useful for framing, e.g., writing assignable-clauses. For example, by using a refining statement, one can write an assignable clause for a loop statement or for the statement in the body of a loop.

Refining statements are also used in connection with model program specification cases (see Chapter 15 [Model Programs], page 122). Within the implementation of a method with such a model program specification, a refining statement indicates exactly what spec-statementis implemented by its body, since its specification part would be exactly that spec-statement. This is helpful for “matching” the implementation against the model program specification [Shaner-Leavens-Naumann07].

Note that the scope of any declarations made in the specification part of a refining statement are limited to the specification part, and do not extend into the body. Thus a refining statement is type correct if each of its subparts is type correct, using the surrounding context for separately type checking the specification and body.

The meaning of a refining statement of the form refiningS B is that the bodyB must refine the specification given in S. This means that B has to obey all the specifications given in S. For example, B may not assume a stronger precondition than that given by S. (Standard defaults are used for omitted clauses in the specification part of a refining statement; thus, if there is no requires clause in a spec-statement, then the precondition defaults to true.) Similarly, B may not assign to locations that are not permitted to be assigned to byS, and, assumingS’s precondition held, then whenB terminates normally it must establish S’s normal postcondition. See Chapter 9 [Method Specifications], page 63, for more about what it means to satisfy such a specification.

When \old()or\pre()are used in the specification part of a refining statement, they have the same meaning as in a specification statement (seeSection 15.6 [Specification State-ments], page 125).

In execution, a refining statement of the form refining S B just executes its body B.

For this reason, typically the refiningkeyword and the specification S would be in JML annotations, but the bodyB would be normal Java code (outside of any annotation).

See Chapter 15 [Model Programs], page 122, for more examples.

13.4.4 Unreachable Statements

The syntax of the unreachablestatement is as follows.

unreachable-statement ::=unreachable ;

Chapter 13: Statements and Annotation Statements 116

The unreachable statement is an annotation that asserts that the control flow of a routine will never reach that point in the program. It is equivalent to the annotation assert false. If control flow does reach an unreachable statement, a tool that checks (by reasoning or at runtime) the behavior of the routine should issue an error of some kind.

The following is an example:

if (true) { ...

} else {

//@ unreachable;

}

13.4.5 Debug Statements

The syntax of the debug statement is as follows. See Section 12.3 [Expressions], page 90, for the syntax ofexpression.

debug-statement ::=debugexpression ;

Adebugstatement is the equivalent of an expression statement but is within an annota-tion. Thus, features visible only in the JML scope can also appear in thedebugstatement.

Examples of such features include ghost variables, model methods,spec_publicfields, and JML-specific expression constructs, to name a few.

The main use of thedebugstatement is to help debugging specifications, e.g., by printing the value of a JML expression, as shown below.

//@ debug System.err.println(x);

In the above example, the variable x may be a ghost variable. Note that using System.err automatically flushes output, unlike System.out. This flushing of output is helpful for debugging.

As shown in the above example, expressions with side-effects are allowed in the debug statement. These include not only methods with side-effects but also increment (++) and decrement (--) operators and various forms of assignment expressions (e.g., =, +=, etc.).

Thus, the debugstatement can also be used to assign a value to a variable, or mutate the state of an object.

//@ debug x = x + 1;

//@ debug aList.add(y);

However, a model variable cannot be assigned to, nor can its state be mutated by using the debug statement, as its value is given by a represents clause (see Section 8.4 [Represents Clauses], page 60).

There is no restriction on the type of expression allowed in the debugstatement.

Tools should allow debug statements to be turned on or off easily. Thus programmers should not count on debug statements being executed. For example, if one needs to assign to a ghost variable, the proper way to do it is to use a set-statement (see Section 13.4.2 [Set Statements], page 114), which would execute even if debug statements are not being executed.

13.4.6 Hence By Statements

The syntax of the hence_bystatement is as follows.

Chapter 13: Statements and Annotation Statements 117

hence-by-statement ::=hence-by-keyword predicate ; hence-by-keyword ::=hence_by | hence_by_redundantly

Thehence_bystatement is used to record reasoning when writing a proof by intermittent assertions. It would normally be used between two assert statements (seeSection 13.3 [As-sert Statements], page 113) or between two assume statements (seeSection 13.4.1 [Assume Statements], page 114).

[[[Needs example.]]]

Chapter 14: Redundancy 118

14 Redundancy

JML has several features that allow the specification of implications [Tan95] and examples [Leavens97c] [Leavens-Baker99]. They are redundant in the sense that they do not con-strain an implementation directly. Instead, they are useful for pointing out consequences to the specification’s readers, for example to draw attention to some consequences of the specification of a method, or to illustrate it by an example.

In addition to clauses of the form X_redundantly, such as requires_redundantly, ensures_redundantly, etc., there are two sections of a method specification that are voted to such redundant specifications. These sections of a method specification are de-scribed by the following grammar.

redundant-spec ::=implications [examples ]|examples

The two subsections below explain these features. The description of clauses of the form X_redundantlyis contained in the first section.