001package daikon.tools.jtb;
002
003import static java.nio.charset.StandardCharsets.UTF_8;
004import static java.util.logging.Level.FINE;
005import static java.util.logging.Level.INFO;
006
007import daikon.*;
008import daikon.inv.OutputFormat;
009import gnu.getopt.*;
010import java.io.File;
011import java.io.FileNotFoundException;
012import java.io.Reader;
013import java.io.Writer;
014import java.nio.file.Files;
015import java.nio.file.Paths;
016import java.util.logging.Logger;
017import jtb.*;
018import jtb.syntaxtree.*;
019import org.plumelib.util.StringsPlume;
020
021/**
022 * Merge Daikon-generated invariants into Java source code as ESC/JML/DBC annotations. All original
023 * {@code .java} files are left unmodified; copies are created.
024 *
025 * <p>The first argument is a Daikon {@code .inv} file -- a serialized file of Invariant objects.
026 * All subsequent arguments are {@code Foo.java} files that are rewritten into {@code
027 * Foo.java-jmlannotated} versions; alternately, use the {@code -r} flag to process every {@code
028 * .java} file under the current directory.
029 */
030public class Annotate {
031
032  // ESC format: Invariants are inserted as follows:
033  //  * invariants at method entry become "requires"
034  //  * invariants at method exit become "ensures".
035  //    ensures/exsures annotations should not mention orig(primitive arguments).
036  //  * invariants at method exceptional exit become "exsures"
037  //  * object invariants become object invariants, inserted at the beginning
038  //    of the java class
039  //  * "modifies" clauses are inserted for changed variables.
040  //    Use "a[*]", not "a[]" or "a[i]" or "a[i..]" or "a[...].field", for arrays;
041  //    consider adding a \forall to specify which indices are *not* changed.
042  //    Modifies clauses should not contain "size()", ".getClass()", or "~".
043  //    Modifies clauses should not contain final fields.
044  //  * use "also_requires", "also_ensures", "also_modifies" if this method
045  //    overrides another method/interface.
046
047  // spec_public:
048  // for each non-public field, add "/*@ spec_public */" to its declaration
049
050  // owner annotations:
051  // for each private field that is set via a call to new in the constructor
052  // (in the short term, just do this for all array fields):
053  //  * add object invariant "invariant field.owner == this"
054  //  * whenever the field is set, "set field.owner = this"
055
056  // JML format: The formatting is similar to ESC (heavyweight) format,
057  // but "modifies" clauses are omitted.
058
059  // DBC format: same as ESC format, but "requires" becomes "@pre",
060  // "ensures" becomes "@post", and we omit everything but invariants,
061  // pre and postconditions.  See Appendix A below for Jtest's (not
062  // very formal or detailed) specification of their DBC
063  // language.  Note that we avoided using most DBC constructs -- we
064  // found the DBC aspect of Jtest buggy, so we try to depend on their
065  // constructs as little as possible.
066
067  // Explanatory comments:
068  // Handle "The invariant on the following line means:".
069
070  // Optional behavior:
071  //  * With -i flag, invariants not supported by ESC are inserted with "!"
072  //    instead of "@"; by default these "inexpressible" invariants are
073  //    simply omitted.
074  //  * With -s flag, use // comments; by default, use /* comments.
075
076  public static final Logger debug = Logger.getLogger("daikon.tools.jtb.Annotate");
077
078  public static final String wrapXML_SWITCH = "wrap_xml";
079  public static final String max_invariants_pp_SWITCH = "max_invariants_pp";
080  public static final String no_reflection_SWITCH = "no_reflection";
081
082  /** The usage message for this program. */
083  private static String usage =
084      StringsPlume.joinLines(
085          "Usage:  java daikon.tools.Annotate FILE.inv FILE.java ...",
086          "  -h   Display this usage message",
087          "  -i   Insert invariants not supported by ESC with \"!\" instead of \"@\";",
088          "       by default these \"inexpressible\" invariants are simply omitted",
089          "  -r   Use all .java files under the current directory as arguments",
090          "  -s   Use // comments rather than /* comments",
091          "  --format name  Insert specifications in the given format: DBC, ESC, JML, Java",
092          "  --wrap_xml     Wrap each annotation and auxiliary information in XML tags",
093          "  --max_invariants_pp N",
094          "                 Annotate the sources with at most N invariants per program point",
095          "                 (the annotated invariants will be an arbitrary subset of the",
096          "                 total number of invariants for the program point).",
097          "  --no_reflection",
098          "                  (This is an experimental option.) Annotate uses reflection",
099          "                  to determine whether a method overrides/implements another",
100          "                  method. If this flag is given, Annotate will not use reflection",
101          "                  to access information about an instrumented class. This means",
102          "                  that in the JML and ESC formats, no \"also\" annotations",
103          "                  will be inserted.",
104          "  --dbg CATEGORY",
105          "  --debug",
106          "                  Enable one or all loggers, analogously to the Daikon option");
107
108  public static void main(String[] args) throws Exception {
109    try {
110      mainHelper(args);
111    } catch (Daikon.DaikonTerminationException e) {
112      Daikon.handleDaikonTerminationException(e);
113    }
114  }
115
116  /**
117   * This does the work of {@link #main(String[])}, but it never calls System.exit, so it is
118   * appropriate to be called progrmmatically.
119   */
120  public static void mainHelper(final String[] args) throws Exception {
121    boolean slashslash = false;
122    boolean insert_inexpressible = false;
123    boolean setLightweight = true;
124    boolean useReflection = true;
125    int maxInvariantsPP = -1;
126
127    Daikon.output_format = OutputFormat.ESCJAVA;
128    LongOpt[] longopts =
129        new LongOpt[] {
130          new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
131          new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
132          new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
133          new LongOpt(Daikon.format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
134          new LongOpt(wrapXML_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
135          new LongOpt(max_invariants_pp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
136          new LongOpt(no_reflection_SWITCH, LongOpt.NO_ARGUMENT, null, 0)
137        };
138    Getopt g = new Getopt("daikon.tools.jtb.Annotate", args, "hs", longopts);
139    int c;
140    while ((c = g.getopt()) != -1) {
141      switch (c) {
142        case 0:
143          // got a long option
144          String option_name = longopts[g.getLongind()].getName();
145
146          if (Daikon.help_SWITCH.equals(option_name)) {
147            System.out.println(usage);
148            throw new Daikon.NormalTermination();
149          } else if (no_reflection_SWITCH.equals(option_name)) {
150            useReflection = false;
151          } else if (max_invariants_pp_SWITCH.equals(option_name)) {
152            try {
153              maxInvariantsPP = Integer.parseInt(Daikon.getOptarg(g));
154            } catch (NumberFormatException e) {
155              System.err.println(
156                  "Annotate: found the --max_invariants_pp option "
157                      + "followed by an invalid numeric argument. Annotate "
158                      + "will run without the option.");
159              maxInvariantsPP = -1;
160            }
161          } else if (wrapXML_SWITCH.equals(option_name)) {
162            PrintInvariants.wrap_xml = true;
163          } else if (Daikon.debugAll_SWITCH.equals(option_name)) {
164            Global.debugAll = true;
165          } else if (Daikon.debug_SWITCH.equals(option_name)) {
166            daikon.LogHelper.setLevel(Daikon.getOptarg(g), FINE);
167          } else if (Daikon.format_SWITCH.equals(option_name)) {
168            String format_name = Daikon.getOptarg(g);
169            Daikon.output_format = OutputFormat.get(format_name);
170            if (Daikon.output_format == null) {
171              throw new Daikon.UserError("Bad argument:  --format " + format_name);
172            }
173            if (Daikon.output_format == OutputFormat.JML) {
174              setLightweight = false;
175            } else {
176              setLightweight = true;
177            }
178          } else {
179            throw new Daikon.UserError("Unknown long option received: " + option_name);
180          }
181          break;
182        case 'h':
183          System.out.println(usage);
184          throw new Daikon.NormalTermination();
185        case 'i':
186          insert_inexpressible = true;
187          break;
188          // case 'r':
189          //   // Should do this witout calling out to the system.  (There must be
190          //   // an easy way to do this in Java.)
191          //   Process p = System.exec("find . -type f -name '*.java' -print");
192          //   p.waitFor();
193          //   StringBuilderInputStream sbis
194          //   break;
195        case 's':
196          slashslash = true;
197          break;
198        case '?':
199          break; // getopt() already printed an error
200        default:
201          System.out.println("getopt() returned " + c);
202          break;
203      }
204    }
205
206    // Set up debug traces; note this comes after reading command line options.
207    daikon.LogHelper.setupLogs(Global.debugAll ? FINE : INFO);
208
209    // The index of the first non-option argument -- the name of the .inv file
210    int argindex = g.getOptind();
211
212    if (argindex >= args.length) {
213      throw new Daikon.UserError(
214          "Error: No .inv file or .java file arguments supplied." + Global.lineSep + usage);
215    }
216    String invfile = args[argindex];
217    argindex++;
218    if (argindex >= args.length) {
219      throw new Daikon.UserError(
220          "Error: No .java file arguments supplied." + Global.lineSep + usage);
221    }
222    PptMap ppts = FileIO.read_serialized_pptmap(new File(invfile), /*use saved config=*/ true);
223
224    Daikon.suppress_redundant_invariants_with_simplify = true;
225
226    for (; argindex < args.length; argindex++) {
227      String javafilename = args[argindex];
228      if (!(javafilename.endsWith(".java") || javafilename.endsWith(".java-random-tabs"))) {
229        throw new Daikon.UserError("File does not end in .java: " + javafilename);
230      }
231      File outputFile;
232      if (Daikon.output_format == OutputFormat.ESCJAVA) {
233        outputFile = new File(javafilename + "-escannotated");
234      } else if (Daikon.output_format == OutputFormat.JML) {
235        outputFile = new File(javafilename + "-jmlannotated");
236      } else if (Daikon.output_format == OutputFormat.JAVA) {
237        outputFile = new File(javafilename + "-javaannotated");
238      } else if (Daikon.output_format == OutputFormat.DBCJAVA) {
239        outputFile = new File(javafilename + "-dbcannotated");
240      } else {
241        throw new Error("unsupported output file format " + Daikon.output_format);
242      }
243      // outputFile.getParentFile().mkdirs();
244      try (Writer output = Files.newBufferedWriter(outputFile.toPath(), UTF_8)) {
245
246        debug.fine("Parsing file " + javafilename);
247
248        // Annotate the file
249        Node root;
250        try (Reader input = Files.newBufferedReader(Paths.get(javafilename), UTF_8)) {
251          JavaParser parser = new JavaParser(input);
252          root = parser.CompilationUnit();
253        } catch (FileNotFoundException e) {
254          throw new Error(e);
255        } catch (ParseException e) {
256          // e.printStackTrace();
257          System.err.println(javafilename + ": " + e);
258          throw new Daikon.UserError("ParseException in applyVisitorInsertComments");
259        }
260
261        debug.fine("Processing file " + javafilename);
262
263        Ast.applyVisitorInsertComments(
264            javafilename,
265            root,
266            output,
267            new AnnotateVisitor(
268                javafilename,
269                root,
270                ppts,
271                slashslash,
272                insert_inexpressible,
273                setLightweight,
274                useReflection,
275                maxInvariantsPP));
276      } catch (Error e) {
277        String message = e.getMessage();
278        if (message != null && message.startsWith("Didn't find class ")) {
279          throw new Daikon.UserError(
280              String.join(
281                  System.lineSeparator(),
282                  message + ".",
283                  "Be sure to put .class files on the classpath when calling Annotate.",
284                  "The classpath is: " + System.getProperty("java.class.path")));
285        }
286        throw e;
287      }
288    }
289  }
290}
291
292// Appendix A: Jtest DBC format (taken from documentation provided by
293// Jtest with their tool, version 1.x)
294
295//                     Design by Contract for Java
296//
297//
298//    This document describes the syntax and semantics for the "Design by
299// Contract" (DbC) specification supported by Jcontract 1.X.
300//
301//    The "Design by Contract" contracts are expressed with Java code
302// embedded in Javadoc comments in the .java source file.
303//
304//
305// 1. Javadoc Tags for Design by Contract.
306// --------------------------------------
307//
308//    The reserved javadoc tags for DbC are:
309//
310// - @invariant: specifies class invariant condition.
311// - @pre: specifies method pre-condition.
312// - @post: specifies method post-condition.
313// - @concurrency: specifies the method concurrency.
314//
315// Jcontract and Jtest also support the following tags:
316//
317// - @throws/@exception: to document exceptions.
318// - @assert: to put assertions in the method bodies.
319// - @verbose: to add verbose statements to the method bodies.
320//
321//    Please see "appendix10.txt" for information about those tags.
322//
323//
324// 2. Contract Syntax.
325// ------------------
326//
327//    The general syntax for a contract is:
328//
329//         DbcContract:
330//               DbcTag DbcCode
331//             | @concurrency { concurrent | guarded | sequential }
332//
333// where
334//
335//         DbcTag:
336//               @invariant
337//             | @pre
338//             | @post
339//
340//         DbcCode:
341//               BooleanExpression
342//             | '(' BooleanExpression ')'
343//             | '(' BooleanExpression ',' MessageExpression ')'
344//             | CodeBlock
345//             | $none
346//
347//         MessageExpression:
348//               Expression
349//
350//    Any Java code can be used in the DbcCode with the following restrictions:
351//
352// - The code should not have side effects, i.e. it should not have assignments
353//   or invocation of methods with side-effects.
354//
355//    Also the following extensions to Java (DbC keywords) are allowed in the
356// contract code:
357//
358// - $result: used in a @post contract, evaluates to the return value of the
359//   method.
360//
361// - $pre: used in a @post contract to refer to the value of an expression at
362//   @pre-time. The syntax to use it is: $pre (ExpressionType, Expression).
363//   Note: the full "$pre (...)" expression should not extend over multiple lines.
364//
365// - $assert: can be used in DbcCode CodeBlocks to specify the contract conditions.
366//   The syntax to use it is:
367//     $assert (BooleanExpression) or
368//     $assert (BooleanExpression , MessageExpression)
369//
370// - $none: to specify there is no contract.
371//
372//
373//    Notes:
374//
375// - The @pre, @post and @concurrent tags apply to the method that follows in
376//   the source file.
377//
378// - The MessageExpression is optional and will be used to identify the contract
379//   in the error messages or contract violation exceptions thrown.
380//   The MessageExpression can be of any type. If it is a reference type it will
381//   be converted to a String using the "toString ()" method. If it is of
382//   primitive type it will first be wrapped into an object.
383//
384// - There can be multiple conditions of the same kind for a given method.
385//   If there are multiple conditions, all conditions are checked. The
386//   conditions are ANDed together into one virtual condition.
387//   For example it is equivalent (and encouraged for clarity) to have multiple
388//   @pre conditions instead of a single big @pre condition.
389//
390//
391// Examples:
392//
393//
394//     /**
395//       * @pre {
396//       *     for (int i = 0; i < array.length; i++)
397//       *         $assert (array [i] != null, "array elements are non-null");
398//       * }
399//       */
400//
401//     public void set (int[] array) {...}
402//
403//
404//     /** @post $result == ($pre (int, arg) + 1) */
405//
406//     public int inc (arg) {...}
407//
408//
409//     /** @invariant size () >= 0 */
410//
411//     class Stack {...}
412//
413//
414//     /**
415//      * @concurrency sequential
416//      * @pre (value > 0, "value positive:" + value)
417//      */
418//
419//     void update (int value) {...}
420//
421//
422// 3. Contract Semantics.
423// ---------------------
424//
425//    The contracts are specified in comments and will not have any effect if
426// compiling or executing in a non DbC enhanced environment.
427//
428//    In a DbC enhanced environment the contracts are executed/checked when
429// methods of a class with DbC contracts are invoked.  Contracts placed inside
430// a method are treated like normal statements and can thus alter the flow of
431// poorly structured conditional statements.  See section 6: Coding Conventions
432// for details.
433//
434//    A contract fails if any of these conditions occur:
435//
436// a) The "BooleanExpression" evaluates to "false"
437//
438// b) An "$assert (BooleanExpression)" is called in a "CodeBlock" with an argument
439//    that evaluates to "false".
440//
441// c) The method is called in a way that violates its @concurrency contract.
442//
443//    If a contract fails the Runtime Handler for the class is notified of
444// the contract violation. Jcontract provides several Runtime Handlers, the
445// default one uses a GUI Monitor that shows the program progress and what
446// contracts are violated. The user can also write its own RuntimeHandlers,
447// for more information see {isntalldir}\docs\runtime.txt.
448//
449//    With the Moninor Runtime Handlers provided by Jcontract program execution
450// continues as if nothing had happened when a contract is violated, i.e. even
451// if a @pre contract is violated, the method will still be executed.
452//    This option makes the DbC enabled and non DbC enabled versions of the
453// program to work in exactly the same way. The only difference is that in the
454// DbC enabled version the contract violations are reported to the current
455// Jcontract Monitor.
456//
457//
458//    Note that contract evaluation is not nested, when a contract calls
459// another methods, the contracts in the other method are not executed.
460//
461//
462// 4. DbC Contracts.
463// ----------------
464//
465//    This section gives details about each specific DbC tag.
466//
467//
468// 4.1 @pre.
469// - - - - -
470//
471//    Pre-conditions check that the client calls the method correctly.
472//
473// - Point of execution: right before calling the method.
474//
475// - Scope: can access anything accessible from the method scope except local
476//   variables. I.e. can access method arguments, and methods/fields of the
477//   class.
478//
479//
480// 4.2 @post.
481// - - - - -
482//
483//    Post-conditions check that the method doesn't work incorrectly.
484//    Sometimes when a post-condition fails it means that the method was not
485// actually supposed to accept the arguments that were passed to it. The fix in
486// this case is to strengthen the @pre-condition.
487//
488// - Point of execution: right after the method returns successfully. Note that
489//   if the method throws an exception the @post contract is not executed.
490//
491// - Scope: same as @pre plus can access "$result" and "$pre (type, expression)".
492//
493//
494// 4.3 @invariant.
495// - - - - - - - -
496//
497//    Class invariants are contracts that the objects of the class should
498// always satisfy.
499//
500// - Point of execution: same as @pre/@post: invariant checked before checking
501//   the pre-condition and after checking the post-condition.
502//   Done for every non-static, non-private method entry and exit and for
503//   every non-private constructor exit.
504//   - Note that if a constructor throws an exception its @post contract is not
505//     executed.
506//   - Not done for "finalize ()".
507//   - When inner class methods are executed, the invariants of the outer classes
508//     are not checked.
509//
510// - Scope: class scope, can access anything a method in the class can access,
511//   except local variables.
512//
513//
514// 4.4 @concurrency.
515// - - - - - - - - -
516//
517//    The @concurrency tag specifies how the method can be called by multiple
518// threads. Its possible values are:
519//
520// a) concurrent: the method can be called simultaneously by different threads.
521//    I.e. the method is multi-thread safe. Note that this is the default
522//    mode for Java methods.
523//
524// b) guarded: the method can be called simultaneously by different threads,
525//    but only one will execute it in turn, while the other threads will
526//    wait for the executing one to finish.
527//    I.e. it specifies that the method is synchronized.
528//    Jcontract will just give a compile-time error if a method is declared
529//    as "guarded" but is not declared as "synchronized".
530//
531// c) sequential: the method can only by executed by one thread at once and it
532//    is not declared synchronized. It is thus the responsibility of the callers
533//    to ensure that no simultaneous calls to that method occur. For methods with
534//    this concurrency contract Jcontract will generate code to check if they are
535//    being executed by more than one thread at once. An error will be reported
536//    at run time if the contract is violated.
537//
538// - Point of execution: right before calling the method.
539//
540//
541// 5. Inheritance.
542// --------------
543//
544//    Contracts are inherited. If the derived class or overriding method doesn't
545// define a contract, it inherits that of the superclass or interface.
546//    Note that a contract of $none implies that the super contract is applied.
547//
548//    If an overriding method does define a contract then it can only:
549//
550// - Weaken the precondition: because it should at least accept the same input as
551//   the parent, but it can also accept more.
552//
553// - Strengthen the postcondition: because it should at least do as much as the
554//   parent one, but it can also do more.
555//
556//    To enforce this:
557//
558// - When checking the @pre condition, the pre-condition contract is assumed to
559//   succeed if any of the @pre conditions of the chain of overridded methods
560//   succeeds. I.e. the preconditions are ORed.
561//
562// - When checking the @post condition, the post-condition contract is assumed
563//   to succeed if all the @post conditions of the chain of overridded methods
564//   succeed. I.e. the postconditions are ANDed.
565//
566//    Note that if there are multiple @pre conditions for a given method, the
567// preconditions are ANDed together into one virtual @pre condition and then
568// ORed with the virtual @pre conditions for the other methods in the chain
569// of overridden methods.
570//
571//    For @invariant conditions the same logic as for @post applies.
572//
573//    @concurrency contracts are also inherited. If the overriding method doesn't
574// have a @concurrency contract it inherits that of the parent. If it has an
575// inheritance contract it can only weaken it, like for @pre conditions. For
576// example if the parent has a "sequential" @concurrency, the overriding method
577// can have a "guarded" or "concurrent" @concurrency.
578//
579// 6. Special Keyword and Functions
580//
581// 6.1 Keywords
582//
583// $implies
584//
585//     You can use the '$implies' keyword to compare two boolean expressions,
586//     ensuring that when the first expression is true, the second one also
587//     is true.
588//
589//     Example: a $implies b
590//     This is equivalent to '!a || b'.
591//
592// 6.2 Collection functions
593//
594// Class and method contracts can contain a few special functions that are
595// internally mapped to equivalent Java code.
596//
597// These are:
598//
599// public boolean Collection.$forall(Type t; <boolean expression>)
600//
601//     <boolean expression> is an expression that will be evaluated for all
602//     elements in the collection, with each element of type "Type", using
603//     an element named "t". The value of $forall is true when for all elements
604//     the expression evaluates to true.
605//
606//     Think of this as a modified 'for' statement.
607//
608//     Example:
609//     /** @pre names.$forall (String s; s.length() != 0) */
610//     void method (List names) { }
611//
612//     Since $forall generates a boolean value, you can use it with assert
613//     in a block precondition:
614//
615//     /** @pre {
616//             $assert (names != null);
617//             $assert (names.$forall (String e; e.length() > 1));
618//         }
619//      */
620//
621// public boolean Collection.$exists(Type t; <boolean expression>)
622//
623//     This is almost identical in structure to $forall, but it succeeds if any
624//     of the elements in the collection cause the expression to evaluate to true.
625//
626//     Example:
627//     /** @pre names.$exists (String s; s != null && "seth".equals (s)) */
628//     void method (List names) { }
629//
630// 7. Coding Conventions.
631// ---------------------
632//
633//    When using Design by Contract in Java, the following coding conventions
634// are recommended:
635//
636// 1) Place all the @invariant conditions in the class javadoc comment, the
637//    javadoc comment appearing immediately before the class definition.
638//
639// 2) It is recommended that the Javadoc comments with the @invariant tag appear
640//    before the class definition.
641//
642// 3) All public and protected methods should have a contract. It is recommended
643//    that all package-private and private methods also have a contract.
644//
645// 4) If a method has a DbC tag it should have a complete contract. This means
646//    that is should have both a precondition and a postcondition.
647//    One should use "DbcTag $none" to specify that a method doesn't have any
648//    condition for that tag.
649//
650// 5) No public class field should participate in an @invariant clause. Since any
651//    client can modify such a field arbitrarily, there is no way for the class to
652//    ensure any invariant on it.
653//
654// 6) The code contracts should only access members visible from the interface.
655//    For example the code in the @pre condition of a method should only access
656//    members that are accessible from any client that could use the method. I.e.
657//    the contract of a public method should only use public members from the
658//    method's class.
659//
660// 7) Contracts that appear in the body of a method should be thought of as
661//    normal statements.  Thus the following example would have undesireable
662//    behavior:
663//
664//        if (a) /** @assert (a) */
665//            System.out.println("poor use of contract code");
666//
667//    Because the assert is a normal statement when your code is compiled by
668//    dbc_javac, this example is equivalent to the following pseudocode:
669//
670//        if (a)
671//            assert (a);
672//        System.out.println("poor use of contract code");
673//
674//    which makes it clear that the assertion is the body of the "if".
675//
676//    The current version of Jcontract doesn't enforce these coding conventions.