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

Side by Side Diff: pkg/analyzer/lib/src/generated/parser.dart

Issue 2990383002: Emit a hint when using generic method comment syntax (issue 30356) (Closed)
Patch Set: Created 3 years, 4 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 library analyzer.parser; 5 library analyzer.parser;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import "dart:math" as math; 8 import "dart:math" as math;
9 9
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 5174 matching lines...) Expand 10 before | Expand all | Expand 10 after
5185 } else { 5185 } else {
5186 type = parseTypeWithoutFunction(inExpression); 5186 type = parseTypeWithoutFunction(inExpression);
5187 } 5187 }
5188 while (_atGenericFunctionTypeAfterReturnType(_currentToken)) { 5188 while (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
5189 type = parseGenericFunctionTypeAfterReturnType(type); 5189 type = parseGenericFunctionTypeAfterReturnType(type);
5190 } 5190 }
5191 return type; 5191 return type;
5192 } 5192 }
5193 5193
5194 /** 5194 /**
5195 * Parse a type which is not `void`.
5196 *
5197 * typeNotVoid ::=
5198 * functionType
5199 * | typeNotVoidWithoutFunction
5200 */
5201 TypeAnnotation parseTypeNotVoid(bool inExpression) {
5202 TypeAnnotation type = null;
5203 if (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
5204 // Generic function type with no return type.
5205 type = parseGenericFunctionTypeAfterReturnType(null);
5206 } else if (_currentToken.keyword == Keyword.VOID &&
5207 _atGenericFunctionTypeAfterReturnType(_currentToken.next)) {
5208 type = astFactory.typeName(
5209 astFactory.simpleIdentifier(getAndAdvance()), null);
5210 } else {
5211 type = parseTypeName(inExpression);
5212 }
5213 while (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
5214 type = parseGenericFunctionTypeAfterReturnType(type);
5215 }
5216 return type;
5217 }
5218
5219 /**
5220 * Parse a type which is not a function type.
5221 *
5222 * typeWithoutFunction ::=
5223 * `void`
5224 * | typeNotVoidWithoutFunction
5225 */
5226 TypeAnnotation parseTypeWithoutFunction(bool inExpression) {
5227 if (_currentToken.keyword == Keyword.VOID) {
5228 return astFactory.typeName(
5229 astFactory.simpleIdentifier(getAndAdvance()), null);
5230 } else {
5231 return parseTypeName(inExpression);
5232 }
5233 }
5234
5235 /**
5236 * Parse a list of type arguments. Return the type argument list that was 5195 * Parse a list of type arguments. Return the type argument list that was
5237 * parsed. 5196 * parsed.
5238 * 5197 *
5239 * This method assumes that the current token matches `TokenType.LT`. 5198 * This method assumes that the current token matches `TokenType.LT`.
5240 * 5199 *
5241 * typeArguments ::= 5200 * typeArguments ::=
5242 * '<' typeList '>' 5201 * '<' typeList '>'
5243 * 5202 *
5244 * typeList ::= 5203 * typeList ::=
5245 * type (',' type)* 5204 * type (',' type)*
(...skipping 23 matching lines...) Expand all
5269 TypeName realType = _parseTypeName(inExpression); 5228 TypeName realType = _parseTypeName(inExpression);
5270 // If this is followed by a generic method type comment, allow the comment 5229 // If this is followed by a generic method type comment, allow the comment
5271 // type to replace the real type name. 5230 // type to replace the real type name.
5272 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to 5231 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
5273 // only work inside generic methods? 5232 // only work inside generic methods?
5274 TypeName typeFromComment = _parseOptionalTypeNameComment(); 5233 TypeName typeFromComment = _parseOptionalTypeNameComment();
5275 return typeFromComment ?? realType; 5234 return typeFromComment ?? realType;
5276 } 5235 }
5277 5236
5278 /** 5237 /**
5238 * Parse a type which is not `void`.
5239 *
5240 * typeNotVoid ::=
5241 * functionType
5242 * | typeNotVoidWithoutFunction
5243 */
5244 TypeAnnotation parseTypeNotVoid(bool inExpression) {
5245 TypeAnnotation type = null;
5246 if (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
5247 // Generic function type with no return type.
5248 type = parseGenericFunctionTypeAfterReturnType(null);
5249 } else if (_currentToken.keyword == Keyword.VOID &&
5250 _atGenericFunctionTypeAfterReturnType(_currentToken.next)) {
5251 type = astFactory.typeName(
5252 astFactory.simpleIdentifier(getAndAdvance()), null);
5253 } else {
5254 type = parseTypeName(inExpression);
5255 }
5256 while (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
5257 type = parseGenericFunctionTypeAfterReturnType(type);
5258 }
5259 return type;
5260 }
5261
5262 /**
5279 * Parse a type parameter. Return the type parameter that was parsed. 5263 * Parse a type parameter. Return the type parameter that was parsed.
5280 * 5264 *
5281 * typeParameter ::= 5265 * typeParameter ::=
5282 * metadata name ('extends' bound)? 5266 * metadata name ('extends' bound)?
5283 */ 5267 */
5284 TypeParameter parseTypeParameter() { 5268 TypeParameter parseTypeParameter() {
5285 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); 5269 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
5286 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 5270 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
5287 if (_matches(TokenType.QUESTION)) { 5271 if (_matches(TokenType.QUESTION)) {
5288 _reportErrorForCurrentToken(ParserErrorCode.NULLABLE_TYPE_PARAMETER); 5272 _reportErrorForCurrentToken(ParserErrorCode.NULLABLE_TYPE_PARAMETER);
(...skipping 23 matching lines...) Expand all
5312 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()]; 5296 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
5313 while (_optional(TokenType.COMMA)) { 5297 while (_optional(TokenType.COMMA)) {
5314 typeParameters.add(parseTypeParameter()); 5298 typeParameters.add(parseTypeParameter());
5315 } 5299 }
5316 Token rightBracket = _expectGt(); 5300 Token rightBracket = _expectGt();
5317 return astFactory.typeParameterList( 5301 return astFactory.typeParameterList(
5318 leftBracket, typeParameters, rightBracket); 5302 leftBracket, typeParameters, rightBracket);
5319 } 5303 }
5320 5304
5321 /** 5305 /**
5306 * Parse a type which is not a function type.
5307 *
5308 * typeWithoutFunction ::=
5309 * `void`
5310 * | typeNotVoidWithoutFunction
5311 */
5312 TypeAnnotation parseTypeWithoutFunction(bool inExpression) {
5313 if (_currentToken.keyword == Keyword.VOID) {
5314 return astFactory.typeName(
5315 astFactory.simpleIdentifier(getAndAdvance()), null);
5316 } else {
5317 return parseTypeName(inExpression);
5318 }
5319 }
5320
5321 /**
5322 * Parse a unary expression. Return the unary expression that was parsed. 5322 * Parse a unary expression. Return the unary expression that was parsed.
5323 * 5323 *
5324 * unaryExpression ::= 5324 * unaryExpression ::=
5325 * prefixOperator unaryExpression 5325 * prefixOperator unaryExpression
5326 * | awaitExpression 5326 * | awaitExpression
5327 * | postfixExpression 5327 * | postfixExpression
5328 * | unaryOperator 'super' 5328 * | unaryOperator 'super'
5329 * | '-' 'super' 5329 * | '-' 'super'
5330 * | incrementOperator assignableExpression 5330 * | incrementOperator assignableExpression
5331 */ 5331 */
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after
5683 } else { 5683 } else {
5684 next = skipTypeWithoutFunction(startToken); 5684 next = skipTypeWithoutFunction(startToken);
5685 } 5685 }
5686 while (next != null && _atGenericFunctionTypeAfterReturnType(next)) { 5686 while (next != null && _atGenericFunctionTypeAfterReturnType(next)) {
5687 next = skipGenericFunctionTypeAfterReturnType(next); 5687 next = skipGenericFunctionTypeAfterReturnType(next);
5688 } 5688 }
5689 return next; 5689 return next;
5690 } 5690 }
5691 5691
5692 /** 5692 /**
5693 * Parse a typeWithoutFunction, starting at the [startToken], without actually
5694 * creating a TypeAnnotation or changing the current token. Return the token
5695 * following the typeWithoutFunction that was parsed, or `null` if the given
5696 * token is not the first token in a valid typeWithoutFunction.
5697 *
5698 * This method must be kept in sync with [parseTypeWithoutFunction].
5699 */
5700 Token skipTypeWithoutFunction(Token startToken) {
5701 if (startToken.keyword == Keyword.VOID) {
5702 return startToken.next;
5703 } else {
5704 return skipTypeName(startToken);
5705 }
5706 }
5707
5708 /**
5709 * Parse a list of type arguments, starting at the [startToken], without 5693 * Parse a list of type arguments, starting at the [startToken], without
5710 * actually creating a type argument list or changing the current token. 5694 * actually creating a type argument list or changing the current token.
5711 * Return the token following the type argument list that was parsed, or 5695 * Return the token following the type argument list that was parsed, or
5712 * `null` if the given token is not the first token in a valid type argument 5696 * `null` if the given token is not the first token in a valid type argument
5713 * list. 5697 * list.
5714 * 5698 *
5715 * This method must be kept in sync with [parseTypeArgumentList]. 5699 * This method must be kept in sync with [parseTypeArgumentList].
5716 * 5700 *
5717 * typeArguments ::= 5701 * typeArguments ::=
5718 * '<' typeList '>' 5702 * '<' typeList '>'
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
5798 return next.next; 5782 return next.next;
5799 } 5783 }
5800 } 5784 }
5801 previous = next; 5785 previous = next;
5802 next = next.next; 5786 next = next.next;
5803 } 5787 }
5804 return null; 5788 return null;
5805 } 5789 }
5806 5790
5807 /** 5791 /**
5792 * Parse a typeWithoutFunction, starting at the [startToken], without actually
5793 * creating a TypeAnnotation or changing the current token. Return the token
5794 * following the typeWithoutFunction that was parsed, or `null` if the given
5795 * token is not the first token in a valid typeWithoutFunction.
5796 *
5797 * This method must be kept in sync with [parseTypeWithoutFunction].
5798 */
5799 Token skipTypeWithoutFunction(Token startToken) {
5800 if (startToken.keyword == Keyword.VOID) {
5801 return startToken.next;
5802 } else {
5803 return skipTypeName(startToken);
5804 }
5805 }
5806
5807 /**
5808 * Advance to the next token in the token stream. 5808 * Advance to the next token in the token stream.
5809 */ 5809 */
5810 void _advance() { 5810 void _advance() {
5811 _currentToken = _currentToken.next; 5811 _currentToken = _currentToken.next;
5812 } 5812 }
5813 5813
5814 /** 5814 /**
5815 * Append the character equivalent of the given [codePoint] to the given 5815 * Append the character equivalent of the given [codePoint] to the given
5816 * [builder]. Use the [startIndex] and [endIndex] to report an error, and 5816 * [builder]. Use the [startIndex] and [endIndex] to report an error, and
5817 * don't append anything to the builder, if the code point is invalid. The 5817 * don't append anything to the builder, if the code point is invalid. The
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
6149 } 6149 }
6150 6150
6151 bool _injectGenericComment(TokenType type, int prefixLen) { 6151 bool _injectGenericComment(TokenType type, int prefixLen) {
6152 if (parseGenericMethodComments) { 6152 if (parseGenericMethodComments) {
6153 CommentToken t = _currentToken.precedingComments; 6153 CommentToken t = _currentToken.precedingComments;
6154 for (; t != null; t = t.next) { 6154 for (; t != null; t = t.next) {
6155 if (t.type == type) { 6155 if (t.type == type) {
6156 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2); 6156 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
6157 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen); 6157 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
6158 if (list != null) { 6158 if (list != null) {
6159 _reportErrorForToken(HintCode.GENERIC_METHOD_COMMENT, t);
6159 // Remove the token from the comment stream. 6160 // Remove the token from the comment stream.
6160 t.remove(); 6161 t.remove();
6161 // Insert the tokens into the stream. 6162 // Insert the tokens into the stream.
6162 _injectTokenList(list); 6163 _injectTokenList(list);
6163 return true; 6164 return true;
6164 } 6165 }
6165 } 6166 }
6166 } 6167 }
6167 } 6168 }
6168 return false; 6169 return false;
(...skipping 2479 matching lines...) Expand 10 before | Expand all | Expand 10 after
8648 } 8649 }
8649 } 8650 }
8650 } 8651 }
8651 8652
8652 /** 8653 /**
8653 * Instances of this class are thrown when the parser detects that AST has 8654 * Instances of this class are thrown when the parser detects that AST has
8654 * too many nested expressions to be parsed safely and avoid possibility of 8655 * too many nested expressions to be parsed safely and avoid possibility of
8655 * [StackOverflowError] in the parser or during later analysis. 8656 * [StackOverflowError] in the parser or during later analysis.
8656 */ 8657 */
8657 class _TooDeepTreeError {} 8658 class _TooDeepTreeError {}
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/dart/error/hint_codes.dart ('k') | pkg/analyzer/test/generated/compile_time_error_code_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698