001package daikon.tools.runtimechecker;
002
003import daikon.tools.jtb.Ast;
004import jtb.syntaxtree.*;
005import org.checkerframework.checker.nullness.qual.NonNull;
006
007/** Represents a class created by the instrumenter to check invariants. */
008public class CheckerClass {
009
010  String name;
011  StringBuilder code;
012  ClassOrInterfaceBody fclassbody;
013
014  public CheckerClass(ClassOrInterfaceBody clazz) {
015    this.fclassbody = clazz;
016
017    // The getClassName method may return some $'s and .'s.
018    // Since this is going to become a class name, remove them.
019    this.name = Ast.getClassName(clazz).replace("$", "_").replace(".", "_") + "_checks";
020
021    // CompilationUnit:
022    // f0 -> [ PackageDeclaration() ]
023    // f1 -> ( ImportDeclaration() )*
024    // f2 -> ( TypeDeclaration() )*
025    // f3 -> ( <"\u001a"> )?
026    // f4 -> ( <STUFF_TO_IGNORE: ~[]> )?
027    // f5 -> <EOF>
028    // PackageDeclaration:
029    // f0 -> Modifiers()
030    // f1 -> "package"
031    // f2 -> Name()
032    // f3 -> ";"
033    // Get the package and imports from clazz. We'll include them.
034    @SuppressWarnings("nullness") // application invariant: every body is in a compilation unit
035    @NonNull CompilationUnit clazzCU =
036        (CompilationUnit) Ast.getParent(CompilationUnit.class, clazz);
037    NodeOptional no = clazzCU.f0;
038    String packageName;
039    if (no.present()) {
040      packageName = Ast.format(((PackageDeclaration) no.node).f2).trim();
041    } else {
042      packageName = "";
043    }
044
045    String imports = Ast.format(clazzCU.f1);
046
047    code = new StringBuilder();
048    if (!packageName.equals("")) {
049      code.append("package " + packageName + ";");
050    }
051    code.append(imports);
052    code.append(" public class " + name + "{ ");
053  }
054
055  // See getCompilationUnit().
056  private boolean alreadyCalled = false;
057
058  /** Must be called only once, when you're done creating this checker. */
059  public CompilationUnit getCompilationUnit() {
060    if (alreadyCalled) {
061      throw new Error("getCompilationUnit should only be called once.");
062    }
063    alreadyCalled = true;
064    code.append("}"); // we're done declaring the class.
065    return (CompilationUnit) Ast.create("CompilationUnit", code.toString());
066  }
067
068  public String getCheckerClassName() {
069    return name;
070  }
071
072  public void addDeclaration(StringBuilder decl) {
073    code.append(decl);
074  }
075}