AnalysisError hasFix attr (Implements #23874).

R=brianwilkerson@google.com, scheglov@google.com

Review URL: https://codereview.chromium.org/1385523002 .
This commit is contained in:
pq 2015-10-05 09:46:17 -07:00
parent 04c5a5f199
commit 8697392367
10 changed files with 182 additions and 15 deletions

View file

@ -61,7 +61,7 @@ dt.typeDefinition {
</style></head>
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version 1.10.0</h1>
<h1 style="color:#999999">Version 1.11.0</h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@ -2380,6 +2380,20 @@ dt.typeDefinition {
the error. The field is omitted if there is no correction
message associated with the error code.
</p>
</dd><dt class="field"><b><i>hasFix ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
<p>
A hint to indicate to interested clients that this error has
an associated fix (or fixes). The absence of this field implies
there are not known to be fixes. Note that since the operation
to calculate whether fixes apply needs to be performant it is
possible that complicated tests will be skipped and a false
negative returned. For this reason, this attribute should be
treated as a "hint". Despite the possibility of false negatives,
no false positives should be returned. If a client sees this
flag set they can proceed with the confidence that there are in
fact associated fixes.
</p>
</dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorFixes">AnalysisErrorFixes: object</a></dt><dd>
<p>
A list of fixes associated with a specific error

View file

@ -70,7 +70,7 @@ class AnalysisServer {
* The version of the analysis server. The value should be replaced
* automatically during the build.
*/
static final String VERSION = '1.9.0';
static final String VERSION = '1.11.0';
/**
* The number of milliseconds to perform operations before inserting

View file

@ -137,6 +137,7 @@ const String FILE_STAMP = 'fileStamp';
const String FILES = 'files';
const String FIXES = 'fixes';
const String FLAGS = 'flags';
const String HAS_FIX = 'hasFix';
const String HIERARCHY_ITEMS = 'hierarchyItems';
const String HOVERS = 'hovers';
const String ID = 'id';

View file

@ -7347,6 +7347,7 @@ class AddContentOverlay implements HasToJson {
* "location": Location
* "message": String
* "correction": optional String
* "hasFix": optional bool
* }
*/
class AnalysisError implements HasToJson {
@ -7360,6 +7361,8 @@ class AnalysisError implements HasToJson {
String _correction;
bool _hasFix;
/**
* The severity of the error.
*/
@ -7430,12 +7433,39 @@ class AnalysisError implements HasToJson {
this._correction = value;
}
AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction}) {
/**
* A hint to indicate to interested clients that this error has an associated
* fix (or fixes). The absence of this field implies there are not known to
* be fixes. Note that since the operation to calculate whether fixes apply
* needs to be performant it is possible that complicated tests will be
* skipped and a false negative returned. For this reason, this attribute
* should be treated as a "hint". Despite the possibility of false negatives,
* no false positives should be returned. If a client sees this flag set they
* can proceed with the confidence that there are in fact associated fixes.
*/
bool get hasFix => _hasFix;
/**
* A hint to indicate to interested clients that this error has an associated
* fix (or fixes). The absence of this field implies there are not known to
* be fixes. Note that since the operation to calculate whether fixes apply
* needs to be performant it is possible that complicated tests will be
* skipped and a false negative returned. For this reason, this attribute
* should be treated as a "hint". Despite the possibility of false negatives,
* no false positives should be returned. If a client sees this flag set they
* can proceed with the confidence that there are in fact associated fixes.
*/
void set hasFix(bool value) {
this._hasFix = value;
}
AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction, bool hasFix}) {
this.severity = severity;
this.type = type;
this.location = location;
this.message = message;
this.correction = correction;
this.hasFix = hasFix;
}
factory AnalysisError.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
@ -7471,7 +7501,11 @@ class AnalysisError implements HasToJson {
if (json.containsKey("correction")) {
correction = jsonDecoder._decodeString(jsonPath + ".correction", json["correction"]);
}
return new AnalysisError(severity, type, location, message, correction: correction);
bool hasFix;
if (json.containsKey("hasFix")) {
hasFix = jsonDecoder._decodeBool(jsonPath + ".hasFix", json["hasFix"]);
}
return new AnalysisError(severity, type, location, message, correction: correction, hasFix: hasFix);
} else {
throw jsonDecoder.mismatch(jsonPath, "AnalysisError", json);
}
@ -7486,6 +7520,9 @@ class AnalysisError implements HasToJson {
if (correction != null) {
result["correction"] = correction;
}
if (hasFix != null) {
result["hasFix"] = hasFix;
}
return result;
}
@ -7499,7 +7536,8 @@ class AnalysisError implements HasToJson {
type == other.type &&
location == other.location &&
message == other.message &&
correction == other.correction;
correction == other.correction &&
hasFix == other.hasFix;
}
return false;
}
@ -7512,6 +7550,7 @@ class AnalysisError implements HasToJson {
hash = _JenkinsSmiHash.combine(hash, location.hashCode);
hash = _JenkinsSmiHash.combine(hash, message.hashCode);
hash = _JenkinsSmiHash.combine(hash, correction.hashCode);
hash = _JenkinsSmiHash.combine(hash, hasFix.hashCode);
return _JenkinsSmiHash.finish(hash);
}
}

View file

@ -5,6 +5,7 @@
library protocol.server;
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/search/search_engine.dart'
as engine;
import 'package:analyzer/src/generated/ast.dart' as engine;
@ -92,8 +93,9 @@ AnalysisError newAnalysisError_fromEngine(
var type = new AnalysisErrorType(errorCode.type.name);
String message = error.message;
String correction = error.correction;
bool fix = hasFix(error.errorCode);
return new AnalysisError(severity, type, location, message,
correction: correction);
correction: correction, hasFix: fix);
}
/**

View file

@ -10,6 +10,7 @@ import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/parser.dart';
/**
* Compute and return the fixes available for the given [error]. The error was
@ -37,6 +38,63 @@ List<Fix> computeFixes(ServerPlugin plugin, ResourceProvider resourceProvider,
return fixes;
}
/**
* Return true if this [errorCode] is likely to have a fix associated with it.
*/
bool hasFix(ErrorCode errorCode) => errorCode ==
StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
errorCode == StaticWarningCode.UNDEFINED_CLASS ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS ||
errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER ||
errorCode ==
CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE ||
errorCode == CompileTimeErrorCode.INVALID_ANNOTATION ||
errorCode == CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT ||
errorCode == CompileTimeErrorCode.PART_OF_NON_PART ||
errorCode ==
CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT ||
errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
errorCode == HintCode.DEAD_CODE ||
errorCode == HintCode.DIVISION_OPTIMIZATION ||
errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL ||
errorCode == HintCode.TYPE_CHECK_IS_NULL ||
errorCode == HintCode.UNDEFINED_GETTER ||
errorCode == HintCode.UNDEFINED_SETTER ||
errorCode == HintCode.UNNECESSARY_CAST ||
errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
errorCode == HintCode.UNUSED_CATCH_STACK ||
errorCode == HintCode.UNUSED_IMPORT ||
errorCode == HintCode.UNDEFINED_METHOD ||
errorCode == ParserErrorCode.EXPECTED_TOKEN ||
errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS ||
errorCode == ParserErrorCode.VAR_AS_TYPE_NAME ||
errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE ||
errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER ||
errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION ||
errorCode == StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT ||
errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION ||
errorCode == StaticTypeWarningCode.UNDEFINED_GETTER ||
errorCode == StaticTypeWarningCode.UNDEFINED_METHOD ||
errorCode == StaticTypeWarningCode.UNDEFINED_SETTER;
/**
* An enumeration of possible quick fix kinds.
*/

