Put fully resolved analysis results (just errors now) into the byte cache.

R=brianwilkerson@google.com, paulberry@google.com
BUG=

Review URL: https://codereview.chromium.org/2455573003 .
This commit is contained in:
Konstantin Shcheglov 2016-10-26 11:48:49 -07:00
parent 205e9a58e1
commit bd594d453f
4 changed files with 466 additions and 3 deletions

View file

@ -236,7 +236,8 @@ class AnalysisDriver {
for (String path in _priorityFiles) {
if (_filesToAnalyze.remove(path)) {
_File file = _fileForPath(path);
AnalysisResult result = _computeAnalysisResult(file);
AnalysisResult result =
_computeAnalysisResult(file, withUnit: true);
yield result;
break;
}
@ -252,7 +253,7 @@ class AnalysisDriver {
if (_filesToAnalyze.isNotEmpty) {
String path = _removeFirst(_filesToAnalyze);
_File file = _fileForPath(path);
AnalysisResult result = _computeAnalysisResult(file);
AnalysisResult result = _computeAnalysisResult(file, withUnit: false);
yield result;
// Repeat the processing loop.
_hasWork.notify();
@ -366,10 +367,32 @@ class AnalysisDriver {
/**
* Compute the [AnalysisResult] for the [file].
*
* The result will have the fully resolved unit only if [withUnit] is `true`.
*/
AnalysisResult _computeAnalysisResult(_File file) {
AnalysisResult _computeAnalysisResult(_File file, {bool withUnit: false}) {
// If we don't need to the fully resolved unit, check for a cached result.
if (!withUnit) {
AnalysisResult result = _getCachedAnalysisResult(file);
if (result != null) {
return result;
}
}
// We need the fully resolved unit, or the result is not cached.
return _logger.run('Compute analysis result for $file', () {
_LibraryContext libraryContext = _createLibraryContext(file);
// We recomputed the dependency hash, and we might have a cached result.
if (!withUnit) {
AnalysisResult result = _getCachedAnalysisResult(file);
if (result != null) {
_logger.writeln('Return the cached analysis result.');
return result;
}
}
// Still no result, compute and store it.
AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
try {
analysisContext.setContents(file.source, file.content);
@ -377,6 +400,25 @@ class AnalysisDriver {
CompilationUnit resolvedUnit =
analysisContext.resolveCompilationUnit2(file.source, file.source);
List<AnalysisError> errors = analysisContext.computeErrors(file.source);
// Store the result into the cache.
{
List<int> bytes = new AnalysisDriverResolvedUnitBuilder(
errors: errors
.map((error) => new AnalysisDriverUnitErrorBuilder(
offset: error.offset,
length: error.length,
uniqueName: error.errorCode.uniqueName,
message: error.message,
correction: error.correction))
.toList())
.toBuffer();
String key = _getResolvedUnitKey(file);
_byteStore.put(key, bytes);
}
// Return the full result.
_logger.writeln('Computed new analysis result.');
return new AnalysisResult(file.path, file.uri, file.content,
file.contentHash, resolvedUnit, errors);
} finally {
@ -526,6 +568,47 @@ class AnalysisDriver {
return new _File.forResolution(this, source);
}
/**
* If we know the dependency signature for the [file], try to load the
* analysis result from the cache. Return `null` if not found.
*/
AnalysisResult _getCachedAnalysisResult(_File file) {
String key = _getResolvedUnitKey(file);
if (key != null) {
List<int> bytes = _byteStore.get(key);
if (bytes != null) {
var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
List<AnalysisError> errors = unit.errors
.map((error) => new AnalysisError.forValues(
file.source,
error.offset,
error.length,
ErrorCode.byUniqueName(error.uniqueName),
error.message,
error.correction))
.toList();
return new AnalysisResult(
file.path, file.uri, null, file.contentHash, null, errors);
}
}
return null;
}
/**
* Return the key to store fully resolved results for the [file] into the
* cache. Return `null` if the dependency signature is not known yet.
*/
String _getResolvedUnitKey(_File file) {
String dependencyHash = _dependencySignatureMap[file.uri];
if (dependencyHash != null) {
ApiSignature signature = new ApiSignature();
signature.addString(dependencyHash);
signature.addString(file.contentHash);
return '${signature.toHex()}.resolved';
}
return null;
}
/**
* Verify the API signature for the file with the given [path], and decide
* which linked libraries should be invalidated, and files reanalyzed.

View file

@ -129,6 +129,296 @@ class _UnlinkedParamKindReader extends fb.Reader<idl.UnlinkedParamKind> {
}
}
class AnalysisDriverResolvedUnitBuilder extends Object with _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
List<AnalysisDriverUnitErrorBuilder> _errors;
@override
List<AnalysisDriverUnitErrorBuilder> get errors => _errors ??= <AnalysisDriverUnitErrorBuilder>[];
/**
* The full list of analysis errors, both syntactic and semantic.
*/
void set errors(List<AnalysisDriverUnitErrorBuilder> value) {
this._errors = value;
}
AnalysisDriverResolvedUnitBuilder({List<AnalysisDriverUnitErrorBuilder> errors})
: _errors = errors;
/**
* Flush [informative] data recursively.
*/
void flushInformative() {
_errors?.forEach((b) => b.flushInformative());
}
/**
* Accumulate non-[informative] data into [signature].
*/
void collectApiSignature(api_sig.ApiSignature signature) {
if (this._errors == null) {
signature.addInt(0);
} else {
signature.addInt(this._errors.length);
for (var x in this._errors) {
x?.collectApiSignature(signature);
}
}
}
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
return fbBuilder.finish(finish(fbBuilder), "ADRU");
}
fb.Offset finish(fb.Builder fbBuilder) {
fb.Offset offset_errors;
if (!(_errors == null || _errors.isEmpty)) {
offset_errors = fbBuilder.writeList(_errors.map((b) => b.finish(fbBuilder)).toList());
}
fbBuilder.startTable();
if (offset_errors != null) {
fbBuilder.addOffset(0, offset_errors);
}
return fbBuilder.endTable();
}
}
idl.AnalysisDriverResolvedUnit readAnalysisDriverResolvedUnit(List<int> buffer) {
fb.BufferContext rootRef = new fb.BufferContext.fromBytes(buffer);
return const _AnalysisDriverResolvedUnitReader().read(rootRef, 0);
}
class _AnalysisDriverResolvedUnitReader extends fb.TableReader<_AnalysisDriverResolvedUnitImpl> {
const _AnalysisDriverResolvedUnitReader();
@override
_AnalysisDriverResolvedUnitImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverResolvedUnitImpl(bc, offset);
}
class _AnalysisDriverResolvedUnitImpl extends Object with _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
final fb.BufferContext _bc;
final int _bcOffset;
_AnalysisDriverResolvedUnitImpl(this._bc, this._bcOffset);
List<idl.AnalysisDriverUnitError> _errors;
@override
List<idl.AnalysisDriverUnitError> get errors {
_errors ??= const fb.ListReader<idl.AnalysisDriverUnitError>(const _AnalysisDriverUnitErrorReader()).vTableGet(_bc, _bcOffset, 0, const <idl.AnalysisDriverUnitError>[]);
return _errors;
}
}
abstract class _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
@override
Map<String, Object> toJson() {
Map<String, Object> _result = <String, Object>{};
if (errors.isNotEmpty) _result["errors"] = errors.map((_value) => _value.toJson()).toList();
return _result;
}
@override
Map<String, Object> toMap() => {
"errors": errors,
};
@override
String toString() => convert.JSON.encode(toJson());
}
class AnalysisDriverUnitErrorBuilder extends Object with _AnalysisDriverUnitErrorMixin implements idl.AnalysisDriverUnitError {
String _correction;
int _length;
String _message;
int _offset;
String _uniqueName;
@override
String get correction => _correction ??= '';
/**
* The optional correction hint for the error.
*/
void set correction(String value) {
this._correction = value;
}
@override
int get length => _length ??= 0;
/**
* The length of the error in the file.
*/
void set length(int value) {
assert(value == null || value >= 0);
this._length = value;
}
@override
String get message => _message ??= '';
/**
* The message of the error.
*/
void set message(String value) {
this._message = value;
}
@override
int get offset => _offset ??= 0;
/**
* The offset from the beginning of the file.
*/
void set offset(int value) {
assert(value == null || value >= 0);
this._offset = value;
}
@override
String get uniqueName => _uniqueName ??= '';
/**
* The unique name of the error code.
*/
void set uniqueName(String value) {
this._uniqueName = value;
}
AnalysisDriverUnitErrorBuilder({String correction, int length, String message, int offset, String uniqueName})
: _correction = correction,
_length = length,
_message = message,
_offset = offset,
_uniqueName = uniqueName;
/**
* Flush [informative] data recursively.
*/
void flushInformative() {
}
/**
* Accumulate non-[informative] data into [signature].
*/
void collectApiSignature(api_sig.ApiSignature signature) {
signature.addInt(this._offset ?? 0);
signature.addInt(this._length ?? 0);
signature.addString(this._uniqueName ?? '');
signature.addString(this._message ?? '');
signature.addString(this._correction ?? '');
}
fb.Offset finish(fb.Builder fbBuilder) {
fb.Offset offset_correction;
fb.Offset offset_message;
fb.Offset offset_uniqueName;
if (_correction != null) {
offset_correction = fbBuilder.writeString(_correction);
}
if (_message != null) {
offset_message = fbBuilder.writeString(_message);
}
if (_uniqueName != null) {
offset_uniqueName = fbBuilder.writeString(_uniqueName);
}
fbBuilder.startTable();
if (offset_correction != null) {
fbBuilder.addOffset(4, offset_correction);
}
if (_length != null && _length != 0) {
fbBuilder.addUint32(1, _length);
}
if (offset_message != null) {
fbBuilder.addOffset(3, offset_message);
}
if (_offset != null && _offset != 0) {
fbBuilder.addUint32(0, _offset);
}
if (offset_uniqueName != null) {
fbBuilder.addOffset(2, offset_uniqueName);
}
return fbBuilder.endTable();
}
}
class _AnalysisDriverUnitErrorReader extends fb.TableReader<_AnalysisDriverUnitErrorImpl> {
const _AnalysisDriverUnitErrorReader();
@override
_AnalysisDriverUnitErrorImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverUnitErrorImpl(bc, offset);
}
class _AnalysisDriverUnitErrorImpl extends Object with _AnalysisDriverUnitErrorMixin implements idl.AnalysisDriverUnitError {
final fb.BufferContext _bc;
final int _bcOffset;
_AnalysisDriverUnitErrorImpl(this._bc, this._bcOffset);
String _correction;
int _length;
String _message;
int _offset;
String _uniqueName;
@override
String get correction {
_correction ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 4, '');
return _correction;
}
@override
int get length {
_length ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 1, 0);
return _length;
}
@override
String get message {
_message ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 3, '');
return _message;
}
@override
int get offset {
_offset ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 0, 0);
return _offset;
}
@override
String get uniqueName {
_uniqueName ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 2, '');
return _uniqueName;
}
}
abstract class _AnalysisDriverUnitErrorMixin implements idl.AnalysisDriverUnitError {
@override
Map<String, Object> toJson() {
Map<String, Object> _result = <String, Object>{};
if (correction != '') _result["correction"] = correction;
if (length != 0) _result["length"] = length;
if (message != '') _result["message"] = message;
if (offset != 0) _result["offset"] = offset;
if (uniqueName != '') _result["uniqueName"] = uniqueName;
return _result;
}
@override
Map<String, Object> toMap() => {
"correction": correction,
"length": length,
"message": message,
"offset": offset,
"uniqueName": uniqueName,
};
@override
String toString() => convert.JSON.encode(toJson());
}
class CodeRangeBuilder extends Object with _CodeRangeMixin implements idl.CodeRange {
int _length;
int _offset;

View file

@ -781,6 +781,46 @@ enum UnlinkedParamKind : byte {
named
}
/**
* Information about a resolved unit.
*/
table AnalysisDriverResolvedUnit {
/**
* The full list of analysis errors, both syntactic and semantic.
*/
errors:[AnalysisDriverUnitError] (id: 0);
}
/**
* Information about an error in a resolved unit.
*/
table AnalysisDriverUnitError {
/**
* The optional correction hint for the error.
*/
correction:string (id: 4);
/**
* The length of the error in the file.
*/
length:uint (id: 1);
/**
* The message of the error.
*/
message:string (id: 3);
/**
* The offset from the beginning of the file.
*/
offset:uint (id: 0);
/**
* The unique name of the error code.
*/
uniqueName:string (id: 2);
}
/**
* Information about an element code range.
*/

View file

@ -57,6 +57,56 @@ import 'format.dart' as generated;
*/
const informative = null;
/**
* Information about a resolved unit.
*/
@TopLevel('ADRU')
abstract class AnalysisDriverResolvedUnit extends base.SummaryClass {
factory AnalysisDriverResolvedUnit.fromBuffer(List<int> buffer) =>
generated.readAnalysisDriverResolvedUnit(buffer);
/**
* The full list of analysis errors, both syntactic and semantic.
*/
@Id(0)
List<AnalysisDriverUnitError> get errors;
}
/**
* Information about an error in a resolved unit.
*/
abstract class AnalysisDriverUnitError extends base.SummaryClass {
/**
* The optional correction hint for the error.
*/
@Id(4)
String get correction;
/**
* The length of the error in the file.
*/
@Id(1)
int get length;
/**
* The message of the error.
*/
@Id(3)
String get message;
/**
* The offset from the beginning of the file.
*/
@Id(0)
int get offset;
/**
* The unique name of the error code.
*/
@Id(2)
String get uniqueName;
}
/**
* Information about an element code range.
*/