Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: pkg/analyzer/test/src/task/strong/strong_test_helper.dart

Issue 1686173002: fix #25739, incorrectly expanding a generic comment multiple times (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // TODO(jmesserly): this file needs to be refactored, it's a port from 5 // TODO(jmesserly): this file needs to be refactored, it's a port from
6 // package:dev_compiler's tests 6 // package:dev_compiler's tests
7 library analyzer.test.src.task.strong.strong_test_helper; 7 library analyzer.test.src.task.strong.strong_test_helper;
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 new SourceFactory([new DartUriResolver(new MockSdk()), uriResolver]); 67 new SourceFactory([new DartUriResolver(new MockSdk()), uriResolver]);
68 68
69 // Run the checker on /main.dart. 69 // Run the checker on /main.dart.
70 Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart')); 70 Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart'));
71 var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource); 71 var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource);
72 72
73 var collector = new _ErrorCollector(); 73 var collector = new _ErrorCollector();
74 74
75 // Extract expectations from the comments in the test files, and 75 // Extract expectations from the comments in the test files, and
76 // check that all errors we emit are included in the expected map. 76 // check that all errors we emit are included in the expected map.
77 var allLibraries = reachableLibraries(initialLibrary.element.library); 77 var allLibraries = _reachableLibraries(initialLibrary.element.library);
78 for (var lib in allLibraries) { 78 for (var lib in allLibraries) {
79 for (var unit in lib.units) { 79 for (var unit in lib.units) {
80 var errors = <AnalysisError>[]; 80 var errors = <AnalysisError>[];
81 collector.errors = errors; 81 collector.errors = errors;
82 82
83 var source = unit.source; 83 var source = unit.source;
84 if (source.uri.scheme == 'dart') continue; 84 if (source.uri.scheme == 'dart') continue;
85 85
86 var librarySource = context.getLibrariesContaining(source).single; 86 var librarySource = context.getLibrariesContaining(source).single;
87 var resolved = context.resolveCompilationUnit2(source, librarySource); 87 var resolved = context.resolveCompilationUnit2(source, librarySource);
88 errors.addAll(context.getErrors(source).errors.where((e) => 88 errors.addAll(context.getErrors(source).errors.where((e) =>
89 e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE && 89 e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE &&
90 // TODO(jmesserly): these are usually intentional dynamic calls. 90 // TODO(jmesserly): these are usually intentional dynamic calls.
91 e.errorCode.name != 'UNDEFINED_METHOD')); 91 e.errorCode.name != 'UNDEFINED_METHOD'));
92 92
93 _expectErrors(resolved, errors); 93 _expectErrors(resolved, errors);
94 } 94 }
95 } 95 }
96 } 96 }
97 97
98 /// Adds a file using [addFile] and calls [check]. 98 /// Adds a file using [addFile] and calls [check].
99 void checkFile(String content) { 99 void checkFile(String content) {
100 addFile(content); 100 addFile(content);
101 check(); 101 check();
102 } 102 }
103 103
104 SourceSpanWithContext createSpanHelper( 104 SourceSpanWithContext _createSpanHelper(
105 LineInfo lineInfo, int start, Source source, String content, 105 LineInfo lineInfo, int start, Source source, String content,
106 {int end}) { 106 {int end}) {
107 var startLoc = locationForOffset(lineInfo, source.uri, start); 107 var startLoc = _locationForOffset(lineInfo, source.uri, start);
108 var endLoc = locationForOffset(lineInfo, source.uri, end ?? start); 108 var endLoc = _locationForOffset(lineInfo, source.uri, end ?? start);
109 109
110 var lineStart = startLoc.offset - startLoc.column; 110 var lineStart = startLoc.offset - startLoc.column;
111 // Find the end of the line. This is not exposed directly on LineInfo, but 111 // Find the end of the line. This is not exposed directly on LineInfo, but
112 // we can find it pretty easily. 112 // we can find it pretty easily.
113 // TODO(jmesserly): for now we do the simple linear scan. Ideally we can get 113 // TODO(jmesserly): for now we do the simple linear scan. Ideally we can get
114 // some help from the LineInfo API. 114 // some help from the LineInfo API.
115 int lineEnd = endLoc.offset; 115 int lineEnd = endLoc.offset;
116 int lineNum = lineInfo.getLocation(lineEnd).lineNumber; 116 int lineNum = lineInfo.getLocation(lineEnd).lineNumber;
117 while (lineEnd < content.length && 117 while (lineEnd < content.length &&
118 lineInfo.getLocation(++lineEnd).lineNumber == lineNum); 118 lineInfo.getLocation(++lineEnd).lineNumber == lineNum);
119 119
120 if (end == null) { 120 if (end == null) {
121 end = lineEnd; 121 end = lineEnd;
122 endLoc = locationForOffset(lineInfo, source.uri, lineEnd); 122 endLoc = _locationForOffset(lineInfo, source.uri, lineEnd);
123 } 123 }
124 124
125 var text = content.substring(start, end); 125 var text = content.substring(start, end);
126 var lineText = content.substring(lineStart, lineEnd); 126 var lineText = content.substring(lineStart, lineEnd);
127 return new SourceSpanWithContext(startLoc, endLoc, text, lineText); 127 return new SourceSpanWithContext(startLoc, endLoc, text, lineText);
128 } 128 }
129 129
130 String _errorCodeName(ErrorCode errorCode) { 130 String _errorCodeName(ErrorCode errorCode) {
131 var name = errorCode.name; 131 var name = errorCode.name;
132 final prefix = 'STRONG_MODE_'; 132 final prefix = 'STRONG_MODE_';
133 if (name.startsWith(prefix)) { 133 if (name.startsWith(prefix)) {
134 return name.substring(prefix.length); 134 return name.substring(prefix.length);
135 } else { 135 } else {
136 return name; 136 return name;
137 } 137 }
138 } 138 }
139 139
140 initStrongModeTests() { 140 void initStrongModeTests() {
141 setUp(() { 141 setUp(() {
142 AnalysisEngine.instance.processRequiredPlugins(); 142 AnalysisEngine.instance.processRequiredPlugins();
143 files = new MemoryResourceProvider(); 143 files = new MemoryResourceProvider();
144 _checkCalled = false; 144 _checkCalled = false;
145 }); 145 });
146 146
147 tearDown(() { 147 tearDown(() {
148 // This is a sanity check, in case only addFile is called. 148 // This is a sanity check, in case only addFile is called.
149 expect(_checkCalled, true, reason: 'must call check() method in test case'); 149 expect(_checkCalled, true, reason: 'must call check() method in test case');
150 files = null; 150 files = null;
151 }); 151 });
152 } 152 }
153 153
154 // TODO(jmesserly): can we reuse the same mock SDK as Analyzer tests? 154 SourceLocation _locationForOffset(LineInfo lineInfo, Uri uri, int offset) {
155 SourceLocation locationForOffset(LineInfo lineInfo, Uri uri, int offset) {
156 var loc = lineInfo.getLocation(offset); 155 var loc = lineInfo.getLocation(offset);
157 return new SourceLocation(offset, 156 return new SourceLocation(offset,
158 sourceUrl: uri, line: loc.lineNumber - 1, column: loc.columnNumber - 1); 157 sourceUrl: uri, line: loc.lineNumber - 1, column: loc.columnNumber - 1);
159 } 158 }
160 159
161 /// Returns all libraries transitively imported or exported from [start]. 160 /// Returns all libraries transitively imported or exported from [start].
162 List<LibraryElement> reachableLibraries(LibraryElement start) { 161 List<LibraryElement> _reachableLibraries(LibraryElement start) {
163 var results = <LibraryElement>[]; 162 var results = <LibraryElement>[];
164 var seen = new Set(); 163 var seen = new Set();
165 void find(LibraryElement lib) { 164 void find(LibraryElement lib) {
166 if (seen.contains(lib)) return; 165 if (seen.contains(lib)) return;
167 seen.add(lib); 166 seen.add(lib);
168 results.add(lib); 167 results.add(lib);
169 lib.importedLibraries.forEach(find); 168 lib.importedLibraries.forEach(find);
170 lib.exportedLibraries.forEach(find); 169 lib.exportedLibraries.forEach(find);
171 } 170 }
172 find(start); 171 find(start);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 229
231 List<_ErrorExpectation> _findExpectedErrors(Token beginToken) { 230 List<_ErrorExpectation> _findExpectedErrors(Token beginToken) {
232 var expectedErrors = <_ErrorExpectation>[]; 231 var expectedErrors = <_ErrorExpectation>[];
233 232
234 // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens. 233 // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens.
235 for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) { 234 for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) {
236 for (CommentToken c = t.precedingComments; c != null; c = c.next) { 235 for (CommentToken c = t.precedingComments; c != null; c = c.next) {
237 if (c.type == TokenType.MULTI_LINE_COMMENT) { 236 if (c.type == TokenType.MULTI_LINE_COMMENT) {
238 String value = c.lexeme.substring(2, c.lexeme.length - 2); 237 String value = c.lexeme.substring(2, c.lexeme.length - 2);
239 if (value.contains(':')) { 238 if (value.contains(':')) {
240 var offset = c.end; 239 int offset = t.offset;
241 if (c.next?.type == TokenType.GENERIC_METHOD_TYPE_LIST) { 240 Token previous = t.previous;
242 offset += 2; 241 while (previous != null && previous.offset > c.offset) {
242 offset = previous.offset;
243 previous = previous.previous;
243 } 244 }
244 for (var expectCode in value.split(',')) { 245 for (var expectCode in value.split(',')) {
245 var expected = _ErrorExpectation.parse(offset, expectCode); 246 var expected = _ErrorExpectation.parse(offset, expectCode);
246 if (expected != null) { 247 if (expected != null) {
247 expectedErrors.add(expected); 248 expectedErrors.add(expected);
248 } 249 }
249 } 250 }
250 } 251 }
251 } 252 }
252 } 253 }
253 } 254 }
254 return expectedErrors; 255 return expectedErrors;
255 } 256 }
256 257
257 void _reportFailure( 258 void _reportFailure(
258 CompilationUnit unit, 259 CompilationUnit unit,
259 List<_ErrorExpectation> unreported, 260 List<_ErrorExpectation> unreported,
260 List<AnalysisError> unexpected, 261 List<AnalysisError> unexpected,
261 Map<_ErrorExpectation, AnalysisError> different) { 262 Map<_ErrorExpectation, AnalysisError> different) {
262 // Get the source code. This reads the data again, but it's safe because 263 // Get the source code. This reads the data again, but it's safe because
263 // all tests use memory file system. 264 // all tests use memory file system.
264 var sourceCode = unit.element.source.contents.data; 265 var sourceCode = unit.element.source.contents.data;
265 266
266 String formatActualError(AnalysisError error) { 267 String formatActualError(AnalysisError error) {
267 int offset = error.offset; 268 int offset = error.offset;
268 int length = error.length; 269 int length = error.length;
269 var span = createSpanHelper( 270 var span = _createSpanHelper(
270 unit.lineInfo, offset, unit.element.source, sourceCode, 271 unit.lineInfo, offset, unit.element.source, sourceCode,
271 end: offset + length); 272 end: offset + length);
272 var levelName = _actualErrorLevel(error).name.toLowerCase(); 273 var levelName = _actualErrorLevel(error).name.toLowerCase();
273 return '@$offset $levelName:${_errorCodeName(error.errorCode)}\n' + 274 return '@$offset $levelName:${_errorCodeName(error.errorCode)}\n' +
274 span.message(error.message); 275 span.message(error.message);
275 } 276 }
276 277
277 String formatExpectedError(_ErrorExpectation error) { 278 String formatExpectedError(_ErrorExpectation error) {
278 int offset = error.offset; 279 int offset = error.offset;
279 var span = createSpanHelper( 280 var span = _createSpanHelper(
280 unit.lineInfo, offset, unit.element.source, sourceCode); 281 unit.lineInfo, offset, unit.element.source, sourceCode);
281 var levelName = error.level.toString().toLowerCase(); 282 var levelName = error.level.toString().toLowerCase();
282 return '@$offset $levelName:${error.typeName}\n' + span.message(''); 283 return '@$offset $levelName:${error.typeName}\n' + span.message('');
283 } 284 }
284 285
285 var message = new StringBuffer(); 286 var message = new StringBuffer();
286 if (unreported.isNotEmpty) { 287 if (unreported.isNotEmpty) {
287 message.writeln('Expected errors that were not reported:'); 288 message.writeln('Expected errors that were not reported:');
288 unreported.map(formatExpectedError).forEach(message.writeln); 289 unreported.map(formatExpectedError).forEach(message.writeln);
289 message.writeln(); 290 message.writeln();
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 378
378 @override 379 @override
379 Source resolveAbsolute(Uri uri, [Uri actualUri]) { 380 Source resolveAbsolute(Uri uri, [Uri actualUri]) {
380 if (uri.scheme == 'package') { 381 if (uri.scheme == 'package') {
381 return (provider.getResource('/packages/' + uri.path) as File) 382 return (provider.getResource('/packages/' + uri.path) as File)
382 .createSource(uri); 383 .createSource(uri);
383 } 384 }
384 return super.resolveAbsolute(uri, actualUri); 385 return super.resolveAbsolute(uri, actualUri);
385 } 386 }
386 } 387 }
OLDNEW
« pkg/analyzer/lib/src/generated/parser.dart ('K') | « pkg/analyzer/test/generated/parser_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698