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.