package org.jmlspecs.openjml;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Map;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import org.jmlspecs.annotation.NonNull;
import org.jmlspecs.annotation.Nullable;
import org.jmlspecs.annotation.Pure;
import org.jmlspecs.openjml.JmlSpecs.FieldSpecs;
import org.jmlspecs.openjml.JmlSpecs.TypeSpecs;
import org.jmlspecs.openjml.JmlTree.JmlClassDecl;
import org.jmlspecs.openjml.JmlTree.JmlCompilationUnit;
import org.jmlspecs.openjml.JmlTree.JmlMethodDecl;
import org.jmlspecs.openjml.JmlTree.JmlMethodSpecs;
import org.jmlspecs.openjml.JmlTree.JmlVariableDecl;
import org.jmlspecs.openjml.Main.IProgressListener;
import org.jmlspecs.openjml.proverinterface.IProverResult;
import org.jmlspecs.openjml.proverinterface.ProverResult;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Options;
public interface IAPI {
//@ public model boolean isOpen; private represents isOpen = main != null;
/** Returns the string describing the version of OpenJML that is this
* set of classes.
* @return the version of this instance of OpenJML
*/
public @NonNull String version();
/** The compilation context for this API object */
//@ ensures \result == context;
@Pure
public @Nullable Context context();
/** The compiler object for this context. */
@Pure
public Main main();
/** A partial (abstract) implementation of a progress listener to hear
* progress on this API's operations.
*/
public static abstract class AbstractProgressListener implements IProgressListener {
protected Context context;
public AbstractProgressListener() {
}
/** Called by the subscribed object when a diagnostic report is made */
@Override
public abstract boolean report(int ticks, int level, String message);
// FIXME - can we get rid of this? in the meantime, it must be called to set the context to match that of the compilation context being listened to
@Override
public void setContext(Context context) { this.context = context; }
}
public static interface IProofResultListener {
void reportProofResult(MethodSymbol msym, IProverResult result);
}
/** Sets a progress listener that hears any progress reports (e.g. names of
* files as they are parsed). Any previous listener is forgotten (there is
* just one listener at a time).
* @param p The listener
*/
public void setProgressListener(@Nullable Main.IProgressListener p);
/** Sets a listener for ESC proof results as they are generated. Any previous
* listener is forgotten (there is just one listener at a time).
* @param p the listener
*/
public void setProofResultListener(@Nullable IProofResultListener p);
/** This method initializes the Options instance of the current compilation
* context. If the options argument is not null, its content is used
* to completely initialize the Options instance; if options is null, then
* the options are initialized by reading
* the options specified in the environment (System properties +
* openjml properties files). Then the specified args are processed to make any
* further adjustments to the options. Any errors are reported through the
* log mechanism. Any non-options in the args list (e.g. files) are
* warned about and ignored.
* */
public void initOptions(@Nullable Options options, @NonNull String ... args);
/** Adds additional command-line options to the current context. Any errors
* are reported through the diagnostics Log.
*/
//@ requires isOpen;
//@ ensures isOpen;
public void addOptions(String... args);
/** Adds a custom option (not checked as a legitimate command-line option);
* may have an argument after a = symbol */
public void addUncheckedOption(String arg);
/** Gets the value of a command-line option (null if not set)
* @param name the option name, including the leading - sign
*/
//@ requires isOpen;
//@ ensures isOpen;
public @Nullable
String getOption(String name);
/** Executes the command-line version of OpenJML, in a newly initialized
* Main, with a new compilation context, returning the exit code.
* The arguments are used to initialize the options and files just as
* described for initOptions().
* @param options an instance of options to use
* @param args additional command-line arguments and files to process
* @return the exit code (0 is success; other values are various kinds of errors)
*/
//@ requires isOpen && args != null && \nonnullarguments(args);
//@ ensures isOpen;
public int execute(@Nullable Options options, @NonNull String ... args);
/** Executes the command-line version of OpenJML, in a newly initialized
* Main, with a new compilation context, returning the exit code.
* The arguments are used to initialize the options and files just as
* described for initOptions() and the constructor for Main().
* @param writer the PrintWriter to receive general output
* @param diagListener a listener to receive reports of diagnostics (e.g. parse or typechecking errors and warnings)
* @param args the command-line arguments
* @return the exit code (0 is success; other values are various kinds of errors)
*/
public int execute(@NonNull PrintWriter writer, @Nullable DiagnosticListener<JavaFileObject> diagListener, @Nullable Options options, @NonNull String ... args);
/** Executes the jmldoc tool on the given command-line arguments. This is
* NOT CURRENTLY IMPLEMENTED and the API may change. */
public int jmldoc(@NonNull String... args);
/** Returns true if the class has been type-checked */
public boolean isTypechecked(ClassSymbol csym);
/** Returns true if the class has been type-checked */
public boolean isTypechecked(String qualifiedName);
/** Enters and typechecks the provided already-parsed compilation unit ASTs. The elements
* of the list should all be JmlCompilationUnit nodes. The operation is
* performed in the current compilation context, wihth currently set options.
* It may add new compilation units to some already checked, but currently
* may not check units that have already been checked.
* @param trees a varargs list or an array of the ASTs to be checked
* @return the number of errors encountered
* @throws IOException
*/
public int typecheck(@NonNull JmlCompilationUnit... trees)
throws IOException;
/** Enters and typechecks the provided already-parsed compilation unit ASTs. The elements
* of the list should all be JmlCompilationUnit nodes. The operation is
* performed in the current compilation context, wihth currently set options.
* It may add new compilation units to some already checked, but currently
* may not check units that have already been checked.
* @param trees a collection (java.util.Collection) of the ASTs to be checked
* @return the number of errors encountered
* @throws IOException
*/
//@ requires isOpen;
//@ ensures isOpen;
public int typecheck(
@NonNull Collection<? extends JmlCompilationUnit> trees)
throws java.io.IOException;
/** Enters and typechecks the provided already-parsed compilation unit ASTs;
* The elements
* of the list must all be JmlCompilationUnit nodes (this signature says JCCompilationUnit
* to be compatible with the JavaCompiler API). The operation is
* performed in the current compilation context, wihth currently set options.
* It may add new compilation units to some already checked, but currently
* may not check units that have already been checked.
* @param list a list (com.sun.tools.javac.util.List) of the ASTs to be checked
* @return the number of errors encountered
* @throws IOException
*/
public int typecheck(@NonNull List<? extends JCCompilationUnit> list) throws IOException;
/** Parses each java file and its specs returning a list of the ASTs for corresponding
* java files; the spec files are automatically found according to JML rules;
* the ASTs of the spec files are contained in the
* JmlCompilationUnit.specsSequence. Error messages are reported separately
* through the diagnostic listener;
* if there are errors, a parse tree may be incomplete. The trees are not
* type-checked and do not have any name resolution applied.
* @param files the names of the input .java or .jml files
* @return a list of corresponding ASTs
*/
//@ requires \nonnullelements(files);
//@ requires isOpen;
//@ ensures isOpen;
//@ ensures files.length == \result.size();
//@ ensures (* output elements are non-null *);
public @NonNull
java.util.List<JmlCompilationUnit> parseFiles(@NonNull String... filenames);
/** Parses each java file and its specs returning a list of the ASTs for corresponding
* java files; the spec files are automatically found according to JML rules;
* the ASTs of the spec files are contained in the
* JmlCompilationUnit.specsSequence. Error messages are reported separately
* through the diagnostic listener;
* if there are errors, a parse tree may be incomplete. The trees are not
* type-checked and do not have any name resolution applied.
* @param inputs a collection of JavaFileObject objects representing inputs
* @return a list of corresponding ASTs
*/
public @NonNull
java.util.List<JmlCompilationUnit> parseFiles(@NonNull Collection<? extends JavaFileObject> inputs);
/** Parses each java file and its specs returning a list of the ASTs for corresponding
* java files; the spec files are automatically found according to JML rules;
* the ASTs of the spec files are contained in the
* JmlCompilationUnit.specsSequence. Error messages are reported separately
* through the diagnostic listener;
* if there are errors, a parse tree may be incomplete. The trees are not
* type-checked and do not have any name resolution applied.
* @param files a list of java.io.File inputs
* @return a list of corresponding ASTs
*/
//@ requires \nonnullelements(files);
//@ requires isOpen;
//@ ensures isOpen;
//@ ensures files.length == \result.size();
//@ ensures (* output elements are non-null *);
public @NonNull
java.util.List<JmlCompilationUnit> parseFiles(
@NonNull File... files);
/** Parses each java file and its specs returning a list of the ASTs for corresponding
* java files; the spec files are automatically found according to JML rules;
* the ASTs of the spec files are contained in the
* JmlCompilationUnit.specsSequence. Error messages are reported separately
* through the diagnostic listener;
* if there are errors, a parse tree may be incomplete. The trees are not
* type-checked and do not have any name resolution applied.
* @param inputs an array of JavaFileObject inputs
* @return a list of corresponding ASTs
*/
//@ requires \nonnullelements(inputs);
//@ requires isOpen;
//@ ensures isOpen;
//@ ensures inputs.length == \result.size();
//@ ensures (* output elements are non-null *);
public @NonNull java.util.List<JmlCompilationUnit> parseFiles(@NonNull JavaFileObject... inputs);
/** Produces a parse tree for a single file without any specifications; the
* file may be either a .java or a .jml file. The trees are not
* type-checked and do not have any name resolution applied and are not made
* part of the compilation context.
* @param file the file to be parsed
* @return the parse tree for the file
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlCompilationUnit parseSingleFile(@NonNull JavaFileObject jfo);
/** Produces a parse tree for a single file without any specifications; the
* file may be either a .java or a specification file. The trees are not
* type-checked and do not have any name resolution applied and are not made
* part of the compilation context.
* @param filename the name of the file to be parsed
* @return the parse tree for the file
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlCompilationUnit parseSingleFile(@NonNull String filename);
/** Produces a parse tree for the given text; the text must represent a
* compilation unit for a .java file or a specification file. The name
* is the file path to associate with the text and must include directories
* corresponding to the purported package holding the java class. The trees are not
* type-checked and do not have any name resolution applied and are not made
* part of the compilation context.
* @param name the filename to associate with the text
* @param content the textual content to parse
* @return the parse tree for the file
*/
// FIXME - resolve whether the package name must be present
// TODO: Would like to automatically set the filename, but can't since the
// JavaFileObject has to be created before parsing and it is immutable
//@ requires name.length() > 0;
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlCompilationUnit parseString(@NonNull String name,
@NonNull String content) throws Exception;
/** Parse input text as a Java/JML expression; the isJML parameter must
* be true if the expression contains JML constructs; it is false if the
* expression is a Java expression considered to be outside a JML
* annotation.
*/
public JCExpression parseExpression(CharSequence text,
boolean isJML);
/** Parse input text as a Java/JML statement; the isJML parameter must
* be true if the expression contains JML constructs; it is false if the
* expression is a Java expression considered to be outside a JML
* annotation.
*/
public JCStatement parseStatement(CharSequence text, boolean isJML);
/** Parses, creates symbol table symbols and typechecks the given set of files.
* This method may be called multiple times to add new classes to the symbol
* table entries. However if any file depends on another file B, file B is sought
* on the sourcepath or the specspath. Typically those paths are set to include
* the files that are listed in the arguments.
* @param files the set of files to parse and check (including referenced files)
* @throws java.io.IOException
*/
//@ requires isOpen;
//@ ensures isOpen;
public void parseAndCheck(File... files)
throws java.io.IOException;
/** Finds the source object, if any, corresponding to the specifications
* for the input Java AST, according to the JML language rules. The result
* may be the same input file that resulted in the given compilation unit,
* if the specs are in the java file itself and not in a .jml file.
* @param jmlcu a Java source AST (not a specification AST)
* @return the file object of the specifications
*/
public @Nullable
JavaFileObject findSpecs(JmlCompilationUnit jmlcu);
/** Attaches specifications to a Java source AST. The second argument may
* be identical to the first, in which case the JML annotations directly in
* Java source AST are used as the specifications for the Java class. If the
* second argument is different, annotations in the Java AST are ignored and
* those in the specified specsSource AST are used instead.
* @param javaSource the Java source
* @param specsSource the specifications AST to attach to the Java source.
*/ // TODO: instead of or in addition to any existing specs?
public void attachSpecs(JmlCompilationUnit javaSource, @Nullable JmlCompilationUnit specsSource);
/** Creates a JavaFileObject instance from a pseudo filename and given content
* @param name the name to give the 'file'
* @param content the content to give the file
* @return the resulting JavaFileObject
*/ // FIXME - comment on whether the package path is needed
public JavaFileObject makeJFOfromString(String name, String content) throws Exception;
/** Creates a JavaFileObject instance from a real file, by name
* @param filepath the path to the file, either absolute or relative to the current working directory
* @return the resulting JavaFileObject
*/
public JavaFileObject makeJFOfromFilename(String filepath);
/** Creates a JavaFileObject instance from a File object
* @param file the file to wrap
* @return the resulting JavaFileObject
*/
public JavaFileObject makeJFOfromFile(File file);
/** Retrieves the symbol table entry for a given package name, based on files already
* parsed and present in the symbol table.
* @param qualifiedName the dot separated package name
* @return the package symbol or null if it is not found
*/
//@ requires isOpen;
//@ ensures isOpen;
public @Nullable
PackageSymbol getPackageSymbol(@NonNull String qualifiedName);
/** Retrieves the symbol table entry for a given Class name, based on files already
* parsed and present in the symbol table; value is not usaable unless
* isTypechecked(qualifiedName) is true.
* @param qualifiedName the dot and dollar (for nested classes) separated
* class name
* @return the class symbol or null if it is not found
*/
//@ requires isOpen;
//@ ensures isOpen;
public @Nullable
ClassSymbol getClassSymbol(@NonNull String qualifiedName);
/** Retrieves the symbol table entry for a given class name as a member
* of the given class, based on files already
* parsed and present in the symbol table.
* @param csym the owning class
* @param name the (simple) name of the nested class
* @return the class symbol or null if it is not found
*/
public @Nullable
ClassSymbol getClassSymbol(@NonNull ClassSymbol csym,
@NonNull String name);
/** Retrieves the symbol table entry for a given method name as a member
* of the given class, based on files already
* parsed and present in the symbol table.
* @param csym the owning class
* @param name the (simple) name of the method
* @return the method symbol or null if it is not found
*/
//@ requires isOpen;
//@ ensures isOpen;
public @Nullable
MethodSymbol getMethodSymbol(@NonNull ClassSymbol csym,
@NonNull String name); // FIXME - need a way to handle multiple methods with the same name
/** Retrieves the symbol table entry for a given variable name as a member
* of the given class, based on files already
* parsed and present in the symbol table.
* @param csym the owning class
* @param name the (simple) name of the variable
* @return the variable symbol or null if it is not found
*/
public @Nullable
VarSymbol getVarSymbol(@NonNull ClassSymbol csym,
@NonNull String name);
/** Returns the symbol for a class declaration (if type checked)
* @param decl the type-checked ast node
* @return the corresponding symbol
*/
public @Nullable
ClassSymbol getSymbol(@NonNull JmlClassDecl decl);
/** Returns the symbol for a method declaration (if type checked)
* @param decl the type-checked ast node
* @return the corresponding symbol
*/
public @Nullable
MethodSymbol getSymbol(@NonNull JmlMethodDecl decl);
/** Returns the symbol for a variable declaration (if type checked)
* @param decl the type-checked ast node
* @return the corresponding symbol
*/
public @Nullable
VarSymbol getSymbol(@NonNull JmlVariableDecl decl);
/** Returns the AST for a given class (not compilation unit)
*
* @param qualifiedName the fully-qualified name of the class whose AST is wanted
* @return the AST for that class
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlClassDecl getClassDecl(@NonNull String qualifiedName);
/** Returns the declaration (the AST) corresponding to the given
* class, if there is one.
* @param csym the class symbol
* @return the corresponding AST, or null
*/
//@ requires isOpen;
//@ ensures isOpen;
public JmlClassDecl getClassDecl(ClassSymbol csym);
/** Returns the declaration (the AST) corresponding to the given
* method, if there is one.
* @param msym the method symbol
* @return the corresponding AST, or null
*/
//@ requires isOpen;
//@ ensures isOpen;
public @Nullable
JmlMethodDecl getMethodDecl(MethodSymbol msym);
/** Returns the declaration (the AST) corresponding to the given
* field, if there is one.
* @param vsym the field symbol
* @return the corresponding AST, or null
*/
//@ requires isOpen;
//@ ensures isOpen;
public @Nullable
JmlVariableDecl getVarDecl(VarSymbol vsym);
// TODO: document
public String getCEValue(int pos, int end, String text,
String fileLocation);
public API.Finder findMethod(JmlCompilationUnit tree, int pos, int end, String text,
String fileLocation);
// FIXME _ need a way to determine if a CU has been typechecked (successfully)
/** Executes static checking on the given method; assumes that all
* relevant ASTs have been typechecked (both the argument and any
* methods that it references by direct calls or in its specs)
* @param msym the method to check
* @return the result of the proof attempt
*/
//@ requires isOpen;
//@ ensures isOpen;
public IProverResult doESC(MethodSymbol msym);
/** Executes static checking on the methods of the given class; assumes that all
* relevant ASTs have been typechecked
* @param csym the class to check
*/
//@ requires isOpen;
//@ ensures isOpen;
public void doESC(ClassSymbol csym);
// /** The proof result of the most recent proof attempt for the given
// * method, or null if there has been none.
// * @param msym the method in question
// * @return the proof result
// */
// //@ requires isOpen;
// //@ ensures isOpen;
// public @Nullable
// IProverResult getProofResult(MethodSymbol msym);
//
// public @Nullable Map<MethodSymbol,IProverResult> getProofResults();
/** Returns the type specs for the given class symbol
*
* @param sym the class symbol whose specs are wanted
* @return the specs for that class
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
TypeSpecs getSpecs(@NonNull ClassSymbol sym);
/** Returns the type specs for the given class symbol,
* including all inherited specs
*
* @param sym the class symbol whose specs are wanted
* @return the specs for that class
*/
//@ requires isOpen;
//@ ensures isOpen;
public java.util.List<TypeSpecs> getAllSpecs(
@NonNull ClassSymbol sym);
/** Returns the specs for a given method
*
* @param sym the method symbol whose specs are wanted
* @return the specs for that method
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlSpecs.MethodSpecs getSpecs(@NonNull MethodSymbol sym);
/** Returns the specs for a given method, including specs of all overridden
* methods. Note that the names of parameters of various methods may be different,
* and hence the specs will need some renaming in order to be used together.
*
* @param msym the method symbol whose specs are wanted
* @return the list of specs for that method
*/
//@ requires isOpen;
//@ ensures isOpen;
public java.util.List<JmlSpecs.MethodSpecs> getAllSpecs(
@NonNull MethodSymbol msym);
// FIXME - should this be inherited specs; what about parameter name renaming?
/** Returns the specs for a given method in denested form
*
* @param sym the method symbol whose specs are wanted
* @return the specs for that method
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlMethodSpecs getDenestedSpecs(@NonNull MethodSymbol sym);
/** Returns the specs for a given field
*
* @param sym the field symbol whose specs are wanted
* @return the specs for that field
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
FieldSpecs getSpecs(@NonNull VarSymbol sym);
/** Returns a node factory for the current compilation context.
* @return a node factory
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
JmlTree.Maker nodeFactory();
/** Prints out a given parse tree (or subtree).
*
* @param ast the ast to print
* @return a string containing the output
* @throws Exception
*/
// FIXME - allow the option of showing composite specs?
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
String prettyPrint(@NonNull JCTree ast)
throws java.io.IOException;
// FIXME - clarify the difference between the above and below call, and what prettyPrint of lists does.
/** Prints out a given parse tree (or subtree), attempting to render
* the JML as compilable source.
*
* @param ast the ast to print
* @return a string containing the output
* @throws Exception
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
String prettyPrintJML(@NonNull JCTree ast)
throws java.io.IOException;
/** Prints out a list of parse trees, separated by the given separator String.
*
* @param astlist a list of asts to print
* @param sep a String that is written out as a separator
* @return a string containing the output
* @throws Exception
*/
//@ requires isOpen;
//@ ensures isOpen;
public @NonNull
String prettyPrint(
@NonNull java.util.List<? extends JCTree> astlist,
@NonNull String sep) throws java.io.IOException;
/** Closes this instance of the compiler, releasing internal memory;
* no further use of the instance is permitted (and will likely result in
* exceptions thrown).
*/
//@ requires isOpen;
//@ assignable isOpen;
//@ ensures !isOpen;
public void close();
}