| OLD | NEW |
| 1 import 'package:analyzer/src/generated/ast.dart'; | 1 import 'package:analyzer/src/generated/ast.dart'; |
| 2 import 'package:analyzer/src/generated/element.dart'; | 2 import 'package:analyzer/src/generated/element.dart'; |
| 3 import 'package:analyzer/src/generated/scanner.dart'; | 3 import 'package:analyzer/src/generated/scanner.dart'; |
| 4 import 'package:analyzer/src/generated/utilities_dart.dart'; | 4 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 5 | 5 |
| 6 int _computeArgIndex(AstNode containingNode, Object entity) { | 6 int _computeArgIndex(AstNode containingNode, Object entity) { |
| 7 var argList = containingNode; | 7 var argList = containingNode; |
| 8 if (argList is ArgumentList) { | 8 if (argList is ArgumentList) { |
| 9 NodeList<Expression> args = argList.arguments; | 9 NodeList<Expression> args = argList.arguments; |
| 10 for (int index = 0; index < args.length; ++index) { | 10 for (int index = 0; index < args.length; ++index) { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 } else if (entity is AstNode) { | 149 } else if (entity is AstNode) { |
| 150 // If the last token in the node isn't a candidate target, then | 150 // If the last token in the node isn't a candidate target, then |
| 151 // neither the node nor any of its descendants can possibly be the | 151 // neither the node nor any of its descendants can possibly be the |
| 152 // completion target, so we can skip the node entirely. | 152 // completion target, so we can skip the node entirely. |
| 153 if (!_isCandidateToken(entity.endToken, offset)) { | 153 if (!_isCandidateToken(entity.endToken, offset)) { |
| 154 continue; | 154 continue; |
| 155 } | 155 } |
| 156 | 156 |
| 157 // If the node is a candidate target, then we are done. | 157 // If the node is a candidate target, then we are done. |
| 158 if (_isCandidateNode(entity, offset)) { | 158 if (_isCandidateNode(entity, offset)) { |
| 159 // Check to see if the offset is in a preceeding comment |
| 160 Token commentToken = _getContainingCommentToken(entity, offset); |
| 161 if (commentToken != null) { |
| 162 entity = commentToken; |
| 163 // If the preceeding comment is dartdoc token then update |
| 164 // the containing node to be the dartdoc comment |
| 165 Comment docComment = |
| 166 _getContainingDocComment(containingNode, commentToken); |
| 167 if (docComment != null) { |
| 168 containingNode = docComment; |
| 169 } |
| 170 } |
| 159 return new CompletionTarget._(containingNode, entity); | 171 return new CompletionTarget._(containingNode, entity); |
| 160 } | 172 } |
| 161 | 173 |
| 162 // Otherwise, the completion target is somewhere inside the entity, | 174 // Otherwise, the completion target is somewhere inside the entity, |
| 163 // so we need to jump to the start of the outer loop to examine its | 175 // so we need to jump to the start of the outer loop to examine its |
| 164 // contents. | 176 // contents. |
| 165 containingNode = entity; | 177 containingNode = entity; |
| 166 continue outerLoop; | 178 continue outerLoop; |
| 167 } else { | 179 } else { |
| 168 // Unexpected entity found (all entities in a parse tree should be | 180 // Unexpected entity found (all entities in a parse tree should be |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 return _isFunctionalParameter(methodElem.parameters, argIndex); | 239 return _isFunctionalParameter(methodElem.parameters, argIndex); |
| 228 } else if (methodElem is FunctionElement) { | 240 } else if (methodElem is FunctionElement) { |
| 229 return _isFunctionalParameter(methodElem.parameters, argIndex); | 241 return _isFunctionalParameter(methodElem.parameters, argIndex); |
| 230 } | 242 } |
| 231 } | 243 } |
| 232 } | 244 } |
| 233 return false; | 245 return false; |
| 234 } | 246 } |
| 235 | 247 |
| 236 /** | 248 /** |
| 249 * Determine if the offset is contained in a preceeding comment token |
| 250 * and return that token, otherwise return `null`. |
| 251 */ |
| 252 static Token _getContainingCommentToken(AstNode node, int offset) { |
| 253 if (offset >= node.offset) { |
| 254 return null; |
| 255 } |
| 256 Token token = node.beginToken; |
| 257 if (token == null) { |
| 258 return null; |
| 259 } |
| 260 token = token.precedingComments; |
| 261 while (token != null) { |
| 262 if (offset <= token.offset) { |
| 263 return null; |
| 264 } |
| 265 if (offset <= token.end) { |
| 266 if (token.type == TokenType.SINGLE_LINE_COMMENT || offset < token.end) { |
| 267 return token; |
| 268 } |
| 269 } |
| 270 token = token.next; |
| 271 } |
| 272 return null; |
| 273 } |
| 274 |
| 275 /** |
| 276 * Determine if the given token is part of the given node's dart doc. |
| 277 */ |
| 278 static Comment _getContainingDocComment(AstNode node, Token token) { |
| 279 if (node is AnnotatedNode) { |
| 280 Comment docComment = node.documentationComment; |
| 281 if (docComment != null && docComment.tokens.contains(token)) { |
| 282 return docComment; |
| 283 } |
| 284 } |
| 285 return null; |
| 286 } |
| 287 |
| 288 /** |
| 237 * Determine whether [node] could possibly be the [entity] for a | 289 * Determine whether [node] could possibly be the [entity] for a |
| 238 * [CompletionTarget] associated with the given [offset]. | 290 * [CompletionTarget] associated with the given [offset]. |
| 239 */ | 291 */ |
| 240 static bool _isCandidateNode(AstNode node, int offset) { | 292 static bool _isCandidateNode(AstNode node, int offset) { |
| 241 // If the node's first token is a keyword or identifier, then the node is a | 293 // If the node's first token is a keyword or identifier, then the node is a |
| 242 // candidate entity if its first token is. | 294 // candidate entity if its first token is. |
| 243 Token beginToken = node.beginToken; | 295 Token beginToken = node.beginToken; |
| 244 if (beginToken.type == TokenType.KEYWORD || | 296 if (beginToken.type == TokenType.KEYWORD || |
| 245 beginToken.type == TokenType.IDENTIFIER) { | 297 beginToken.type == TokenType.IDENTIFIER) { |
| 246 return _isCandidateToken(beginToken, offset); | 298 return _isCandidateToken(beginToken, offset); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 if (param.parameterKind == ParameterKind.NAMED) { | 336 if (param.parameterKind == ParameterKind.NAMED) { |
| 285 // TODO(danrubel) handle named parameters | 337 // TODO(danrubel) handle named parameters |
| 286 return false; | 338 return false; |
| 287 } else { | 339 } else { |
| 288 return paramType is FunctionType || paramType is FunctionTypeAlias; | 340 return paramType is FunctionType || paramType is FunctionTypeAlias; |
| 289 } | 341 } |
| 290 } | 342 } |
| 291 return false; | 343 return false; |
| 292 } | 344 } |
| 293 } | 345 } |
| OLD | NEW |