/*
 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.jshell;

import java.util.Collection;
import java.util.List;

Provides analysis utilities for source code input. Optional functionality that provides for a richer interactive experience. Includes completion analysis: Is the input a complete snippet of code? Do I need to prompt for more input? Would adding a semicolon make it complete? Is there more than one snippet? etc. Also includes completion suggestions, as might be used in tab-completion.
Since:9
/** * Provides analysis utilities for source code input. * Optional functionality that provides for a richer interactive experience. * Includes completion analysis: * Is the input a complete snippet of code? * Do I need to prompt for more input? * Would adding a semicolon make it complete? * Is there more than one snippet? * etc. * Also includes completion suggestions, as might be used in tab-completion. * * @since 9 */
public abstract class SourceCodeAnalysis {
Given an input string, find the first snippet of code (one statement, definition, import, or expression) and evaluate if it is complete.
Params:
  • input – the input source string
Returns:a CompletionInfo instance with location and completeness info
/** * Given an input string, find the first snippet of code (one statement, * definition, import, or expression) and evaluate if it is complete. * @param input the input source string * @return a CompletionInfo instance with location and completeness info */
public abstract CompletionInfo analyzeCompletion(String input);
Compute possible follow-ups for the given input. Uses information from the current JShell state, including type information, to filter the suggestions.
Params:
  • input – the user input, so far
  • cursor – the current position of the cursors in the given input text
  • anchor – outgoing parameter - when an option will be completed, the text between the anchor and cursor will be deleted and replaced with the given option
Returns:list of candidate continuations of the given input.
/** * Compute possible follow-ups for the given input. * Uses information from the current {@code JShell} state, including * type information, to filter the suggestions. * @param input the user input, so far * @param cursor the current position of the cursors in the given {@code input} text * @param anchor outgoing parameter - when an option will be completed, the text between * the anchor and cursor will be deleted and replaced with the given option * @return list of candidate continuations of the given input. */
public abstract List<Suggestion> completionSuggestions(String input, int cursor, int[] anchor);
Compute documentation for the given user's input. Multiple Documentation objects may be returned when multiple elements match the user's input (like for overloaded methods).
Params:
  • input – the snippet the user wrote so far
  • cursor – the current position of the cursors in the given input text
  • computeJavadoc – true if the javadoc for the given input should be computed in addition to the signature
Returns:the documentations for the given user's input, if multiple elements match the input, multiple Documentation objects are returned.
/** * Compute documentation for the given user's input. Multiple {@code Documentation} objects may * be returned when multiple elements match the user's input (like for overloaded methods). * @param input the snippet the user wrote so far * @param cursor the current position of the cursors in the given {@code input} text * @param computeJavadoc true if the javadoc for the given input should be computed in * addition to the signature * @return the documentations for the given user's input, if multiple elements match the input, * multiple {@code Documentation} objects are returned. */
public abstract List<Documentation> documentation(String input, int cursor, boolean computeJavadoc);
Infer the type of the given expression. The expression spans from the beginning of code to the given cursor position. Returns null if the type of the expression cannot be inferred.
Params:
  • code – the expression for which the type should be inferred
  • cursor – current cursor position in the given code
Returns:the inferred type, or null if it cannot be inferred
/** * Infer the type of the given expression. The expression spans from the beginning of {@code code} * to the given {@code cursor} position. Returns null if the type of the expression cannot * be inferred. * * @param code the expression for which the type should be inferred * @param cursor current cursor position in the given code * @return the inferred type, or null if it cannot be inferred */
public abstract String analyzeType(String code, int cursor);
List qualified names known for the simple name in the given code immediately to the left of the given cursor position. The qualified names are gathered by inspecting the classpath used by eval (see JShell.addToClasspath(String)).
Params:
  • code – the expression for which the candidate qualified names should be computed
  • cursor – current cursor position in the given code
Returns:the known qualified names
/** * List qualified names known for the simple name in the given code immediately * to the left of the given cursor position. The qualified names are gathered by inspecting the * classpath used by eval (see {@link JShell#addToClasspath(java.lang.String)}). * * @param code the expression for which the candidate qualified names should be computed * @param cursor current cursor position in the given code * @return the known qualified names */
public abstract QualifiedNames listQualifiedNames(String code, int cursor);
Returns the wrapper information for the Snippet. The wrapper changes as the environment changes, so calls to this method at different times may yield different results.
Params:
  • snippet – the Snippet from which to retrieve the wrapper
Returns:information on the wrapper
/** * Returns the wrapper information for the {@code Snippet}. The wrapper changes as * the environment changes, so calls to this method at different times may * yield different results. * * @param snippet the {@code Snippet} from which to retrieve the wrapper * @return information on the wrapper */
public abstract SnippetWrapper wrapper(Snippet snippet);
Returns the wrapper information for the snippet within the input source string.

Wrapper information for malformed and incomplete snippets also generate wrappers. The list is in snippet encounter order. The wrapper changes as the environment changes, so calls to this method at different times may yield different results.

The input should be exactly one complete snippet of source code, that is, one expression, statement, variable declaration, method declaration, class declaration, or import. To break arbitrary input into individual complete snippets, use analyzeCompletion(String).

The wrapper may not match that returned by wrapper(Snippet), were the source converted to a Snippet.

Params:
  • input – the source input from which to generate wrappers
Returns:a list of wrapper information
/** * Returns the wrapper information for the snippet within the * input source string. * <p> * Wrapper information for malformed and incomplete * snippets also generate wrappers. The list is in snippet encounter * order. The wrapper changes as the environment changes, so calls to this * method at different times may yield different results. * <p> * The input should be * exactly one complete snippet of source code, that is, one expression, * statement, variable declaration, method declaration, class declaration, * or import. * To break arbitrary input into individual complete snippets, use * {@link SourceCodeAnalysis#analyzeCompletion(String)}. * <p> * The wrapper may not match that returned by * {@link SourceCodeAnalysis#wrapper(Snippet) wrapper(Snippet)}, * were the source converted to a {@code Snippet}. * * @param input the source input from which to generate wrappers * @return a list of wrapper information */
public abstract List<SnippetWrapper> wrappers(String input);
Converts the source code of a snippet into a Snippet object (or list of Snippet objects in the case of some var declarations, e.g.: int x, y, z;). Does not install the snippets: declarations are not accessible by other snippets; imports are not added. Does not execute the snippets.

Queries may be done on the Snippet object. The Snippet.id() will be "*UNASSOCIATED*". The returned snippets are not associated with the JShell instance, so attempts to pass them to JShell methods will throw an IllegalArgumentException. They will not appear in queries for snippets -- for example, JShell.snippets().

Restrictions on the input are as in JShell.eval.

Only preliminary compilation is performed, sufficient to build the Snippet. Snippets known to be erroneous, are returned as ErroneousSnippet, other snippets may or may not be in error.

Params:
  • input – The input String to convert
Throws:
Returns:usually a singleton list of Snippet, but may be empty or multiple
/** * Converts the source code of a snippet into a {@link Snippet} object (or * list of {@code Snippet} objects in the case of some var declarations, * e.g.: int x, y, z;). * Does not install the snippets: declarations are not * accessible by other snippets; imports are not added. * Does not execute the snippets. * <p> * Queries may be done on the {@code Snippet} object. The {@link Snippet#id()} * will be {@code "*UNASSOCIATED*"}. * The returned snippets are not associated with the * {@link JShell} instance, so attempts to pass them to {@code JShell} * methods will throw an {@code IllegalArgumentException}. * They will not appear in queries for snippets -- * for example, {@link JShell#snippets() }. * <p> * Restrictions on the input are as in {@link JShell#eval}. * <p> * Only preliminary compilation is performed, sufficient to build the * {@code Snippet}. Snippets known to be erroneous, are returned as * {@link ErroneousSnippet}, other snippets may or may not be in error. * * @param input The input String to convert * @return usually a singleton list of Snippet, but may be empty or multiple * @throws IllegalStateException if the {@code JShell} instance is closed. */
public abstract List<Snippet> sourceToSnippets(String input);
Returns a collection of Snippets which might need updating if the given Snippet is updated. The returned collection is designed to be inclusive and may include many false positives.
Params:
  • snippet – the Snippet whose dependents are requested
Returns:the collection of dependents
/** * Returns a collection of {@code Snippet}s which might need updating if the * given {@code Snippet} is updated. The returned collection is designed to * be inclusive and may include many false positives. * * @param snippet the {@code Snippet} whose dependents are requested * @return the collection of dependents */
public abstract Collection<Snippet> dependents(Snippet snippet);
Internal only constructor
/** * Internal only constructor */
SourceCodeAnalysis() {}
The result of analyzeCompletion(String input). Describes the completeness of the first snippet in the given input.
/** * The result of {@code analyzeCompletion(String input)}. * Describes the completeness of the first snippet in the given input. */
public interface CompletionInfo {
The analyzed completeness of the input.
Returns:an enum describing the completeness of the input string.
/** * The analyzed completeness of the input. * * @return an enum describing the completeness of the input string. */
Completeness completeness();
Input remaining after the complete part of the source.
Returns:the portion of the input string that remains after the complete Snippet
/** * Input remaining after the complete part of the source. * * @return the portion of the input string that remains after the * complete Snippet */
String remaining();
Source code for the first Snippet of code input. For example, first statement, or first method declaration. Trailing semicolons will be added, as needed.
Returns:the source of the first encountered Snippet
/** * Source code for the first Snippet of code input. For example, first * statement, or first method declaration. Trailing semicolons will be * added, as needed. * * @return the source of the first encountered Snippet */
String source(); }
Describes the completeness of the given input.
/** * Describes the completeness of the given input. */
public enum Completeness {
The input is a complete source snippet (declaration or statement) as is.
/** * The input is a complete source snippet (declaration or statement) as is. */
COMPLETE(true),
With this addition of a semicolon the input is a complete source snippet. This will only be returned when the end of input is encountered.
/** * With this addition of a semicolon the input is a complete source snippet. * This will only be returned when the end of input is encountered. */
COMPLETE_WITH_SEMI(true),
There must be further source beyond the given input in order for it to be complete. A semicolon would not complete it. This will only be returned when the end of input is encountered.
/** * There must be further source beyond the given input in order for it * to be complete. A semicolon would not complete it. * This will only be returned when the end of input is encountered. */
DEFINITELY_INCOMPLETE(false),
A statement with a trailing (non-terminated) empty statement. Though technically it would be a complete statement with the addition of a semicolon, it is rare that that assumption is the desired behavior. The input is considered incomplete. Comments and white-space are still considered empty.
/** * A statement with a trailing (non-terminated) empty statement. * Though technically it would be a complete statement * with the addition of a semicolon, it is rare * that that assumption is the desired behavior. * The input is considered incomplete. Comments and white-space are * still considered empty. */
CONSIDERED_INCOMPLETE(false),
An empty input. The input is considered incomplete. Comments and white-space are still considered empty.
/** * An empty input. * The input is considered incomplete. Comments and white-space are * still considered empty. */
EMPTY(false),
The completeness of the input could not be determined because it contains errors. Error detection is not a goal of completeness analysis, however errors interfered with determining its completeness. The input is considered complete because evaluating is the best mechanism to get error information.
/** * The completeness of the input could not be determined because it * contains errors. Error detection is not a goal of completeness * analysis, however errors interfered with determining its completeness. * The input is considered complete because evaluating is the best * mechanism to get error information. */
UNKNOWN(true); private final boolean isComplete; Completeness(boolean isComplete) { this.isComplete = isComplete; }
Indicates whether the first snippet of source is complete. For example, "x=" is not complete, but "x=2" is complete, even though a subsequent line could make it "x=2+2". Already erroneous code is marked complete.
Returns:true if the input is or begins a complete Snippet; otherwise false
/** * Indicates whether the first snippet of source is complete. * For example, "{@code x=}" is not * complete, but "{@code x=2}" is complete, even though a subsequent line could * make it "{@code x=2+2}". Already erroneous code is marked complete. * * @return {@code true} if the input is or begins a complete Snippet; * otherwise {@code false} */
public boolean isComplete() { return isComplete; } }
A candidate for continuation of the given user's input.
/** * A candidate for continuation of the given user's input. */
public interface Suggestion {
The candidate continuation of the given user's input.
Returns:the continuation string
/** * The candidate continuation of the given user's input. * * @return the continuation string */
String continuation();
Indicates whether input continuation matches the target type and is thus more likely to be the desired continuation. A matching continuation is preferred.
Returns:true if this suggested continuation matches the target type; otherwise false
/** * Indicates whether input continuation matches the target type and is thus * more likely to be the desired continuation. A matching continuation is * preferred. * * @return {@code true} if this suggested continuation matches the * target type; otherwise {@code false} */
boolean matchesType(); }
A documentation for a candidate for continuation of the given user's input.
/** * A documentation for a candidate for continuation of the given user's input. */
public interface Documentation {
The signature of the given element.
Returns:the signature
/** * The signature of the given element. * * @return the signature */
String signature();
The javadoc of the given element.
Returns:the javadoc, or null if not found or not requested
/** * The javadoc of the given element. * * @return the javadoc, or null if not found or not requested */
String javadoc(); }
List of possible qualified names.
/** * List of possible qualified names. */
public static final class QualifiedNames { private final List<String> names; private final int simpleNameLength; private final boolean upToDate; private final boolean resolvable; QualifiedNames(List<String> names, int simpleNameLength, boolean upToDate, boolean resolvable) { this.names = names; this.simpleNameLength = simpleNameLength; this.upToDate = upToDate; this.resolvable = resolvable; }
Known qualified names for the given simple name in the original code.
Returns:known qualified names
/** * Known qualified names for the given simple name in the original code. * * @return known qualified names */
public List<String> getNames() { return names; }
The length of the simple name in the original code for which the qualified names where gathered.
Returns:the length of the simple name; -1 if there is no name immediately left to the cursor for which the candidates could be computed
/** * The length of the simple name in the original code for which the * qualified names where gathered. * * @return the length of the simple name; -1 if there is no name immediately left to the cursor for * which the candidates could be computed */
public int getSimpleNameLength() { return simpleNameLength; }
Indicates whether the result is based on up-to-date data. The listQualifiedNames method may return before the classpath is fully inspected, in which case this method will return false. If the result is based on a fully inspected classpath, this method will return true.
Returns:true if the result is based on up-to-date data; otherwise false
/** * Indicates whether the result is based on up-to-date data. The * {@link SourceCodeAnalysis#listQualifiedNames(java.lang.String, int) listQualifiedNames} * method may return before the classpath is fully inspected, in which case this method will * return {@code false}. If the result is based on a fully inspected classpath, this method * will return {@code true}. * * @return {@code true} if the result is based on up-to-date data; * otherwise {@code false} */
public boolean isUpToDate() { return upToDate; }
Indicates whether the given simple name in the original code refers to a resolvable element.
Returns:true if the given simple name in the original code refers to a resolvable element; otherwise false
/** * Indicates whether the given simple name in the original code refers * to a resolvable element. * * @return {@code true} if the given simple name in the original code * refers to a resolvable element; otherwise {@code false} */
public boolean isResolvable() { return resolvable; } }
The wrapping of a snippet of Java source into valid top-level Java source. The wrapping will always either be an import or include a synthetic class at the top-level. If a synthetic class is generated, it will be proceeded by the package and import declarations, and may contain synthetic class members.

This interface, in addition to the mapped form, provides the context and position mapping information.

/** * The wrapping of a snippet of Java source into valid top-level Java * source. The wrapping will always either be an import or include a * synthetic class at the top-level. If a synthetic class is generated, it * will be proceeded by the package and import declarations, and may contain * synthetic class members. * <p> * This interface, in addition to the mapped form, provides the context and * position mapping information. */
public interface SnippetWrapper {
Returns the input that is wrapped. For wrappers(String), this is the source of the snippet within the input. A variable declaration of N variables will map to N wrappers with the source separated.

For wrapper(Snippet), this is Snippet.source().

Returns:the input source corresponding to the wrapper.
/** * Returns the input that is wrapped. For * {@link SourceCodeAnalysis#wrappers(java.lang.String) wrappers(String)}, * this is the source of the snippet within the input. A variable * declaration of {@code N} variables will map to {@code N} wrappers * with the source separated. * <p> * For {@link SourceCodeAnalysis#wrapper(Snippet) wrapper(Snippet)}, * this is {@link Snippet#source() }. * * @return the input source corresponding to the wrapper. */
String source();
Returns a Java class definition that wraps the source() or, if an import, the import source.

If the input is not a valid Snippet, this will not be a valid class/import definition.

The source may be divided and mapped to different locations within the wrapped source.

Returns:the source wrapped into top-level Java code
/** * Returns a Java class definition that wraps the * {@link SnippetWrapper#source()} or, if an import, the import source. * <p> * If the input is not a valid Snippet, this will not be a valid * class/import definition. * <p> * The source may be divided and mapped to different locations within * the wrapped source. * * @return the source wrapped into top-level Java code */
String wrapped();
Returns the fully qualified class name of the wrapped() class. For erroneous input, a best guess is returned.
Returns:the name of the synthetic wrapped class; if an import, the name is not defined
/** * Returns the fully qualified class name of the * {@link SnippetWrapper#wrapped() } class. * For erroneous input, a best guess is returned. * * @return the name of the synthetic wrapped class; if an import, the * name is not defined */
String fullClassName();
Returns the Kind of the source().
Returns:an enum representing the general kind of snippet.
/** * Returns the {@link Snippet.Kind} of the * {@link SnippetWrapper#source()}. * * @return an enum representing the general kind of snippet. */
Snippet.Kind kind();
Maps character position within the source to character position within the wrapped.
Params:
Returns:the corresponding position in wrapped()
/** * Maps character position within the source to character position * within the wrapped. * * @param pos the position in {@link SnippetWrapper#source()} * @return the corresponding position in * {@link SnippetWrapper#wrapped() } */
int sourceToWrappedPosition(int pos);
Maps character position within the wrapped to character position within the source.
Params:
Returns:the corresponding position in source()
/** * Maps character position within the wrapped to character position * within the source. * * @param pos the position in {@link SnippetWrapper#wrapped()} * @return the corresponding position in * {@link SnippetWrapper#source() } */
int wrappedToSourcePosition(int pos); } }