/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java
675 строк
25 KB
Jan Lahoda
8186876: JShell: access javadoc for user/library classes
20 июл 2026, 16:02
20 июл 2026, 16:02
99255c4
Код
Авторство
О чём код?
/* * Copyright (c) 2014, 2025, 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; import java.util.Set; import java.util.function.Supplier; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; /** * 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. * @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 {@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 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 convertor convert the given {@linkplain ElementSuggestion} to a custom completion suggestions. * @return list of candidate continuations of the given input. * @since 26 */ public abstract <S> List<S> completionSuggestions(String input, int cursor, ElementSuggestionConvertor<S> convertor); /** * 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 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 {@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 {@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. * <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 {@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}, unless otherwise * noted. * They will not appear in queries for snippets -- * for example, {@link JShell#snippets() }. * <p> * Restrictions on the input are as in {@link JShell#eval(String)}. * <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. * * @since 10 */ public abstract List<Snippet> sourceToSnippets(String input); /** * 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); /** * Returns a collection of {@code Highlight}s which can be used to color * the given snippet. * <p> * The returned {@code Highlight}s do not overlap, and are sorted by their * start position. * * @param snippet the snippet for which the {@code Highlight}s should be computed * @return the computed {@code Highlight}s. * @since 19 */ public abstract List<Highlight> highlights(String snippet); /** * Internal only constructor */ SourceCodeAnalysis() {} /** * 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. * * @return an enum describing the completeness of the input string. */ Completeness completeness(); /** * 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. * * @return the source of the first encountered Snippet */ String source(); } /** * Describes the completeness of the given input. */ public enum Completeness { /** * 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. */ 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. */ 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. */ CONSIDERED_INCOMPLETE(false), /** * Snippet is likely a prefix of a real snippet. Typically, the snippet * is a documentation comment, after which it is expected that a declaration * will follow. * * @since 28 */ PREFIX(false), /** * 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. */ UNKNOWN(true); private final boolean isComplete; Completeness(boolean isComplete) { this.isComplete = isComplete; } /** * 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. */ public interface Suggestion { /** * 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. * * @return {@code true} if this suggested continuation matches the * target type; otherwise {@code false} */ boolean matchesType(); } /** * A description of an {@linkplain Element} that is a possible continuation of * a given snippet. * * @apiNote Instances of this interface and instances of the returned {@linkplain Elements} * should only be used and held during the execution of the * {@link #completionSuggestions(java.lang.String, int, jdk.jshell.SourceCodeAnalysis.ElementSuggestionConvertor) } * method. Their use outside of the context of the method is not supported and * the effect is undefined. * * @since 26 */ public sealed interface ElementSuggestion permits SourceCodeAnalysisImpl.ElementSuggestionImpl { /** * {@return a possible continuation {@linkplain Element}, or {@code null} * if this item does not represent an {@linkplain Element}.} */ Element element(); /** * {@return a possible continuation keyword, or {@code null} * if this item does not represent a keyword.} */ String keyword(); /** * {@return {@code true} if this {@linkplain Element}'s type fits into * the context.} * * Typically used when the type of the element fits the expected type. */ boolean matchesType(); /** * {@return the offset in the original snippet at which point this {@linkplain Element} * should be inserted.} */ int anchor(); /** * {@return a {@linkplain Supplier} for the javadoc documentation for this Element.} * * @apiNote The instance returned from this method is safe to hold for extended * periods of time, and can be called outside of the context of the * {@link #completionSuggestions(java.lang.String, int, jdk.jshell.SourceCodeAnalysis.ElementSuggestionConvertor) } method. */ Supplier<String> documentation(); } /** * Permit access to completion state. * * @since 26 */ public sealed interface CompletionState permits SourceCodeAnalysisImpl.CompletionStateImpl { /** * {@return true if the given element is available using the simple name at * the place of the cursor.} * * @param el {@linkplain Element} to check */ public boolean availableUsingSimpleName(Element el); /** * {@return flags describing the overall completion context.} */ public Set<CompletionContext> completionContext(); /** * {@return if the context is a qualified expression * (i.e. {@link CompletionContext#QUALIFIED} is set), * the type of the selector expression; {@code null} otherwise.} */ public TypeMirror selectorType(); /** * {@return an implementation of some utility methods for * operating on elements} */ Elements elementUtils(); /** * {@return an implementation of some utility methods for * operating on types} */ Types typeUtils(); } /** * Various flags describing the context in which the completion happens. * * @since 26 */ public enum CompletionContext { /** * The context is inside annotation attributes. */ ANNOTATION_ATTRIBUTE, /** * Parentheses should not be filled for methods and constructor * in the current context. * * Typically used in the import or method reference contexts. */ NO_PAREN, /** * Interpret {@link ElementKind#ANNOTATION_TYPE}s as annotation uses. Typically means * they should be prefixed with {@code @}. */ TYPES_AS_ANNOTATIONS, /** * The context is in a qualified expression (like member access). Simple * names only should be used. */ QUALIFIED, ; } /** * A convertor from a list of {@linkplain ElementSuggestion} to a list * of custom target completion items. * * @param <S> a custom target completion type. * @since 26 */ public interface ElementSuggestionConvertor<S> { /** * Convert a list of {@linkplain ElementSuggestion} to a list * of custom completion items. * * @param state the state of the completion * @param suggestions the input suggestions * @return the converted suggestions */ public List<S> convert(CompletionState state, List<? extends ElementSuggestion> suggestions); } /** * A documentation for a candidate for continuation of the given user's input. */ public interface Documentation { /** * The signature of the given element. * * @return the signature */ String signature(); /** * The javadoc of the given element. * * @return the javadoc, or null if not found or not requested */ String javadoc(); /** * If this {@code Documentation} is created for a method invocation, * return the current parameter index. * * @implNote the default implementation returns {@code -1} * @return the active parameter index, or {@code -1} if not available * @since 26 */ default int activeParameterIndex() { return -1; } } /** * 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. * * @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. * * @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 * {@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. * * @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. * <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 * {@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 * {@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 * {@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 {@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. * * @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. * * @param pos the position in {@link SnippetWrapper#wrapped()} * @return the corresponding position in * {@link SnippetWrapper#source() } */ int wrappedToSourcePosition(int pos); } /**Assigns attributes usable for coloring to spans inside a snippet. * * @param start the starting position of the span * @param end the ending position of the span * @param attributes the attributes assigned to the span * @since 19 */ public record Highlight(int start, int end, Set<Attribute> attributes) {} /** * A span attribute which can be used to derive a coloring. * @since 19 */ public enum Attribute { /** * The span refers to a declaration of an element. */ DECLARATION, /** * The span refers to a deprecated element. */ DEPRECATED, /** * The span is a keyword. */ KEYWORD; } }