View file

@ -1029,6 +1029,7 @@ final Matcher isAddContentOverlay = new LazyMatcher(() => new MatchesJsonObject(
* "location": Location
* "message": String
* "correction": optional String
* "hasFix": optional bool
* }
*/
final Matcher isAnalysisError = new LazyMatcher(() => new MatchesJsonObject(
@ -1038,7 +1039,8 @@ final Matcher isAnalysisError = new LazyMatcher(() => new MatchesJsonObject(
"location": isLocation,
"message": isString
}, optionalFields: {
"correction": isString
"correction": isString,
"hasFix": isBool
}));
/**

View file

@ -72,7 +72,8 @@ class AnalysisErrorTest {
START_COLUMN: 2
},
MESSAGE: 'my message',
CORRECTION: 'my correction'
CORRECTION: 'my correction',
HAS_FIX : false
});
}
@ -89,7 +90,8 @@ class AnalysisErrorTest {
START_LINE: 3,
START_COLUMN: 2
},
MESSAGE: 'my message'
MESSAGE: 'my message',
HAS_FIX : false
});
}
@ -106,7 +108,8 @@ class AnalysisErrorTest {
START_LINE: -1,
START_COLUMN: -1
},
MESSAGE: 'my message'
MESSAGE: 'my message',
HAS_FIX : false
});
}
}

View file

@ -71,15 +71,27 @@ public class AnalysisError {
*/
private final String correction;
/**
* A hint to indicate to interested clients that this error has an associated fix (or fixes). The
* absence of this field implies there are not known to be fixes. Note that since the operation to
* calculate whether fixes apply needs to be performant it is possible that complicated tests will
* be skipped and a false negative returned. For this reason, this attribute should be treated as a
* "hint". Despite the possibility of false negatives, no false positives should be returned. If a
* client sees this flag set they can proceed with the confidence that there are in fact associated
* fixes.
*/
private final Boolean hasFix;
/**
* Constructor for {@link AnalysisError}.
*/
public AnalysisError(String severity, String type, Location location, String message, String correction) {
public AnalysisError(String severity, String type, Location location, String message, String correction, Boolean hasFix) {
this.severity = severity;
this.type = type;
this.location = location;
this.message = message;
this.correction = correction;
this.hasFix = hasFix;
}
@Override
@ -91,7 +103,8 @@ public class AnalysisError {
ObjectUtilities.equals(other.type, type) &&
ObjectUtilities.equals(other.location, location) &&
ObjectUtilities.equals(other.message, message) &&
ObjectUtilities.equals(other.correction, correction);
ObjectUtilities.equals(other.correction, correction) &&
ObjectUtilities.equals(other.hasFix, hasFix);
}
return false;
}
@ -102,7 +115,8 @@ public class AnalysisError {
Location location = Location.fromJson(jsonObject.get("location").getAsJsonObject());
String message = jsonObject.get("message").getAsString();
String correction = jsonObject.get("correction") == null ? null : jsonObject.get("correction").getAsString();
return new AnalysisError(severity, type, location, message, correction);
Boolean hasFix = jsonObject.get("hasFix") == null ? null : jsonObject.get("hasFix").getAsBoolean();
return new AnalysisError(severity, type, location, message, correction, hasFix);
}
public static List<AnalysisError> fromJsonArray(JsonArray jsonArray) {
@ -126,6 +140,19 @@ public class AnalysisError {
return correction;
}
/**
* A hint to indicate to interested clients that this error has an associated fix (or fixes). The
* absence of this field implies there are not known to be fixes. Note that since the operation to
* calculate whether fixes apply needs to be performant it is possible that complicated tests will
* be skipped and a false negative returned. For this reason, this attribute should be treated as a
* "hint". Despite the possibility of false negatives, no false positives should be returned. If a
* client sees this flag set they can proceed with the confidence that there are in fact associated
* fixes.
*/
public Boolean getHasFix() {
return hasFix;
}
/**
* The location associated with the error.
*/
@ -163,6 +190,7 @@ public class AnalysisError {
builder.append(location);
builder.append(message);
builder.append(correction);
builder.append(hasFix);
return builder.toHashCode();
}
@ -175,6 +203,9 @@ public class AnalysisError {
if (correction != null) {
jsonObject.addProperty("correction", correction);
}
if (hasFix != null) {
jsonObject.addProperty("hasFix", hasFix);
}
return jsonObject;
}
@ -191,7 +222,9 @@ public class AnalysisError {
builder.append("message=");
builder.append(message + ", ");
builder.append("correction=");
builder.append(correction);
builder.append(correction + ", ");
builder.append("hasFix=");
builder.append(hasFix);
builder.append("]");
return builder.toString();
}

View file

@ -6,7 +6,7 @@
</head>
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version <version>1.10.0</version></h1>
<h1 style="color:#999999">Version <version>1.11.0</version></h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@ -2027,6 +2027,21 @@
message associated with the error code.
</p>
</field>
<field name="hasFix" optional="true">
<ref>bool</ref>
<p>
A hint to indicate to interested clients that this error has
an associated fix (or fixes). The absence of this field implies
there are not known to be fixes. Note that since the operation
to calculate whether fixes apply needs to be performant it is
possible that complicated tests will be skipped and a false
negative returned. For this reason, this attribute should be
treated as a "hint". Despite the possibility of false negatives,
no false positives should be returned. If a client sees this
flag set they can proceed with the confidence that there are in
fact associated fixes.
</p>
</field>
</object>
</type>
<type name="AnalysisErrorFixes">