Skip to content

Commit eb96871

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Compute unlinked API signatures without unlinked summaries.
[email protected], [email protected] Change-Id: I21c87f60d88716eb9c6b1d5e558bb17156daa598 Reviewed-on: https://dart-review.googlesource.com/74925 Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 98d25ed commit eb96871

File tree

6 files changed

+988
-42
lines changed

6 files changed

+988
-42
lines changed

pkg/analyzer/lib/src/dart/analysis/driver.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
9292
/**
9393
* The version of data format, should be incremented on every format change.
9494
*/
95-
static const int DATA_VERSION = 65;
95+
static const int DATA_VERSION = 66;
9696

9797
/**
9898
* The number of exception contexts allowed to write. Once this field is

pkg/analyzer/lib/src/dart/analysis/file_state.dart

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:analyzer/src/dart/analysis/defined_names.dart';
1414
import 'package:analyzer/src/dart/analysis/one_phase_summaries_selector.dart';
1515
import 'package:analyzer/src/dart/analysis/referenced_names.dart';
1616
import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
17+
import 'package:analyzer/src/dart/analysis/unlinked_api_signature.dart';
1718
import 'package:analyzer/src/dart/scanner/reader.dart';
1819
import 'package:analyzer/src/dart/scanner/scanner.dart';
1920
import 'package:analyzer/src/generated/engine.dart';
@@ -126,7 +127,6 @@ class FileState {
126127
Set<String> _definedTopLevelNames;
127128
Set<String> _referencedNames;
128129
Set<String> _subtypedNames;
129-
String _unlinkedKey;
130130
AnalysisDriverUnlinkedUnit _driverUnlinkedUnit;
131131
UnlinkedUnit _unlinked;
132132
List<int> _apiSignature;
@@ -419,41 +419,53 @@ class FileState {
419419
_contentHash = rawFileState.contentHash;
420420
}
421421

422-
// Prepare the unlinked bundle key.
422+
// Prepare keys of unlinked data.
423+
String apiSignatureKey;
424+
String unlinkedKey;
423425
{
424-
ApiSignature signature = new ApiSignature();
426+
var signature = new ApiSignature();
425427
signature.addUint32List(_fsState._salt);
426428
signature.addString(_contentHash);
427-
_unlinkedKey = '${signature.toHex()}.unlinked';
429+
430+
var signatureHex = signature.toHex();
431+
apiSignatureKey = '$signatureHex.api_signature';
432+
unlinkedKey = '$signatureHex.unlinked';
428433
}
429434

430-
// Prepare bytes of the unlinked bundle - existing or new.
431-
List<int> bytes;
432-
{
433-
bytes = _fsState._byteStore.get(_unlinkedKey);
434-
if (bytes == null || bytes.isEmpty) {
435-
CompilationUnit unit = parse();
436-
_fsState._logger.run('Create unlinked for $path', () {
437-
UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit,
435+
// Try to get bytes of unlinked data.
436+
var apiSignatureBytes = _fsState._byteStore.get(apiSignatureKey);
437+
var unlinkedUnitBytes = _fsState._byteStore.get(unlinkedKey);
438+
439+
// Compute unlinked data that we are missing.
440+
if (apiSignatureBytes == null || unlinkedUnitBytes == null) {
441+
CompilationUnit unit = parse(AnalysisErrorListener.NULL_LISTENER);
442+
_fsState._logger.run('Create unlinked for $path', () {
443+
if (apiSignatureBytes == null) {
444+
apiSignatureBytes = computeUnlinkedApiSignature(unit);
445+
_fsState._byteStore.put(apiSignatureKey, apiSignatureBytes);
446+
}
447+
if (unlinkedUnitBytes == null) {
448+
var unlinkedUnit = serializeAstUnlinked(unit,
438449
serializeInferrableFields: !enableOnePhaseSummaries);
439-
DefinedNames definedNames = computeDefinedNames(unit);
440-
List<String> referencedNames = computeReferencedNames(unit).toList();
441-
List<String> subtypedNames = computeSubtypedNames(unit).toList();
442-
bytes = new AnalysisDriverUnlinkedUnitBuilder(
450+
var definedNames = computeDefinedNames(unit);
451+
var referencedNames = computeReferencedNames(unit).toList();
452+
var subtypedNames = computeSubtypedNames(unit).toList();
453+
unlinkedUnitBytes = new AnalysisDriverUnlinkedUnitBuilder(
443454
unit: unlinkedUnit,
444455
definedTopLevelNames: definedNames.topLevelNames.toList(),
445456
definedClassMemberNames:
446457
definedNames.classMemberNames.toList(),
447458
referencedNames: referencedNames,
448459
subtypedNames: subtypedNames)
449460
.toBuffer();
450-
_fsState._byteStore.put(_unlinkedKey, bytes);
451-
});
452-
}
461+
_fsState._byteStore.put(unlinkedKey, unlinkedUnitBytes);
462+
}
463+
});
453464
}
454465

455466
// Read the unlinked bundle.
456-
_driverUnlinkedUnit = new AnalysisDriverUnlinkedUnit.fromBuffer(bytes);
467+
_driverUnlinkedUnit =
468+
new AnalysisDriverUnlinkedUnit.fromBuffer(unlinkedUnitBytes);
457469
_unlinked = _driverUnlinkedUnit.unit;
458470
_lineInfo = new LineInfo(_unlinked.lineStarts);
459471

@@ -465,10 +477,9 @@ class FileState {
465477
_topLevelDeclarations = null;
466478

467479
// Prepare API signature.
468-
List<int> newApiSignature = new Uint8List.fromList(_unlinked.apiSignature);
469480
bool apiSignatureChanged = _apiSignature != null &&
470-
!_equalByteLists(_apiSignature, newApiSignature);
471-
_apiSignature = newApiSignature;
481+
!_equalByteLists(_apiSignature, apiSignatureBytes);
482+
_apiSignature = apiSignatureBytes;
472483

473484
// The API signature changed.
474485
// Flush transitive signatures of affected files.
@@ -684,8 +695,6 @@ class FileStateTestView {
684695
final FileState file;
685696

686697
FileStateTestView(this.file);
687-
688-
String get unlinkedKey => file._unlinkedKey;
689698
}
690699

691700
/**
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/dart/ast/ast.dart';
6+
import 'package:analyzer/dart/ast/token.dart';
7+
import 'package:analyzer/src/dart/ast/token.dart';
8+
import 'package:analyzer/src/summary/api_signature.dart';
9+
10+
/// Return the bytes of the unlinked API signature of the given [unit].
11+
///
12+
/// If API signatures of two units are different, they may have different APIs.
13+
List<int> computeUnlinkedApiSignature(CompilationUnit unit) {
14+
var computer = new _UnitApiSignatureComputer();
15+
computer.compute(unit);
16+
return computer.signature.toByteList();
17+
}
18+
19+
class _UnitApiSignatureComputer {
20+
final signature = new ApiSignature();
21+
22+
void addClassOrMixin(ClassOrMixinDeclaration node) {
23+
addTokens(node.beginToken, node.leftBracket);
24+
25+
bool hasConstConstructor = node.members
26+
.any((m) => m is ConstructorDeclaration && m.constKeyword != null);
27+
28+
signature.addInt(node.members.length);
29+
for (var member in node.members) {
30+
if (member is ConstructorDeclaration) {
31+
var lastInitializer = member.constKeyword != null &&
32+
member.initializers != null &&
33+
member.initializers.isNotEmpty
34+
? member.initializers.last
35+
: null;
36+
addTokens(
37+
member.beginToken,
38+
(lastInitializer ?? member.parameters ?? member.name).endToken,
39+
);
40+
} else if (member is FieldDeclaration) {
41+
addVariables(member, member.fields, hasConstConstructor);
42+
} else if (member is MethodDeclaration) {
43+
addTokens(
44+
member.beginToken,
45+
(member.parameters ?? member.name).endToken,
46+
);
47+
} else {
48+
addNode(member);
49+
}
50+
}
51+
52+
addToken(node.rightBracket);
53+
}
54+
55+
void addNode(AstNode node) {
56+
addTokens(node.beginToken, node.endToken);
57+
}
58+
59+
void addToken(Token token) {
60+
signature.addString(token.lexeme);
61+
}
62+
63+
/// Appends tokens from [begin] (including), to [end] (also including).
64+
void addTokens(Token begin, Token end) {
65+
if (begin is CommentToken) {
66+
begin = (begin as CommentToken).parent;
67+
}
68+
Token token = begin;
69+
while (token != null) {
70+
addToken(token);
71+
if (token == end) {
72+
break;
73+
}
74+
token = token.next;
75+
}
76+
}
77+
78+
void addVariables(
79+
AstNode node,
80+
VariableDeclarationList variableList,
81+
bool includeFinalInitializers,
82+
) {
83+
if (variableList.type == null ||
84+
variableList.isConst ||
85+
variableList.isFinal && includeFinalInitializers) {
86+
addTokens(node.beginToken, node.endToken);
87+
} else {
88+
addTokens(node.beginToken, variableList.type.endToken);
89+
90+
signature.addInt(variableList.variables.length);
91+
for (var variable in variableList.variables) {
92+
addTokens(variable.beginToken, variable.name.endToken);
93+
addToken(variable.endToken.next); // `,` or `;`
94+
}
95+
}
96+
}
97+
98+
void compute(CompilationUnit unit) {
99+
signature.addInt(unit.directives.length);
100+
unit.directives.forEach(addNode);
101+
102+
signature.addInt(unit.declarations.length);
103+
for (var declaration in unit.declarations) {
104+
if (declaration is ClassOrMixinDeclaration) {
105+
addClassOrMixin(declaration);
106+
} else if (declaration is FunctionDeclaration) {
107+
var parameters = declaration.functionExpression.parameters;
108+
addTokens(
109+
declaration.beginToken,
110+
(parameters ?? declaration.name).endToken,
111+
);
112+
} else if (declaration is TopLevelVariableDeclaration) {
113+
addVariables(declaration, declaration.variables, false);
114+
} else {
115+
addNode(declaration);
116+
}
117+
}
118+
}
119+
}

pkg/analyzer/test/src/dart/analysis/file_state_test.dart

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -654,22 +654,6 @@ class C {
654654
expect(file.apiSignature, signature);
655655
}
656656

657-
test_store_zeroLengthUnlinked() {
658-
String path = _p('/test.dart');
659-
provider.newFile(path, 'class A {}');
660-
661-
// Get the file, prepare unlinked.
662-
FileState file = fileSystemState.getFileForPath(path);
663-
expect(file.unlinked, isNotNull);
664-
665-
// Make the unlinked unit in the byte store zero-length, damaged.
666-
byteStore.put(file.test.unlinkedKey, <int>[]);
667-
668-
// Refresh should not fail, zero bytes in the store are ignored.
669-
file.refresh();
670-
expect(file.unlinked, isNotNull);
671-
}
672-
673657
test_subtypedNames() {
674658
String path = _p('/test.dart');
675659
provider.newFile(path, r'''

pkg/analyzer/test/src/dart/analysis/test_all.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'referenced_names_test.dart' as referenced_names;
1818
import 'search_test.dart' as search;
1919
import 'session_helper_test.dart' as session_helper;
2020
import 'session_test.dart' as session;
21+
import 'unlinked_api_signature_test.dart' as unlinked_api_signature;
2122
import 'uri_converter_test.dart' as uri_converter;
2223

2324
main() {
@@ -36,6 +37,7 @@ main() {
3637
search.main();
3738
session_helper.main();
3839
session.main();
40+
unlinked_api_signature.main();
3941
uri_converter.main();
4042
}, name: 'analysis');
4143
}

0 commit comments

Comments
 (0)