diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html index 453a5203754..98a977c59d7 100644 --- a/pkg/analysis_server/doc/api.html +++ b/pkg/analysis_server/doc/api.html @@ -276,6 +276,7 @@ a:focus, a:hover {

Execution

@@ -2263,6 +2264,7 @@ a:focus, a:hover { +

Requests

execution.createContext
request: {
   "id": String
   "method": "execution.createContext"
@@ -2317,6 +2319,110 @@ a:focus, a:hover {
         

The identifier of the execution context that is to be deleted.

+
execution.getSuggestions
request: {
+  "id": String
+  "method": "execution.getSuggestions"
+  "params": {
+    "code": String
+    "offset": int
+    "contextFile": FilePath
+    "contextOffset": int
+    "variables": List<RuntimeCompletionVariable>
+    "expressions": optional List<RuntimeCompletionExpression>
+  }
+}

response: {
+  "id": String
+  "error": optional RequestError
+  "result": {
+    "suggestions": optional List<CompletionSuggestion>
+    "expressions": optional List<RuntimeCompletionExpression>
+  }
+}
+

+ Request completion suggestions for the given runtime context. +

+

+ It might take one or two requests of this type to get completion + suggestions. The first request should have only "code", "offset", + and "variables", but not "expressions". If there are sub-expressions that + can have different runtime types, and are considered to be safe to + evaluate at runtime (e.g. getters), so using their actual runtime types + can improve completion results, the server will not include the + "suggestions" field in the response, and instead will return the + "expressions" field. The client will use debug API to get current runtime + types for these sub-expressions and send another request, this time with + "expressions". If there are no interesting sub-expressions to get + runtime types for, or when the "expressions" field is provided by the + client, the server will return "suggestions" in the response. +

+ + +

parameters:

code: String
+ +

+ The code to get suggestions in. +

+
offset: int
+ +

+ The offset within the code to get suggestions at. +

+
contextFile: FilePath
+ +

+ The path of the context file, e.g. the file of the current debugger + frame. The combination of the context file and context offset can + be used to ensure that all variables of the context are available + for completion (with their static types). +

+
contextOffset: int
+ +

+ The offset in the context file, e.g. the line offset in the current + debugger frame. +

+
variables: List<RuntimeCompletionVariable>
+ +

+ The runtime context variables that are potentially referenced in the + code. +

+
expressions: List<RuntimeCompletionExpression> (optional)
+ +

+ The list of sub-expressions in the code for which the client wants + to provide runtime types. It does not have to be the full list of + expressions requested by the server, for missing expressions their + static types will be used. +

+

+ When this field is omitted, the server will return completion + suggestions only when there are no interesting sub-expressions in the + given code. The client may provide an empty list, in this case the + server will return completion suggestions. +

+

returns:

suggestions: List<CompletionSuggestion> (optional)
+ +

+ The completion suggestions. In contrast to usual completion request, + suggestions for private elements also will be provided. +

+

+ If there are sub-expressions that can have different runtime types, + and are considered to be safe to evaluate at runtime (e.g. getters), + so using their actual runtime types can improve completion results, + the server omits this field in the response, and instead will return + the "expressions" field. +

+
expressions: List<RuntimeCompletionExpression> (optional)
+ +

+ The list of sub-expressions in the code for which the server would + like to know runtime types to provide better completion suggestions. +

+

+ This field is omitted the field "suggestions" is returned. +

execution.mapUri
request: {
   "id": String
   "method": "execution.mapUri"
@@ -2538,6 +2644,10 @@ a:focus, a:hover {
   
   
   
+  
+  
+  
+  
   
   
   
@@ -4250,6 +4360,103 @@ a:focus, a:hover {
           API reaches version 1.0.
         

+
RuntimeCompletionExpression: object
+

+ An expression for which we want to know its runtime type. + In expressions like `a.b.c.where((e) => e.^)` we want to know the + runtime type of `a.b.c` to enforce it statically at the time when we + compute completion suggestions, and get better type for `e`. +

+ +
offset: int
+ +

+ The offset of the expression in the code for completion. +

+
length: int
+ +

+ The length of the expression in the code for completion. +

+
type: RuntimeCompletionExpressionType (optional)
+ +

+ When the expression is sent from the server to the client, the + type is omitted. The client should fill the type when it sends the + request to the server again. +

+
RuntimeCompletionExpressionType: object
+

+ A type at runtime. +

+ +
libraryPath: FilePath (optional)
+ +

+ The path of the library that has this type. + Omitted if the type is not declared in any library, e.g. "dynamic", + or "void". +

+
kind: RuntimeCompletionExpressionTypeKind
+ +

+ The kind of the type. +

+
name: String (optional)
+ +

+ The name of the type. Omitted if the type does not have a name, e.g. + an inline function type. +

+
typeArguments: List<RuntimeCompletionExpressionType> (optional)
+ +

+ The type arguments of the type. + Omitted if the type does not have type parameters. +

+
returnType: RuntimeCompletionExpressionType (optional)
+ +

+ If the type is a function type, the return type of the function. + Omitted if the type is not a function type. +

+
parameterTypes: List<RuntimeCompletionExpressionType> (optional)
+ +

+ If the type is a function type, the types of the function parameters + of all kinds - required, optional positional, and optional named. + Omitted if the type is not a function type. +

+
parameterNames: List<String> (optional)
+ +

+ If the type is a function type, the names of the function parameters + of all kinds - required, optional positional, and optional named. + The names of positional parameters are empty strings. + Omitted if the type is not a function type. +

+
RuntimeCompletionExpressionTypeKind: String
+

+ An enumeration of the kinds of runtime expression types. +

+ +
DYNAMIC
FUNCTION
INTERFACE
RuntimeCompletionVariable: object
+

+ A variable in a runtime context. +

+ +
name: String
+ +

+ The name of the variable. + The name "this" has a special meaning and is used as an implicit + target for runtime completion, and in explicit "this" references. +

+
type: RuntimeCompletionExpressionType
+ +

+ The type of the variable. +

SearchId: String

@@ -4832,7 +5039,7 @@ a:focus, a:hover { TODO: TBD

Index

-

Domains

server ()

Requests
Notifications

analysis ()

Requests
Notifications

completion ()

Requests
Notifications

search ()

Requests
Notifications

edit ()

Requests

execution ()

Requests
Notifications

diagnostic ()

Requests

Types ()

Refactorings ()

+

Domains

server ()

Requests
Notifications

analysis ()

Requests
Notifications

completion ()

Requests
Notifications

search ()

Requests
Notifications

edit ()

Requests

execution ()

Requests
Notifications

diagnostic ()

Requests

Types ()

Refactorings ()

\ No newline at end of file diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart index 148fc494d14..fcd43003aed 100644 --- a/pkg/analysis_server/lib/protocol/protocol_constants.dart +++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart @@ -196,6 +196,13 @@ const String EXECUTION_REQUEST_CREATE_CONTEXT = 'execution.createContext'; const String EXECUTION_REQUEST_CREATE_CONTEXT_CONTEXT_ROOT = 'contextRoot'; const String EXECUTION_REQUEST_DELETE_CONTEXT = 'execution.deleteContext'; const String EXECUTION_REQUEST_DELETE_CONTEXT_ID = 'id'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS = 'execution.getSuggestions'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS_CODE = 'code'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS_CONTEXT_FILE = 'contextFile'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS_CONTEXT_OFFSET = 'contextOffset'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS_EXPRESSIONS = 'expressions'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS_OFFSET = 'offset'; +const String EXECUTION_REQUEST_GET_SUGGESTIONS_VARIABLES = 'variables'; const String EXECUTION_REQUEST_MAP_URI = 'execution.mapUri'; const String EXECUTION_REQUEST_MAP_URI_FILE = 'file'; const String EXECUTION_REQUEST_MAP_URI_ID = 'id'; @@ -204,6 +211,8 @@ const String EXECUTION_REQUEST_SET_SUBSCRIPTIONS = 'execution.setSubscriptions'; const String EXECUTION_REQUEST_SET_SUBSCRIPTIONS_SUBSCRIPTIONS = 'subscriptions'; const String EXECUTION_RESPONSE_CREATE_CONTEXT_ID = 'id'; +const String EXECUTION_RESPONSE_GET_SUGGESTIONS_EXPRESSIONS = 'expressions'; +const String EXECUTION_RESPONSE_GET_SUGGESTIONS_SUGGESTIONS = 'suggestions'; const String EXECUTION_RESPONSE_MAP_URI_FILE = 'file'; const String EXECUTION_RESPONSE_MAP_URI_URI = 'uri'; const String FLUTTER_NOTIFICATION_OUTLINE = 'flutter.outline'; diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart index cd60f28dab4..7175c14044c 100644 --- a/pkg/analysis_server/lib/protocol/protocol_generated.dart +++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart @@ -9503,6 +9503,422 @@ class ExecutionDeleteContextResult implements ResponseResult { } } +/** + * execution.getSuggestions params + * + * { + * "code": String + * "offset": int + * "contextFile": FilePath + * "contextOffset": int + * "variables": List + * "expressions": optional List + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class ExecutionGetSuggestionsParams implements RequestParams { + String _code; + + int _offset; + + String _contextFile; + + int _contextOffset; + + List _variables; + + List _expressions; + + /** + * The code to get suggestions in. + */ + String get code => _code; + + /** + * The code to get suggestions in. + */ + void set code(String value) { + assert(value != null); + this._code = value; + } + + /** + * The offset within the code to get suggestions at. + */ + int get offset => _offset; + + /** + * The offset within the code to get suggestions at. + */ + void set offset(int value) { + assert(value != null); + this._offset = value; + } + + /** + * The path of the context file, e.g. the file of the current debugger frame. + * The combination of the context file and context offset can be used to + * ensure that all variables of the context are available for completion + * (with their static types). + */ + String get contextFile => _contextFile; + + /** + * The path of the context file, e.g. the file of the current debugger frame. + * The combination of the context file and context offset can be used to + * ensure that all variables of the context are available for completion + * (with their static types). + */ + void set contextFile(String value) { + assert(value != null); + this._contextFile = value; + } + + /** + * The offset in the context file, e.g. the line offset in the current + * debugger frame. + */ + int get contextOffset => _contextOffset; + + /** + * The offset in the context file, e.g. the line offset in the current + * debugger frame. + */ + void set contextOffset(int value) { + assert(value != null); + this._contextOffset = value; + } + + /** + * The runtime context variables that are potentially referenced in the code. + */ + List get variables => _variables; + + /** + * The runtime context variables that are potentially referenced in the code. + */ + void set variables(List value) { + assert(value != null); + this._variables = value; + } + + /** + * The list of sub-expressions in the code for which the client wants to + * provide runtime types. It does not have to be the full list of expressions + * requested by the server, for missing expressions their static types will + * be used. + * + * When this field is omitted, the server will return completion suggestions + * only when there are no interesting sub-expressions in the given code. The + * client may provide an empty list, in this case the server will return + * completion suggestions. + */ + List get expressions => _expressions; + + /** + * The list of sub-expressions in the code for which the client wants to + * provide runtime types. It does not have to be the full list of expressions + * requested by the server, for missing expressions their static types will + * be used. + * + * When this field is omitted, the server will return completion suggestions + * only when there are no interesting sub-expressions in the given code. The + * client may provide an empty list, in this case the server will return + * completion suggestions. + */ + void set expressions(List value) { + this._expressions = value; + } + + ExecutionGetSuggestionsParams(String code, int offset, String contextFile, + int contextOffset, List variables, + {List expressions}) { + this.code = code; + this.offset = offset; + this.contextFile = contextFile; + this.contextOffset = contextOffset; + this.variables = variables; + this.expressions = expressions; + } + + factory ExecutionGetSuggestionsParams.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + String code; + if (json.containsKey("code")) { + code = jsonDecoder.decodeString(jsonPath + ".code", json["code"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "code"); + } + int offset; + if (json.containsKey("offset")) { + offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "offset"); + } + String contextFile; + if (json.containsKey("contextFile")) { + contextFile = jsonDecoder.decodeString( + jsonPath + ".contextFile", json["contextFile"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "contextFile"); + } + int contextOffset; + if (json.containsKey("contextOffset")) { + contextOffset = jsonDecoder.decodeInt( + jsonPath + ".contextOffset", json["contextOffset"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "contextOffset"); + } + List variables; + if (json.containsKey("variables")) { + variables = jsonDecoder.decodeList( + jsonPath + ".variables", + json["variables"], + (String jsonPath, Object json) => + new RuntimeCompletionVariable.fromJson( + jsonDecoder, jsonPath, json)); + } else { + throw jsonDecoder.mismatch(jsonPath, "variables"); + } + List expressions; + if (json.containsKey("expressions")) { + expressions = jsonDecoder.decodeList( + jsonPath + ".expressions", + json["expressions"], + (String jsonPath, Object json) => + new RuntimeCompletionExpression.fromJson( + jsonDecoder, jsonPath, json)); + } + return new ExecutionGetSuggestionsParams( + code, offset, contextFile, contextOffset, variables, + expressions: expressions); + } else { + throw jsonDecoder.mismatch( + jsonPath, "execution.getSuggestions params", json); + } + } + + factory ExecutionGetSuggestionsParams.fromRequest(Request request) { + return new ExecutionGetSuggestionsParams.fromJson( + new RequestDecoder(request), "params", request.params); + } + + @override + Map toJson() { + Map result = {}; + result["code"] = code; + result["offset"] = offset; + result["contextFile"] = contextFile; + result["contextOffset"] = contextOffset; + result["variables"] = variables + .map((RuntimeCompletionVariable value) => value.toJson()) + .toList(); + if (expressions != null) { + result["expressions"] = expressions + .map((RuntimeCompletionExpression value) => value.toJson()) + .toList(); + } + return result; + } + + @override + Request toRequest(String id) { + return new Request(id, "execution.getSuggestions", toJson()); + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is ExecutionGetSuggestionsParams) { + return code == other.code && + offset == other.offset && + contextFile == other.contextFile && + contextOffset == other.contextOffset && + listEqual( + variables, + other.variables, + (RuntimeCompletionVariable a, RuntimeCompletionVariable b) => + a == b) && + listEqual( + expressions, + other.expressions, + (RuntimeCompletionExpression a, RuntimeCompletionExpression b) => + a == b); + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, code.hashCode); + hash = JenkinsSmiHash.combine(hash, offset.hashCode); + hash = JenkinsSmiHash.combine(hash, contextFile.hashCode); + hash = JenkinsSmiHash.combine(hash, contextOffset.hashCode); + hash = JenkinsSmiHash.combine(hash, variables.hashCode); + hash = JenkinsSmiHash.combine(hash, expressions.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + +/** + * execution.getSuggestions result + * + * { + * "suggestions": optional List + * "expressions": optional List + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class ExecutionGetSuggestionsResult implements ResponseResult { + List _suggestions; + + List _expressions; + + /** + * The completion suggestions. In contrast to usual completion request, + * suggestions for private elements also will be provided. + * + * If there are sub-expressions that can have different runtime types, and + * are considered to be safe to evaluate at runtime (e.g. getters), so using + * their actual runtime types can improve completion results, the server + * omits this field in the response, and instead will return the + * "expressions" field. + */ + List get suggestions => _suggestions; + + /** + * The completion suggestions. In contrast to usual completion request, + * suggestions for private elements also will be provided. + * + * If there are sub-expressions that can have different runtime types, and + * are considered to be safe to evaluate at runtime (e.g. getters), so using + * their actual runtime types can improve completion results, the server + * omits this field in the response, and instead will return the + * "expressions" field. + */ + void set suggestions(List value) { + this._suggestions = value; + } + + /** + * The list of sub-expressions in the code for which the server would like to + * know runtime types to provide better completion suggestions. + * + * This field is omitted the field "suggestions" is returned. + */ + List get expressions => _expressions; + + /** + * The list of sub-expressions in the code for which the server would like to + * know runtime types to provide better completion suggestions. + * + * This field is omitted the field "suggestions" is returned. + */ + void set expressions(List value) { + this._expressions = value; + } + + ExecutionGetSuggestionsResult( + {List suggestions, + List expressions}) { + this.suggestions = suggestions; + this.expressions = expressions; + } + + factory ExecutionGetSuggestionsResult.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + List suggestions; + if (json.containsKey("suggestions")) { + suggestions = jsonDecoder.decodeList( + jsonPath + ".suggestions", + json["suggestions"], + (String jsonPath, Object json) => + new CompletionSuggestion.fromJson(jsonDecoder, jsonPath, json)); + } + List expressions; + if (json.containsKey("expressions")) { + expressions = jsonDecoder.decodeList( + jsonPath + ".expressions", + json["expressions"], + (String jsonPath, Object json) => + new RuntimeCompletionExpression.fromJson( + jsonDecoder, jsonPath, json)); + } + return new ExecutionGetSuggestionsResult( + suggestions: suggestions, expressions: expressions); + } else { + throw jsonDecoder.mismatch( + jsonPath, "execution.getSuggestions result", json); + } + } + + factory ExecutionGetSuggestionsResult.fromResponse(Response response) { + return new ExecutionGetSuggestionsResult.fromJson( + new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), + "result", + response.result); + } + + @override + Map toJson() { + Map result = {}; + if (suggestions != null) { + result["suggestions"] = suggestions + .map((CompletionSuggestion value) => value.toJson()) + .toList(); + } + if (expressions != null) { + result["expressions"] = expressions + .map((RuntimeCompletionExpression value) => value.toJson()) + .toList(); + } + return result; + } + + @override + Response toResponse(String id) { + return new Response(id, result: toJson()); + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is ExecutionGetSuggestionsResult) { + return listEqual(suggestions, other.suggestions, + (CompletionSuggestion a, CompletionSuggestion b) => a == b) && + listEqual( + expressions, + other.expressions, + (RuntimeCompletionExpression a, RuntimeCompletionExpression b) => + a == b); + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, suggestions.hashCode); + hash = JenkinsSmiHash.combine(hash, expressions.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + /** * execution.launchData params * @@ -15226,6 +15642,585 @@ class RequestErrorCode implements Enum { String toJson() => name; } +/** + * RuntimeCompletionExpression + * + * { + * "offset": int + * "length": int + * "type": optional RuntimeCompletionExpressionType + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class RuntimeCompletionExpression implements HasToJson { + int _offset; + + int _length; + + RuntimeCompletionExpressionType _type; + + /** + * The offset of the expression in the code for completion. + */ + int get offset => _offset; + + /** + * The offset of the expression in the code for completion. + */ + void set offset(int value) { + assert(value != null); + this._offset = value; + } + + /** + * The length of the expression in the code for completion. + */ + int get length => _length; + + /** + * The length of the expression in the code for completion. + */ + void set length(int value) { + assert(value != null); + this._length = value; + } + + /** + * When the expression is sent from the server to the client, the type is + * omitted. The client should fill the type when it sends the request to the + * server again. + */ + RuntimeCompletionExpressionType get type => _type; + + /** + * When the expression is sent from the server to the client, the type is + * omitted. The client should fill the type when it sends the request to the + * server again. + */ + void set type(RuntimeCompletionExpressionType value) { + this._type = value; + } + + RuntimeCompletionExpression(int offset, int length, + {RuntimeCompletionExpressionType type}) { + this.offset = offset; + this.length = length; + this.type = type; + } + + factory RuntimeCompletionExpression.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + int offset; + if (json.containsKey("offset")) { + offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "offset"); + } + int length; + if (json.containsKey("length")) { + length = jsonDecoder.decodeInt(jsonPath + ".length", json["length"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "length"); + } + RuntimeCompletionExpressionType type; + if (json.containsKey("type")) { + type = new RuntimeCompletionExpressionType.fromJson( + jsonDecoder, jsonPath + ".type", json["type"]); + } + return new RuntimeCompletionExpression(offset, length, type: type); + } else { + throw jsonDecoder.mismatch(jsonPath, "RuntimeCompletionExpression", json); + } + } + + @override + Map toJson() { + Map result = {}; + result["offset"] = offset; + result["length"] = length; + if (type != null) { + result["type"] = type.toJson(); + } + return result; + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is RuntimeCompletionExpression) { + return offset == other.offset && + length == other.length && + type == other.type; + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, offset.hashCode); + hash = JenkinsSmiHash.combine(hash, length.hashCode); + hash = JenkinsSmiHash.combine(hash, type.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + +/** + * RuntimeCompletionExpressionType + * + * { + * "libraryPath": optional FilePath + * "kind": RuntimeCompletionExpressionTypeKind + * "name": optional String + * "typeArguments": optional List + * "returnType": optional RuntimeCompletionExpressionType + * "parameterTypes": optional List + * "parameterNames": optional List + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class RuntimeCompletionExpressionType implements HasToJson { + String _libraryPath; + + RuntimeCompletionExpressionTypeKind _kind; + + String _name; + + List _typeArguments; + + RuntimeCompletionExpressionType _returnType; + + List _parameterTypes; + + List _parameterNames; + + /** + * The path of the library that has this type. Omitted if the type is not + * declared in any library, e.g. "dynamic", or "void". + */ + String get libraryPath => _libraryPath; + + /** + * The path of the library that has this type. Omitted if the type is not + * declared in any library, e.g. "dynamic", or "void". + */ + void set libraryPath(String value) { + this._libraryPath = value; + } + + /** + * The kind of the type. + */ + RuntimeCompletionExpressionTypeKind get kind => _kind; + + /** + * The kind of the type. + */ + void set kind(RuntimeCompletionExpressionTypeKind value) { + assert(value != null); + this._kind = value; + } + + /** + * The name of the type. Omitted if the type does not have a name, e.g. an + * inline function type. + */ + String get name => _name; + + /** + * The name of the type. Omitted if the type does not have a name, e.g. an + * inline function type. + */ + void set name(String value) { + this._name = value; + } + + /** + * The type arguments of the type. Omitted if the type does not have type + * parameters. + */ + List get typeArguments => _typeArguments; + + /** + * The type arguments of the type. Omitted if the type does not have type + * parameters. + */ + void set typeArguments(List value) { + this._typeArguments = value; + } + + /** + * If the type is a function type, the return type of the function. Omitted + * if the type is not a function type. + */ + RuntimeCompletionExpressionType get returnType => _returnType; + + /** + * If the type is a function type, the return type of the function. Omitted + * if the type is not a function type. + */ + void set returnType(RuntimeCompletionExpressionType value) { + this._returnType = value; + } + + /** + * If the type is a function type, the types of the function parameters of + * all kinds - required, optional positional, and optional named. Omitted if + * the type is not a function type. + */ + List get parameterTypes => _parameterTypes; + + /** + * If the type is a function type, the types of the function parameters of + * all kinds - required, optional positional, and optional named. Omitted if + * the type is not a function type. + */ + void set parameterTypes(List value) { + this._parameterTypes = value; + } + + /** + * If the type is a function type, the names of the function parameters of + * all kinds - required, optional positional, and optional named. The names + * of positional parameters are empty strings. Omitted if the type is not a + * function type. + */ + List get parameterNames => _parameterNames; + + /** + * If the type is a function type, the names of the function parameters of + * all kinds - required, optional positional, and optional named. The names + * of positional parameters are empty strings. Omitted if the type is not a + * function type. + */ + void set parameterNames(List value) { + this._parameterNames = value; + } + + RuntimeCompletionExpressionType(RuntimeCompletionExpressionTypeKind kind, + {String libraryPath, + String name, + List typeArguments, + RuntimeCompletionExpressionType returnType, + List parameterTypes, + List parameterNames}) { + this.libraryPath = libraryPath; + this.kind = kind; + this.name = name; + this.typeArguments = typeArguments; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + this.parameterNames = parameterNames; + } + + factory RuntimeCompletionExpressionType.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + String libraryPath; + if (json.containsKey("libraryPath")) { + libraryPath = jsonDecoder.decodeString( + jsonPath + ".libraryPath", json["libraryPath"]); + } + RuntimeCompletionExpressionTypeKind kind; + if (json.containsKey("kind")) { + kind = new RuntimeCompletionExpressionTypeKind.fromJson( + jsonDecoder, jsonPath + ".kind", json["kind"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "kind"); + } + String name; + if (json.containsKey("name")) { + name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]); + } + List typeArguments; + if (json.containsKey("typeArguments")) { + typeArguments = jsonDecoder.decodeList( + jsonPath + ".typeArguments", + json["typeArguments"], + (String jsonPath, Object json) => + new RuntimeCompletionExpressionType.fromJson( + jsonDecoder, jsonPath, json)); + } + RuntimeCompletionExpressionType returnType; + if (json.containsKey("returnType")) { + returnType = new RuntimeCompletionExpressionType.fromJson( + jsonDecoder, jsonPath + ".returnType", json["returnType"]); + } + List parameterTypes; + if (json.containsKey("parameterTypes")) { + parameterTypes = jsonDecoder.decodeList( + jsonPath + ".parameterTypes", + json["parameterTypes"], + (String jsonPath, Object json) => + new RuntimeCompletionExpressionType.fromJson( + jsonDecoder, jsonPath, json)); + } + List parameterNames; + if (json.containsKey("parameterNames")) { + parameterNames = jsonDecoder.decodeList(jsonPath + ".parameterNames", + json["parameterNames"], jsonDecoder.decodeString); + } + return new RuntimeCompletionExpressionType(kind, + libraryPath: libraryPath, + name: name, + typeArguments: typeArguments, + returnType: returnType, + parameterTypes: parameterTypes, + parameterNames: parameterNames); + } else { + throw jsonDecoder.mismatch( + jsonPath, "RuntimeCompletionExpressionType", json); + } + } + + @override + Map toJson() { + Map result = {}; + if (libraryPath != null) { + result["libraryPath"] = libraryPath; + } + result["kind"] = kind.toJson(); + if (name != null) { + result["name"] = name; + } + if (typeArguments != null) { + result["typeArguments"] = typeArguments + .map((RuntimeCompletionExpressionType value) => value.toJson()) + .toList(); + } + if (returnType != null) { + result["returnType"] = returnType.toJson(); + } + if (parameterTypes != null) { + result["parameterTypes"] = parameterTypes + .map((RuntimeCompletionExpressionType value) => value.toJson()) + .toList(); + } + if (parameterNames != null) { + result["parameterNames"] = parameterNames; + } + return result; + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is RuntimeCompletionExpressionType) { + return libraryPath == other.libraryPath && + kind == other.kind && + name == other.name && + listEqual( + typeArguments, + other.typeArguments, + (RuntimeCompletionExpressionType a, + RuntimeCompletionExpressionType b) => + a == b) && + returnType == other.returnType && + listEqual( + parameterTypes, + other.parameterTypes, + (RuntimeCompletionExpressionType a, + RuntimeCompletionExpressionType b) => + a == b) && + listEqual(parameterNames, other.parameterNames, + (String a, String b) => a == b); + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, libraryPath.hashCode); + hash = JenkinsSmiHash.combine(hash, kind.hashCode); + hash = JenkinsSmiHash.combine(hash, name.hashCode); + hash = JenkinsSmiHash.combine(hash, typeArguments.hashCode); + hash = JenkinsSmiHash.combine(hash, returnType.hashCode); + hash = JenkinsSmiHash.combine(hash, parameterTypes.hashCode); + hash = JenkinsSmiHash.combine(hash, parameterNames.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + +/** + * RuntimeCompletionExpressionTypeKind + * + * enum { + * DYNAMIC + * FUNCTION + * INTERFACE + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class RuntimeCompletionExpressionTypeKind implements Enum { + static const RuntimeCompletionExpressionTypeKind DYNAMIC = + const RuntimeCompletionExpressionTypeKind._("DYNAMIC"); + + static const RuntimeCompletionExpressionTypeKind FUNCTION = + const RuntimeCompletionExpressionTypeKind._("FUNCTION"); + + static const RuntimeCompletionExpressionTypeKind INTERFACE = + const RuntimeCompletionExpressionTypeKind._("INTERFACE"); + + /** + * A list containing all of the enum values that are defined. + */ + static const List VALUES = + const [DYNAMIC, FUNCTION, INTERFACE]; + + @override + final String name; + + const RuntimeCompletionExpressionTypeKind._(this.name); + + factory RuntimeCompletionExpressionTypeKind(String name) { + switch (name) { + case "DYNAMIC": + return DYNAMIC; + case "FUNCTION": + return FUNCTION; + case "INTERFACE": + return INTERFACE; + } + throw new Exception('Illegal enum value: $name'); + } + + factory RuntimeCompletionExpressionTypeKind.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json is String) { + try { + return new RuntimeCompletionExpressionTypeKind(json); + } catch (_) { + // Fall through + } + } + throw jsonDecoder.mismatch( + jsonPath, "RuntimeCompletionExpressionTypeKind", json); + } + + @override + String toString() => "RuntimeCompletionExpressionTypeKind.$name"; + + String toJson() => name; +} + +/** + * RuntimeCompletionVariable + * + * { + * "name": String + * "type": RuntimeCompletionExpressionType + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class RuntimeCompletionVariable implements HasToJson { + String _name; + + RuntimeCompletionExpressionType _type; + + /** + * The name of the variable. The name "this" has a special meaning and is + * used as an implicit target for runtime completion, and in explicit "this" + * references. + */ + String get name => _name; + + /** + * The name of the variable. The name "this" has a special meaning and is + * used as an implicit target for runtime completion, and in explicit "this" + * references. + */ + void set name(String value) { + assert(value != null); + this._name = value; + } + + /** + * The type of the variable. + */ + RuntimeCompletionExpressionType get type => _type; + + /** + * The type of the variable. + */ + void set type(RuntimeCompletionExpressionType value) { + assert(value != null); + this._type = value; + } + + RuntimeCompletionVariable(String name, RuntimeCompletionExpressionType type) { + this.name = name; + this.type = type; + } + + factory RuntimeCompletionVariable.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + String name; + if (json.containsKey("name")) { + name = jsonDecoder.decodeString(jsonPath + ".name", json["name"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "name"); + } + RuntimeCompletionExpressionType type; + if (json.containsKey("type")) { + type = new RuntimeCompletionExpressionType.fromJson( + jsonDecoder, jsonPath + ".type", json["type"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "type"); + } + return new RuntimeCompletionVariable(name, type); + } else { + throw jsonDecoder.mismatch(jsonPath, "RuntimeCompletionVariable", json); + } + } + + @override + Map toJson() { + Map result = {}; + result["name"] = name; + result["type"] = type.toJson(); + return result; + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is RuntimeCompletionVariable) { + return name == other.name && type == other.type; + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, name.hashCode); + hash = JenkinsSmiHash.combine(hash, type.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + /** * search.findElementReferences params * diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md index 4dbeae6cb73..466c66e3d5d 100644 --- a/pkg/analysis_server/test/integration/coverage.md +++ b/pkg/analysis_server/test/integration/coverage.md @@ -53,6 +53,7 @@ server calls. This file is validated by `coverage_test.dart`. ## execution domain - [x] execution.createContext - [x] execution.deleteContext +- [ ] execution.getSuggestions - [x] execution.mapUri - [x] execution.setSubscriptions - [ ] execution.launchData diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart index 9b77a47b4b3..41880e3d8fe 100644 --- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart +++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart @@ -1829,6 +1829,98 @@ abstract class IntegrationTestMixin { return null; } + /** + * Request completion suggestions for the given runtime context. + * + * It might take one or two requests of this type to get completion + * suggestions. The first request should have only "code", "offset", and + * "variables", but not "expressions". If there are sub-expressions that can + * have different runtime types, and are considered to be safe to evaluate at + * runtime (e.g. getters), so using their actual runtime types can improve + * completion results, the server will not include the "suggestions" field in + * the response, and instead will return the "expressions" field. The client + * will use debug API to get current runtime types for these sub-expressions + * and send another request, this time with "expressions". If there are no + * interesting sub-expressions to get runtime types for, or when the + * "expressions" field is provided by the client, the server will return + * "suggestions" in the response. + * + * Parameters + * + * code: String + * + * The code to get suggestions in. + * + * offset: int + * + * The offset within the code to get suggestions at. + * + * contextFile: FilePath + * + * The path of the context file, e.g. the file of the current debugger + * frame. The combination of the context file and context offset can be + * used to ensure that all variables of the context are available for + * completion (with their static types). + * + * contextOffset: int + * + * The offset in the context file, e.g. the line offset in the current + * debugger frame. + * + * variables: List + * + * The runtime context variables that are potentially referenced in the + * code. + * + * expressions: List (optional) + * + * The list of sub-expressions in the code for which the client wants to + * provide runtime types. It does not have to be the full list of + * expressions requested by the server, for missing expressions their + * static types will be used. + * + * When this field is omitted, the server will return completion + * suggestions only when there are no interesting sub-expressions in the + * given code. The client may provide an empty list, in this case the + * server will return completion suggestions. + * + * Returns + * + * suggestions: List (optional) + * + * The completion suggestions. In contrast to usual completion request, + * suggestions for private elements also will be provided. + * + * If there are sub-expressions that can have different runtime types, and + * are considered to be safe to evaluate at runtime (e.g. getters), so + * using their actual runtime types can improve completion results, the + * server omits this field in the response, and instead will return the + * "expressions" field. + * + * expressions: List (optional) + * + * The list of sub-expressions in the code for which the server would like + * to know runtime types to provide better completion suggestions. + * + * This field is omitted the field "suggestions" is returned. + */ + Future sendExecutionGetSuggestions( + String code, + int offset, + String contextFile, + int contextOffset, + List variables, + {List expressions}) async { + var params = new ExecutionGetSuggestionsParams( + code, offset, contextFile, contextOffset, variables, + expressions: expressions) + .toJson(); + var result = await server.send("execution.getSuggestions", params); + ResponseDecoder decoder = new ResponseDecoder(null); + return new ExecutionGetSuggestionsResult.fromJson( + decoder, 'result', result); + } + /** * Map a URI from the execution context to the file that it corresponds to, * or map a file to the URI that it corresponds to in the execution context. diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart index dd07221863e..549934276fc 100644 --- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart +++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart @@ -1276,6 +1276,70 @@ final Matcher isRequestErrorCode = new MatchesEnum("RequestErrorCode", [ "UNSUPPORTED_FEATURE" ]); +/** + * RuntimeCompletionExpression + * + * { + * "offset": int + * "length": int + * "type": optional RuntimeCompletionExpressionType + * } + */ +final Matcher isRuntimeCompletionExpression = new LazyMatcher(() => + new MatchesJsonObject( + "RuntimeCompletionExpression", {"offset": isInt, "length": isInt}, + optionalFields: {"type": isRuntimeCompletionExpressionType})); + +/** + * RuntimeCompletionExpressionType + * + * { + * "libraryPath": optional FilePath + * "kind": RuntimeCompletionExpressionTypeKind + * "name": optional String + * "typeArguments": optional List + * "returnType": optional RuntimeCompletionExpressionType + * "parameterTypes": optional List + * "parameterNames": optional List + * } + */ +final Matcher isRuntimeCompletionExpressionType = new LazyMatcher( + () => new MatchesJsonObject("RuntimeCompletionExpressionType", { + "kind": isRuntimeCompletionExpressionTypeKind + }, optionalFields: { + "libraryPath": isFilePath, + "name": isString, + "typeArguments": isListOf(isRuntimeCompletionExpressionType), + "returnType": isRuntimeCompletionExpressionType, + "parameterTypes": isListOf(isRuntimeCompletionExpressionType), + "parameterNames": isListOf(isString) + })); + +/** + * RuntimeCompletionExpressionTypeKind + * + * enum { + * DYNAMIC + * FUNCTION + * INTERFACE + * } + */ +final Matcher isRuntimeCompletionExpressionTypeKind = new MatchesEnum( + "RuntimeCompletionExpressionTypeKind", + ["DYNAMIC", "FUNCTION", "INTERFACE"]); + +/** + * RuntimeCompletionVariable + * + * { + * "name": String + * "type": RuntimeCompletionExpressionType + * } + */ +final Matcher isRuntimeCompletionVariable = new LazyMatcher(() => + new MatchesJsonObject("RuntimeCompletionVariable", + {"name": isString, "type": isRuntimeCompletionExpressionType})); + /** * SearchId * @@ -2328,6 +2392,44 @@ final Matcher isExecutionDeleteContextParams = new LazyMatcher(() => */ final Matcher isExecutionDeleteContextResult = isNull; +/** + * execution.getSuggestions params + * + * { + * "code": String + * "offset": int + * "contextFile": FilePath + * "contextOffset": int + * "variables": List + * "expressions": optional List + * } + */ +final Matcher isExecutionGetSuggestionsParams = new LazyMatcher( + () => new MatchesJsonObject("execution.getSuggestions params", { + "code": isString, + "offset": isInt, + "contextFile": isFilePath, + "contextOffset": isInt, + "variables": isListOf(isRuntimeCompletionVariable) + }, optionalFields: { + "expressions": isListOf(isRuntimeCompletionExpression) + })); + +/** + * execution.getSuggestions result + * + * { + * "suggestions": optional List + * "expressions": optional List + * } + */ +final Matcher isExecutionGetSuggestionsResult = new LazyMatcher(() => + new MatchesJsonObject("execution.getSuggestions result", null, + optionalFields: { + "suggestions": isListOf(isCompletionSuggestion), + "expressions": isListOf(isRuntimeCompletionExpression) + })); + /** * execution.launchData params * diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java index 62726497089..f8991b5304c 100644 --- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java +++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java @@ -575,6 +575,38 @@ public interface AnalysisServer { */ public void execution_deleteContext(String id); + /** + * {@code execution.getSuggestions} + * + * Request completion suggestions for the given runtime context. + * + * It might take one or two requests of this type to get completion suggestions. The first request + * should have only "code", "offset", and "variables", but not "expressions". If there are + * sub-expressions that can have different runtime types, and are considered to be safe to evaluate + * at runtime (e.g. getters), so using their actual runtime types can improve completion results, + * the server will not include the "suggestions" field in the response, and instead will return the + * "expressions" field. The client will use debug API to get current runtime types for these + * sub-expressions and send another request, this time with "expressions". If there are no + * interesting sub-expressions to get runtime types for, or when the "expressions" field is + * provided by the client, the server will return "suggestions" in the response. + * + * @param code The code to get suggestions in. + * @param offset The offset within the code to get suggestions at. + * @param contextFile The path of the context file, e.g. the file of the current debugger frame. + * The combination of the context file and context offset can be used to ensure that all + * variables of the context are available for completion (with their static types). + * @param contextOffset The offset in the context file, e.g. the line offset in the current + * debugger frame. + * @param variables The runtime context variables that are potentially referenced in the code. + * @param expressions The list of sub-expressions in the code for which the client wants to provide + * runtime types. It does not have to be the full list of expressions requested by the + * server, for missing expressions their static types will be used. When this field is + * omitted, the server will return completion suggestions only when there are no + * interesting sub-expressions in the given code. The client may provide an empty list, in + * this case the server will return completion suggestions. + */ + public void execution_getSuggestions(String code, int offset, String contextFile, int contextOffset, List variables, List expressions, GetSuggestionsConsumer consumer); + /** * {@code execution.mapUri} * diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java new file mode 100644 index 00000000000..c0cc239f246 --- /dev/null +++ b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + * + * This file has been automatically generated. Please do not edit it manually. + * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files". + */ +package org.dartlang.analysis.server.protocol; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import com.google.common.collect.Lists; +import com.google.dart.server.utilities.general.JsonUtilities; +import com.google.dart.server.utilities.general.ObjectUtilities; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.commons.lang3.StringUtils; + +/** + * An expression for which we want to know its runtime type. In expressions like `a.b.c.where((e) + * => e.^)` we want to know the runtime type of `a.b.c` to enforce it statically at the time + * when we compute completion suggestions, and get better type for `e`. + * + * @coverage dart.server.generated.types + */ +@SuppressWarnings("unused") +public class RuntimeCompletionExpression { + + public static final RuntimeCompletionExpression[] EMPTY_ARRAY = new RuntimeCompletionExpression[0]; + + public static final List EMPTY_LIST = Lists.newArrayList(); + + /** + * The offset of the expression in the code for completion. + */ + private final int offset; + + /** + * The length of the expression in the code for completion. + */ + private final int length; + + /** + * When the expression is sent from the server to the client, the type is omitted. The client + * should fill the type when it sends the request to the server again. + */ + private final RuntimeCompletionExpressionType type; + + /** + * Constructor for {@link RuntimeCompletionExpression}. + */ + public RuntimeCompletionExpression(int offset, int length, RuntimeCompletionExpressionType type) { + this.offset = offset; + this.length = length; + this.type = type; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RuntimeCompletionExpression) { + RuntimeCompletionExpression other = (RuntimeCompletionExpression) obj; + return + other.offset == offset && + other.length == length && + ObjectUtilities.equals(other.type, type); + } + return false; + } + + public static RuntimeCompletionExpression fromJson(JsonObject jsonObject) { + int offset = jsonObject.get("offset").getAsInt(); + int length = jsonObject.get("length").getAsInt(); + RuntimeCompletionExpressionType type = jsonObject.get("type") == null ? null : RuntimeCompletionExpressionType.fromJson(jsonObject.get("type").getAsJsonObject()); + return new RuntimeCompletionExpression(offset, length, type); + } + + public static List fromJsonArray(JsonArray jsonArray) { + if (jsonArray == null) { + return EMPTY_LIST; + } + ArrayList list = new ArrayList(jsonArray.size()); + Iterator iterator = jsonArray.iterator(); + while (iterator.hasNext()) { + list.add(fromJson(iterator.next().getAsJsonObject())); + } + return list; + } + + /** + * The length of the expression in the code for completion. + */ + public int getLength() { + return length; + } + + /** + * The offset of the expression in the code for completion. + */ + public int getOffset() { + return offset; + } + + /** + * When the expression is sent from the server to the client, the type is omitted. The client + * should fill the type when it sends the request to the server again. + */ + public RuntimeCompletionExpressionType getType() { + return type; + } + + @Override + public int hashCode() { + HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(offset); + builder.append(length); + builder.append(type); + return builder.toHashCode(); + } + + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("offset", offset); + jsonObject.addProperty("length", length); + if (type != null) { + jsonObject.add("type", type.toJson()); + } + return jsonObject; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append("offset="); + builder.append(offset + ", "); + builder.append("length="); + builder.append(length + ", "); + builder.append("type="); + builder.append(type); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpressionType.java b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpressionType.java new file mode 100644 index 00000000000..c31710a7b69 --- /dev/null +++ b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpressionType.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + * + * This file has been automatically generated. Please do not edit it manually. + * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files". + */ +package org.dartlang.analysis.server.protocol; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import com.google.common.collect.Lists; +import com.google.dart.server.utilities.general.JsonUtilities; +import com.google.dart.server.utilities.general.ObjectUtilities; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.commons.lang3.StringUtils; + +/** + * A type at runtime. + * + * @coverage dart.server.generated.types + */ +@SuppressWarnings("unused") +public class RuntimeCompletionExpressionType { + + public static final RuntimeCompletionExpressionType[] EMPTY_ARRAY = new RuntimeCompletionExpressionType[0]; + + public static final List EMPTY_LIST = Lists.newArrayList(); + + /** + * The path of the library that has this type. Omitted if the type is not declared in any library, + * e.g. "dynamic", or "void". + */ + private final String libraryPath; + + /** + * The kind of the type. + */ + private final String kind; + + /** + * The name of the type. Omitted if the type does not have a name, e.g. an inline function type. + */ + private final String name; + + /** + * The type arguments of the type. Omitted if the type does not have type parameters. + */ + private final List typeArguments; + + /** + * If the type is a function type, the return type of the function. Omitted if the type is not a + * function type. + */ + private final RuntimeCompletionExpressionType returnType; + + /** + * If the type is a function type, the types of the function parameters of all kinds - required, + * optional positional, and optional named. Omitted if the type is not a function type. + */ + private final List parameterTypes; + + /** + * If the type is a function type, the names of the function parameters of all kinds - required, + * optional positional, and optional named. The names of positional parameters are empty strings. + * Omitted if the type is not a function type. + */ + private final List parameterNames; + + /** + * Constructor for {@link RuntimeCompletionExpressionType}. + */ + public RuntimeCompletionExpressionType(String libraryPath, String kind, String name, List typeArguments, RuntimeCompletionExpressionType returnType, List parameterTypes, List parameterNames) { + this.libraryPath = libraryPath; + this.kind = kind; + this.name = name; + this.typeArguments = typeArguments; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + this.parameterNames = parameterNames; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RuntimeCompletionExpressionType) { + RuntimeCompletionExpressionType other = (RuntimeCompletionExpressionType) obj; + return + ObjectUtilities.equals(other.libraryPath, libraryPath) && + ObjectUtilities.equals(other.kind, kind) && + ObjectUtilities.equals(other.name, name) && + ObjectUtilities.equals(other.typeArguments, typeArguments) && + ObjectUtilities.equals(other.returnType, returnType) && + ObjectUtilities.equals(other.parameterTypes, parameterTypes) && + ObjectUtilities.equals(other.parameterNames, parameterNames); + } + return false; + } + + public static RuntimeCompletionExpressionType fromJson(JsonObject jsonObject) { + String libraryPath = jsonObject.get("libraryPath") == null ? null : jsonObject.get("libraryPath").getAsString(); + String kind = jsonObject.get("kind").getAsString(); + String name = jsonObject.get("name") == null ? null : jsonObject.get("name").getAsString(); + List typeArguments = jsonObject.get("typeArguments") == null ? null : RuntimeCompletionExpressionType.fromJsonArray(jsonObject.get("typeArguments").getAsJsonArray()); + RuntimeCompletionExpressionType returnType = jsonObject.get("returnType") == null ? null : RuntimeCompletionExpressionType.fromJson(jsonObject.get("returnType").getAsJsonObject()); + List parameterTypes = jsonObject.get("parameterTypes") == null ? null : RuntimeCompletionExpressionType.fromJsonArray(jsonObject.get("parameterTypes").getAsJsonArray()); + List parameterNames = jsonObject.get("parameterNames") == null ? null : JsonUtilities.decodeStringList(jsonObject.get("parameterNames").getAsJsonArray()); + return new RuntimeCompletionExpressionType(libraryPath, kind, name, typeArguments, returnType, parameterTypes, parameterNames); + } + + public static List fromJsonArray(JsonArray jsonArray) { + if (jsonArray == null) { + return EMPTY_LIST; + } + ArrayList list = new ArrayList(jsonArray.size()); + Iterator iterator = jsonArray.iterator(); + while (iterator.hasNext()) { + list.add(fromJson(iterator.next().getAsJsonObject())); + } + return list; + } + + /** + * The kind of the type. + */ + public String getKind() { + return kind; + } + + /** + * The path of the library that has this type. Omitted if the type is not declared in any library, + * e.g. "dynamic", or "void". + */ + public String getLibraryPath() { + return libraryPath; + } + + /** + * The name of the type. Omitted if the type does not have a name, e.g. an inline function type. + */ + public String getName() { + return name; + } + + /** + * If the type is a function type, the names of the function parameters of all kinds - required, + * optional positional, and optional named. The names of positional parameters are empty strings. + * Omitted if the type is not a function type. + */ + public List getParameterNames() { + return parameterNames; + } + + /** + * If the type is a function type, the types of the function parameters of all kinds - required, + * optional positional, and optional named. Omitted if the type is not a function type. + */ + public List getParameterTypes() { + return parameterTypes; + } + + /** + * If the type is a function type, the return type of the function. Omitted if the type is not a + * function type. + */ + public RuntimeCompletionExpressionType getReturnType() { + return returnType; + } + + /** + * The type arguments of the type. Omitted if the type does not have type parameters. + */ + public List getTypeArguments() { + return typeArguments; + } + + @Override + public int hashCode() { + HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(libraryPath); + builder.append(kind); + builder.append(name); + builder.append(typeArguments); + builder.append(returnType); + builder.append(parameterTypes); + builder.append(parameterNames); + return builder.toHashCode(); + } + + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + if (libraryPath != null) { + jsonObject.addProperty("libraryPath", libraryPath); + } + jsonObject.addProperty("kind", kind); + if (name != null) { + jsonObject.addProperty("name", name); + } + if (typeArguments != null) { + JsonArray jsonArrayTypeArguments = new JsonArray(); + for (RuntimeCompletionExpressionType elt : typeArguments) { + jsonArrayTypeArguments.add(elt.toJson()); + } + jsonObject.add("typeArguments", jsonArrayTypeArguments); + } + if (returnType != null) { + jsonObject.add("returnType", returnType.toJson()); + } + if (parameterTypes != null) { + JsonArray jsonArrayParameterTypes = new JsonArray(); + for (RuntimeCompletionExpressionType elt : parameterTypes) { + jsonArrayParameterTypes.add(elt.toJson()); + } + jsonObject.add("parameterTypes", jsonArrayParameterTypes); + } + if (parameterNames != null) { + JsonArray jsonArrayParameterNames = new JsonArray(); + for (String elt : parameterNames) { + jsonArrayParameterNames.add(new JsonPrimitive(elt)); + } + jsonObject.add("parameterNames", jsonArrayParameterNames); + } + return jsonObject; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append("libraryPath="); + builder.append(libraryPath + ", "); + builder.append("kind="); + builder.append(kind + ", "); + builder.append("name="); + builder.append(name + ", "); + builder.append("typeArguments="); + builder.append(StringUtils.join(typeArguments, ", ") + ", "); + builder.append("returnType="); + builder.append(returnType + ", "); + builder.append("parameterTypes="); + builder.append(StringUtils.join(parameterTypes, ", ") + ", "); + builder.append("parameterNames="); + builder.append(StringUtils.join(parameterNames, ", ")); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpressionTypeKind.java b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpressionTypeKind.java new file mode 100644 index 00000000000..c544c9fc89a --- /dev/null +++ b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpressionTypeKind.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + * + * This file has been automatically generated. Please do not edit it manually. + * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files". + */ +package org.dartlang.analysis.server.protocol; + +/** + * An enumeration of the kinds of runtime expression types. + * + * @coverage dart.server.generated.types + */ +public class RuntimeCompletionExpressionTypeKind { + + public static final String DYNAMIC = "DYNAMIC"; + + public static final String FUNCTION = "FUNCTION"; + + public static final String INTERFACE = "INTERFACE"; + +} diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionVariable.java b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionVariable.java new file mode 100644 index 00000000000..05e90400528 --- /dev/null +++ b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionVariable.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file + * for details. All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + * + * This file has been automatically generated. Please do not edit it manually. + * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files". + */ +package org.dartlang.analysis.server.protocol; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import com.google.common.collect.Lists; +import com.google.dart.server.utilities.general.JsonUtilities; +import com.google.dart.server.utilities.general.ObjectUtilities; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.commons.lang3.StringUtils; + +/** + * A variable in a runtime context. + * + * @coverage dart.server.generated.types + */ +@SuppressWarnings("unused") +public class RuntimeCompletionVariable { + + public static final RuntimeCompletionVariable[] EMPTY_ARRAY = new RuntimeCompletionVariable[0]; + + public static final List EMPTY_LIST = Lists.newArrayList(); + + /** + * The name of the variable. The name "this" has a special meaning and is used as an implicit + * target for runtime completion, and in explicit "this" references. + */ + private final String name; + + /** + * The type of the variable. + */ + private final RuntimeCompletionExpressionType type; + + /** + * Constructor for {@link RuntimeCompletionVariable}. + */ + public RuntimeCompletionVariable(String name, RuntimeCompletionExpressionType type) { + this.name = name; + this.type = type; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RuntimeCompletionVariable) { + RuntimeCompletionVariable other = (RuntimeCompletionVariable) obj; + return + ObjectUtilities.equals(other.name, name) && + ObjectUtilities.equals(other.type, type); + } + return false; + } + + public static RuntimeCompletionVariable fromJson(JsonObject jsonObject) { + String name = jsonObject.get("name").getAsString(); + RuntimeCompletionExpressionType type = RuntimeCompletionExpressionType.fromJson(jsonObject.get("type").getAsJsonObject()); + return new RuntimeCompletionVariable(name, type); + } + + public static List fromJsonArray(JsonArray jsonArray) { + if (jsonArray == null) { + return EMPTY_LIST; + } + ArrayList list = new ArrayList(jsonArray.size()); + Iterator iterator = jsonArray.iterator(); + while (iterator.hasNext()) { + list.add(fromJson(iterator.next().getAsJsonObject())); + } + return list; + } + + /** + * The name of the variable. The name "this" has a special meaning and is used as an implicit + * target for runtime completion, and in explicit "this" references. + */ + public String getName() { + return name; + } + + /** + * The type of the variable. + */ + public RuntimeCompletionExpressionType getType() { + return type; + } + + @Override + public int hashCode() { + HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(name); + builder.append(type); + return builder.toHashCode(); + } + + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("name", name); + jsonObject.add("type", type.toJson()); + return jsonObject; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append("name="); + builder.append(name + ", "); + builder.append("type="); + builder.append(type); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html index 0d1c534dcef..90588f91b96 100644 --- a/pkg/analysis_server/tool/spec/spec_input.html +++ b/pkg/analysis_server/tool/spec/spec_input.html @@ -2307,6 +2307,111 @@ + +

+ Request completion suggestions for the given runtime context. +

+

+ It might take one or two requests of this type to get completion + suggestions. The first request should have only "code", "offset", + and "variables", but not "expressions". If there are sub-expressions that + can have different runtime types, and are considered to be safe to + evaluate at runtime (e.g. getters), so using their actual runtime types + can improve completion results, the server will not include the + "suggestions" field in the response, and instead will return the + "expressions" field. The client will use debug API to get current runtime + types for these sub-expressions and send another request, this time with + "expressions". If there are no interesting sub-expressions to get + runtime types for, or when the "expressions" field is provided by the + client, the server will return "suggestions" in the response. +

+ + + String +

+ The code to get suggestions in. +

+
+ + int +

+ The offset within the code to get suggestions at. +

+
+ + FilePath +

+ The path of the context file, e.g. the file of the current debugger + frame. The combination of the context file and context offset can + be used to ensure that all variables of the context are available + for completion (with their static types). +

+
+ + int +

+ The offset in the context file, e.g. the line offset in the current + debugger frame. +

+
+ + + RuntimeCompletionVariable + +

+ The runtime context variables that are potentially referenced in the + code. +

+
+ + + RuntimeCompletionExpression + +

+ The list of sub-expressions in the code for which the client wants + to provide runtime types. It does not have to be the full list of + expressions requested by the server, for missing expressions their + static types will be used. +

+

+ When this field is omitted, the server will return completion + suggestions only when there are no interesting sub-expressions in the + given code. The client may provide an empty list, in this case the + server will return completion suggestions. +

+
+
+ + + + CompletionSuggestion + +

+ The completion suggestions. In contrast to usual completion request, + suggestions for private elements also will be provided. +

+

+ If there are sub-expressions that can have different runtime types, + and are considered to be safe to evaluate at runtime (e.g. getters), + so using their actual runtime types can improve completion results, + the server omits this field in the response, and instead will return + the "expressions" field. +

+
+ + + RuntimeCompletionExpression + +

+ The list of sub-expressions in the code for which the server would + like to know runtime types to provide better completion suggestions. +

+

+ This field is omitted the field "suggestions" is returned. +

+
+
+

Map a URI from the execution context to the file that it corresponds @@ -3075,6 +3180,132 @@ The identifier for a execution context.

+ +

+ An expression for which we want to know its runtime type. + In expressions like `a.b.c.where((e) => e.^)` we want to know the + runtime type of `a.b.c` to enforce it statically at the time when we + compute completion suggestions, and get better type for `e`. +

+ + + int +

+ The offset of the expression in the code for completion. +

+
+ + int +

+ The length of the expression in the code for completion. +

+
+ + RuntimeCompletionExpressionType +

+ When the expression is sent from the server to the client, the + type is omitted. The client should fill the type when it sends the + request to the server again. +

+
+
+
+ +

+ A variable in a runtime context. +

+ + + String +

+ The name of the variable. + The name "this" has a special meaning and is used as an implicit + target for runtime completion, and in explicit "this" references. +

+
+ + RuntimeCompletionExpressionType +

+ The type of the variable. +

+
+
+
+ +

+ A type at runtime. +

+ + + FilePath +

+ The path of the library that has this type. + Omitted if the type is not declared in any library, e.g. "dynamic", + or "void". +

+
+ + RuntimeCompletionExpressionTypeKind +

+ The kind of the type. +

+
+ + String +

+ The name of the type. Omitted if the type does not have a name, e.g. + an inline function type. +

+
+ + + RuntimeCompletionExpressionType + +

+ The type arguments of the type. + Omitted if the type does not have type parameters. +

+
+ + RuntimeCompletionExpressionType +

+ If the type is a function type, the return type of the function. + Omitted if the type is not a function type. +

+
+ + + RuntimeCompletionExpressionType + +

+ If the type is a function type, the types of the function parameters + of all kinds - required, optional positional, and optional named. + Omitted if the type is not a function type. +

+
+ + + String + +

+ If the type is a function type, the names of the function parameters + of all kinds - required, optional positional, and optional named. + The names of positional parameters are empty strings. + Omitted if the type is not a function type. +

+
+
+
+ +

+ An enumeration of the kinds of runtime expression types. +

+ + DYNAMIC + FUNCTION + INTERFACE + +

An enumeration of the services provided by the execution