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

Side by Side Diff: pkg/analysis_services/lib/src/correction/fix.dart

Issue 405483007: More fixes in the Fixes service. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 // This code was auto-generated, is not intended to be edited, and is subject to
6 // significant change. Please see the README file for more information.
7
8 library services.src.correction.fix;
9
10 import 'package:analysis_services/correction/change.dart';
11 import 'package:analysis_services/correction/fix.dart';
12 import 'package:analysis_services/search/search_engine.dart';
13 import 'package:analysis_services/src/correction/name_suggestion.dart';
14 import 'package:analysis_services/src/correction/source_buffer.dart';
15 import 'package:analysis_services/src/correction/source_range.dart' as rf;
16 import 'package:analysis_services/src/correction/util.dart';
17 import 'package:analyzer/src/generated/ast.dart';
18 import 'package:analyzer/src/generated/element.dart';
19 import 'package:analyzer/src/generated/error.dart';
20 import 'package:analyzer/src/generated/java_core.dart';
21 import 'package:analyzer/src/generated/parser.dart';
22 import 'package:analyzer/src/generated/source.dart';
23 import 'package:analyzer/src/generated/utilities_dart.dart';
24
25
26 /**
27 * The computer for Dart fixes.
28 */
29 class FixProcessor {
30 final SearchEngine searchEngine;
31 final String file;
32 final CompilationUnit unit;
33 final AnalysisError error;
34
35 final List<Edit> edits = <Edit>[];
36 final Map<String, PositionGroup> positionGroups = <String, PositionGroup>{};
37 final List<Fix> fixes = <Fix>[];
38
39 CorrectionUtils utils;
40 int errorOffset;
41 int errorLength;
42 int errorEnd;
43 AstNode node;
44 AstNode coveredNode;
45
46
47 FixProcessor(this.searchEngine, this.file, this.unit, this.error);
48
49 List<Fix> compute() {
50 utils = new CorrectionUtils(unit);
51 errorOffset = error.offset;
52 errorLength = error.length;
53 errorEnd = errorOffset + errorLength;
54 node = new NodeLocator.con1(errorOffset).searchWithin(unit);
55 coveredNode = new NodeLocator.con2(
56 errorOffset,
57 errorOffset + errorLength).searchWithin(unit);
58 // analyze ErrorCode
59 ErrorCode errorCode = error.errorCode;
60 if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
61 _addFix_boolInsteadOfBoolean();
62 }
63 if (errorCode ==
64 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE) {
65 _addFix_replaceWithConstInstanceCreation();
66 }
67 if (errorCode ==
68 CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT) {
69 _addFix_createConstructorSuperExplicit();
70 }
71 // if (identical(
72 // errorCode,
73 // CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT)) {
74 // _addFix_createConstructorSuperImplicit();
75 // }
76 if (errorCode ==
77 CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT) {
78 _addFix_createConstructorSuperExplicit();
79 }
80 // if (identical(errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST)) {
81 // _addFix_createPart();
82 // _addFix_addPackageDependency();
83 // }
84 if (errorCode == HintCode.DIVISION_OPTIMIZATION) {
85 _addFix_useEffectiveIntegerDivision();
86 }
87 if (errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL) {
88 _addFix_isNotNull();
89 }
90 if (errorCode == HintCode.TYPE_CHECK_IS_NULL) {
91 _addFix_isNull();
92 }
93 if (errorCode == HintCode.UNNECESSARY_CAST) {
94 _addFix_removeUnnecessaryCast();
95 }
96 if (errorCode == HintCode.UNUSED_IMPORT) {
97 _addFix_removeUnusedImport();
98 }
99 if (errorCode == ParserErrorCode.EXPECTED_TOKEN) {
100 _addFix_insertSemicolon();
101 }
102 if (errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS) {
103 _addFix_removeParameters_inGetterDeclaration();
104 }
105 if (errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER) {
106 _addFix_makeEnclosingClassAbstract();
107 }
108 if (errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) {
109 _addFix_createConstructor_insteadOfSyntheticDefault();
110 }
111 if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
112 _addFix_createConstructor_named();
113 }
114 if (errorCode ==
115 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
116 errorCode ==
117 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
118 errorCode ==
119 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
120 errorCode ==
121 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR | |
122 errorCode ==
123 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_P LUS) {
124 // make class abstract
125 _addFix_makeEnclosingClassAbstract();
126 // implement methods
127 AnalysisErrorWithProperties errorWithProperties =
128 error as AnalysisErrorWithProperties;
129 Object property =
130 errorWithProperties.getProperty(ErrorProperty.UNIMPLEMENTED_METHODS);
131 List<ExecutableElement> missingOverrides =
132 property as List<ExecutableElement>;
133 _addFix_createMissingOverrides(missingOverrides);
134 _addFix_createNoSuchMethod();
135 }
136 if (errorCode == StaticWarningCode.UNDEFINED_CLASS) {
137 _addFix_importLibrary_withType();
138 _addFix_createClass();
139 _addFix_undefinedClass_useSimilar();
140 }
141 // if (identical(errorCode, StaticWarningCode.UNDEFINED_IDENTIFIER)) {
142 // _addFix_createFunction_forFunctionType();
143 // _addFix_importLibrary_withType();
144 // _addFix_importLibrary_withTopLevelVariable();
145 // }
146 if (errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER) {
147 _addFix_useStaticAccess_method();
148 _addFix_useStaticAccess_property();
149 }
150 if (errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) {
151 _addFix_removeParentheses_inGetterInvocation();
152 }
153 // if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_FUNCTION)) {
154 // _addFix_importLibrary_withFunction();
155 // _addFix_undefinedFunction_useSimilar();
156 // _addFix_undefinedFunction_create();
157 // }
158 // if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_GETTER)) {
159 // _addFix_createFunction_forFunctionType();
160 // }
161 // if (identical(errorCode, HintCode.UNDEFINED_METHOD) ||
162 // identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
163 // _addFix_undefinedMethod_useSimilar();
164 // _addFix_undefinedMethod_create();
165 // _addFix_undefinedFunction_create();
166 // }
167 // done
168 return fixes;
169 }
170
171 void _addFix(FixKind kind, List args, {String fixFile}) {
172 if (fixFile == null) {
173 fixFile = file;
174 }
175 FileEdit fileEdit = new FileEdit(file);
176 edits.forEach((edit) => fileEdit.add(edit));
177 // prepare Change
178 String message = JavaString.format(kind.message, args);
179 Change change = new Change(message);
180 change.add(fileEdit);
181 positionGroups.values.forEach((group) => change.addPositionGroup(group));
182 // add Fix
183 Fix fix = new Fix(kind, change);
184 fixes.add(fix);
185 }
186
187 void _addFix_addPackageDependency() {
188 // TODO(scheglov) implement
189 // if (node is SimpleStringLiteral && node.parent is NamespaceDirective) {
190 // SimpleStringLiteral uriLiteral = node as SimpleStringLiteral;
191 // String uriString = uriLiteral.value;
192 // // we need package: import
193 // if (!uriString.startsWith("package:")) {
194 // return;
195 // }
196 // // prepare package name
197 // String packageName = StringUtils.removeStart(uriString, "package:");
198 // packageName = StringUtils.substringBefore(packageName, "/");
199 // // add proposal
200 // _proposals.add(
201 // new AddDependencyCorrectionProposal(
202 // _unitFile,
203 // packageName,
204 // FixKind.ADD_PACKAGE_DEPENDENCY,
205 // [packageName]));
206 // }
207 }
208
209 void _addFix_boolInsteadOfBoolean() {
210 SourceRange range = rf.rangeError(error);
211 _addReplaceEdit(range, "bool");
212 _addFix(FixKind.REPLACE_BOOLEAN_WITH_BOOL, []);
213 }
214
215
216 void _addFix_createClass() {
217 if (_mayBeTypeIdentifier(node)) {
218 String name = (node as SimpleIdentifier).name;
219 // prepare environment
220 String eol = utils.endOfLine;
221 CompilationUnitMember enclosingMember =
222 node.getAncestor((node) => node is CompilationUnitMember);
223 int offset = enclosingMember.end;
224 String prefix = "";
225 // prepare source
226 SourceBuilder sb = new SourceBuilder(file, offset);
227 {
228 sb.append("${eol}${eol}");
229 sb.append(prefix);
230 // "class"
231 sb.append("class ");
232 // append name
233 {
234 sb.startPosition("NAME");
235 sb.append(name);
236 sb.endPosition();
237 }
238 // no members
239 sb.append(" {");
240 sb.append(eol);
241 sb.append("}");
242 }
243 // insert source
244 _insertBuilder(sb);
245 _addLinkedPosition("NAME", rf.rangeNode(node));
246 // add proposal
247 _addFix(FixKind.CREATE_CLASS, [name]);
248 }
249 }
250
251
252 void _addFix_createConstructorSuperExplicit() {
253 ConstructorDeclaration targetConstructor =
254 node.parent as ConstructorDeclaration;
255 ClassDeclaration targetClassNode =
256 targetConstructor.parent as ClassDeclaration;
257 ClassElement targetClassElement = targetClassNode.element;
258 ClassElement superClassElement = targetClassElement.supertype.element;
259 // add proposals for all super constructors
260 List<ConstructorElement> superConstructors = superClassElement.constructors;
261 for (ConstructorElement superConstructor in superConstructors) {
262 String constructorName = superConstructor.name;
263 // skip private
264 if (Identifier.isPrivateName(constructorName)) {
265 continue;
266 }
267 // prepare SourceBuilder
268 SourceBuilder sb;
269 {
270 List<ConstructorInitializer> initializers =
271 targetConstructor.initializers;
272 if (initializers.isEmpty) {
273 int insertOffset = targetConstructor.parameters.end;
274 sb = new SourceBuilder(file, insertOffset);
275 sb.append(" : ");
276 } else {
277 ConstructorInitializer lastInitializer =
278 initializers[initializers.length - 1];
279 int insertOffset = lastInitializer.end;
280 sb = new SourceBuilder(file, insertOffset);
281 sb.append(", ");
282 }
283 }
284 // add super constructor name
285 sb.append("super");
286 if (!StringUtils.isEmpty(constructorName)) {
287 sb.append(".");
288 sb.append(constructorName);
289 }
290 // add arguments
291 sb.append("(");
292 bool firstParameter = true;
293 for (ParameterElement parameter in superConstructor.parameters) {
294 // skip non-required parameters
295 if (parameter.parameterKind != ParameterKind.REQUIRED) {
296 break;
297 }
298 // comma
299 if (firstParameter) {
300 firstParameter = false;
301 } else {
302 sb.append(", ");
303 }
304 // default value
305 DartType parameterType = parameter.type;
306 sb.startPosition(parameter.name);
307 sb.append(getDefaultValueCode(parameterType));
308 sb.endPosition();
309 }
310 sb.append(")");
311 // insert proposal
312 _insertBuilder(sb);
313 // add proposal
314 String proposalName = _getConstructorProposalName(superConstructor);
315 _addFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, [proposalName]);
316 }
317 }
318
319 void _addFix_createConstructorSuperImplicit() {
320 // TODO(scheglov) implement
321 // ClassDeclaration targetClassNode = node.parent as ClassDeclaration;
322 // ClassElement targetClassElement = targetClassNode.element;
323 // ClassElement superClassElement = targetClassElement.supertype.element;
324 // String targetClassName = targetClassElement.name;
325 // // add proposals for all super constructors
326 // List<ConstructorElement> superConstructors = superClassElement.constructor s;
327 // for (ConstructorElement superConstructor in superConstructors) {
328 // String constructorName = superConstructor.name;
329 // // skip private
330 // if (Identifier.isPrivateName(constructorName)) {
331 // continue;
332 // }
333 // // prepare parameters and arguments
334 // JavaStringBuilder parametersBuffer = new JavaStringBuilder();
335 // JavaStringBuilder argumentsBuffer = new JavaStringBuilder();
336 // bool firstParameter = true;
337 // for (ParameterElement parameter in superConstructor.parameters) {
338 // // skip non-required parameters
339 // if (parameter.parameterKind != ParameterKind.REQUIRED) {
340 // break;
341 // }
342 // // comma
343 // if (firstParameter) {
344 // firstParameter = false;
345 // } else {
346 // parametersBuffer.append(", ");
347 // argumentsBuffer.append(", ");
348 // }
349 // // name
350 // String parameterName = parameter.displayName;
351 // if (parameterName.length > 1 && parameterName.startsWith("_")) {
352 // parameterName = parameterName.substring(1);
353 // }
354 // // parameter & argument
355 // _appendParameterSource(parametersBuffer, parameter.type, parameterName );
356 // argumentsBuffer.append(parameterName);
357 // }
358 // // add proposal
359 // String eol = utils.endOfLine;
360 // QuickFixProcessorImpl_NewConstructorLocation targetLocation =
361 // _prepareNewConstructorLocation(targetClassNode, eol);
362 // SourceBuilder sb = new SourceBuilder.con1(targetLocation._offset);
363 // {
364 // String indent = utils.getIndent(1);
365 // sb.append(targetLocation._prefix);
366 // sb.append(indent);
367 // sb.append(targetClassName);
368 // if (!constructorName.isEmpty) {
369 // sb.startPosition("NAME");
370 // sb.append(".");
371 // sb.append(constructorName);
372 // sb.endPosition();
373 // }
374 // sb.append("(");
375 // sb.append(parametersBuffer.toString());
376 // sb.append(") : super");
377 // if (!constructorName.isEmpty) {
378 // sb.append(".");
379 // sb.append(constructorName);
380 // }
381 // sb.append("(");
382 // sb.append(argumentsBuffer.toString());
383 // sb.append(");");
384 // sb.append(targetLocation._suffix);
385 // }
386 // _addInsertEdit3(sb);
387 // // add proposal
388 // String proposalName = _getConstructorProposalName(superConstructor);
389 // _addFix(
390 // FixKind.CREATE_CONSTRUCTOR_SUPER,
391 // [proposalName]);
392 // }
393 }
394
395 void _addFix_createConstructor_insteadOfSyntheticDefault() {
396 TypeName typeName = null;
397 ConstructorName constructorName = null;
398 InstanceCreationExpression instanceCreation = null;
399 if (node is SimpleIdentifier) {
400 if (node.parent is TypeName) {
401 typeName = node.parent as TypeName;
402 if (typeName.name == node && typeName.parent is ConstructorName) {
403 constructorName = typeName.parent as ConstructorName;
404 // should be synthetic default constructor
405 {
406 ConstructorElement constructorElement =
407 constructorName.staticElement;
408 if (constructorElement == null ||
409 !constructorElement.isDefaultConstructor ||
410 !constructorElement.isSynthetic) {
411 return;
412 }
413 }
414 // prepare InstanceCreationExpression
415 if (constructorName.parent is InstanceCreationExpression) {
416 instanceCreation = constructorName.parent as
417 InstanceCreationExpression;
418 if (instanceCreation.constructorName != constructorName) {
419 return;
420 }
421 }
422 }
423 }
424 }
425 // do we have enough information?
426 if (instanceCreation == null) {
427 return;
428 }
429 // prepare environment
430 String eol = utils.endOfLine;
431 // prepare target
432 DartType targetType = typeName.type;
433 if (targetType is! InterfaceType) {
434 return;
435 }
436 ClassElement targetElement = targetType.element as ClassElement;
437 String targetFile = targetElement.source.fullName;
438 ClassDeclaration targetClass = targetElement.node;
439 QuickFixProcessorImpl_NewConstructorLocation targetLocation =
440 _prepareNewConstructorLocation(targetClass, eol);
441 // build method source
442 SourceBuilder sb = new SourceBuilder(targetFile, targetLocation._offset);
443 {
444 String indent = " ";
445 sb.append(targetLocation._prefix);
446 sb.append(indent);
447 sb.append(targetElement.name);
448 _addFix_undefinedMethod_create_parameters(
449 sb,
450 instanceCreation.argumentList);
451 sb.append(") {${eol}${indent}}");
452 sb.append(targetLocation._suffix);
453 }
454 // insert source
455 _insertBuilder(sb);
456 // add proposal
457 _addFix(FixKind.CREATE_CONSTRUCTOR, [constructorName], fixFile: targetFile);
458 }
459
460 void _addFix_createConstructor_named() {
461 SimpleIdentifier name = null;
462 ConstructorName constructorName = null;
463 InstanceCreationExpression instanceCreation = null;
464 if (node is SimpleIdentifier) {
465 // name
466 name = node as SimpleIdentifier;
467 if (name.parent is ConstructorName) {
468 constructorName = name.parent as ConstructorName;
469 if (constructorName.name == name) {
470 // Type.name
471 if (constructorName.parent is InstanceCreationExpression) {
472 instanceCreation = constructorName.parent as
473 InstanceCreationExpression;
474 // new Type.name()
475 if (instanceCreation.constructorName != constructorName) {
476 return;
477 }
478 }
479 }
480 }
481 }
482 // do we have enough information?
483 if (instanceCreation == null) {
484 return;
485 }
486 // prepare environment
487 String eol = utils.endOfLine;
488 // prepare target interface type
489 DartType targetType = constructorName.type.type;
490 if (targetType is! InterfaceType) {
491 return;
492 }
493 ClassElement targetElement = targetType.element as ClassElement;
494 String targetFile = targetElement.source.fullName;
495 ClassDeclaration targetClass = targetElement.node;
496 QuickFixProcessorImpl_NewConstructorLocation targetLocation =
497 _prepareNewConstructorLocation(targetClass, eol);
498 // build method source
499 SourceBuilder sb = new SourceBuilder(targetFile, targetLocation._offset);
500 {
501 String indent = " ";
502 sb.append(targetLocation._prefix);
503 sb.append(indent);
504 sb.append(targetElement.name);
505 sb.append(".");
506 // append name
507 {
508 sb.startPosition("NAME");
509 sb.append(name.name);
510 sb.endPosition();
511 }
512 _addFix_undefinedMethod_create_parameters(
513 sb,
514 instanceCreation.argumentList);
515 sb.append(") {${eol}${indent}}");
516 sb.append(targetLocation._suffix);
517 }
518 // insert source
519 _insertBuilder(sb);
520 if (targetFile == file) {
521 _addLinkedPosition("NAME", rf.rangeNode(name));
522 }
523 // add proposal
524 _addFix(FixKind.CREATE_CONSTRUCTOR, [constructorName], fixFile: targetFile);
525 }
526
527 void _addFix_createFunction_forFunctionType() {
528 // TODO(scheglov) implement
529 // if (node is SimpleIdentifier) {
530 // SimpleIdentifier nameNode = node as SimpleIdentifier;
531 // // prepare argument expression (to get parameter)
532 // ClassElement targetElement;
533 // Expression argument;
534 // {
535 // Expression target = CorrectionUtils.getQualifiedPropertyTarget(node);
536 // if (target != null) {
537 // DartType targetType = target.bestType;
538 // if (targetType != null && targetType.element is ClassElement) {
539 // targetElement = targetType.element as ClassElement;
540 // argument = target.parent as Expression;
541 // } else {
542 // return;
543 // }
544 // } else {
545 // ClassDeclaration enclosingClass =
546 // node.getAncestor((node) => node is ClassDeclaration);
547 // targetElement = enclosingClass != null ?
548 // enclosingClass.element :
549 // null;
550 // argument = nameNode;
551 // }
552 // }
553 // // should be argument of some invocation
554 // ParameterElement parameterElement = argument.bestParameterElement;
555 // if (parameterElement == null) {
556 // return;
557 // }
558 // // should be parameter of function type
559 // DartType parameterType = parameterElement.type;
560 // if (parameterType is! FunctionType) {
561 // return;
562 // }
563 // FunctionType functionType = parameterType as FunctionType;
564 // // add proposal
565 // if (targetElement != null) {
566 // _addProposal_createFunction_method(targetElement, functionType);
567 // } else {
568 // _addProposal_createFunction_function(functionType);
569 // }
570 // }
571 }
572
573 void
574 _addFix_createMissingOverrides(List<ExecutableElement> missingOverrides) {
575 // TODO(scheglov) implement
576 // // sort by name
577 // missingOverrides.sort(
578 // (Element firstElement, Element secondElement) =>
579 // ObjectUtils.compare(firstElement.displayName, secondElement.displa yName));
580 // // add elements
581 // ClassDeclaration targetClass = node.parent as ClassDeclaration;
582 // bool isFirst = true;
583 // for (ExecutableElement missingOverride in missingOverrides) {
584 // _addFix_createMissingOverrides_single(
585 // targetClass,
586 // missingOverride,
587 // isFirst);
588 // isFirst = false;
589 // }
590 // // add proposal
591 // _addFix(
592 // FixKind.CREATE_MISSING_OVERRIDES,
593 // [missingOverrides.length]);
594 }
595
596 void _addFix_createMissingOverrides_single(ClassDeclaration targetClass,
597 ExecutableElement missingOverride, bool isFirst) {
598 // TODO(scheglov) implement
599 // // prepare environment
600 // String eol = utils.endOfLine;
601 // String prefix = utils.getIndent(1);
602 // String prefix2 = utils.getIndent(2);
603 // int insertOffset = targetClass.end - 1;
604 // // prepare source
605 // JavaStringBuilder sb = new JavaStringBuilder();
606 // // may be empty line
607 // if (!isFirst || !targetClass.members.isEmpty) {
608 // sb.append(eol);
609 // }
610 // // may be property
611 // ElementKind elementKind = missingOverride.kind;
612 // bool isGetter = elementKind == ElementKind.GETTER;
613 // bool isSetter = elementKind == ElementKind.SETTER;
614 // bool isMethod = elementKind == ElementKind.METHOD;
615 // bool isOperator = isMethod && (missingOverride as MethodElement).isOperato r;
616 // sb.append(prefix);
617 // if (isGetter) {
618 // sb.append("// TODO: implement ${missingOverride.displayName}");
619 // sb.append(eol);
620 // sb.append(prefix);
621 // }
622 // // @override
623 // {
624 // sb.append("@override");
625 // sb.append(eol);
626 // sb.append(prefix);
627 // }
628 // // return type
629 // _appendType(sb, missingOverride.type.returnType);
630 // if (isGetter) {
631 // sb.append("get ");
632 // } else if (isSetter) {
633 // sb.append("set ");
634 // } else if (isOperator) {
635 // sb.append("operator ");
636 // }
637 // // name
638 // sb.append(missingOverride.displayName);
639 // // parameters + body
640 // if (isGetter) {
641 // sb.append(" => null;");
642 // } else if (isMethod || isSetter) {
643 // List<ParameterElement> parameters = missingOverride.parameters;
644 // _appendParameters(sb, parameters);
645 // sb.append(" {");
646 // // TO-DO
647 // sb.append(eol);
648 // sb.append(prefix2);
649 // if (isMethod) {
650 // sb.append("// TODO: implement ${missingOverride.displayName}");
651 // } else {
652 // sb.append("// TODO: implement ${missingOverride.displayName}");
653 // }
654 // sb.append(eol);
655 // // close method
656 // sb.append(prefix);
657 // sb.append("}");
658 // }
659 // sb.append(eol);
660 // // done
661 // _addInsertEdit(insertOffset, sb.toString());
662 // // maybe set end range
663 // if (_endRange == null) {
664 // _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0);
665 // }
666 }
667
668 void _addFix_createNoSuchMethod() {
669 // TODO(scheglov) implement
670 // ClassDeclaration targetClass = node.parent as ClassDeclaration;
671 // // prepare environment
672 // String eol = utils.endOfLine;
673 // String prefix = utils.getIndent(1);
674 // int insertOffset = targetClass.end - 1;
675 // // prepare source
676 // SourceBuilder sb = new SourceBuilder.con1(insertOffset);
677 // {
678 // // insert empty line before existing member
679 // if (!targetClass.members.isEmpty) {
680 // sb.append(eol);
681 // }
682 // // append method
683 // sb.append(prefix);
684 // sb.append(
685 // "noSuchMethod(Invocation invocation) => super.noSuchMethod(invocatio n);");
686 // sb.append(eol);
687 // }
688 // // done
689 // _addInsertEdit3(sb);
690 // _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0);
691 // // add proposal
692 // _addFix(FixKind.CREATE_NO_SUCH_METHOD, []);
693 }
694
695 void _addFix_createPart() {
696 // TODO(scheglov) implement
697 // if (node is SimpleStringLiteral && node.parent is PartDirective) {
698 // SimpleStringLiteral uriLiteral = node as SimpleStringLiteral;
699 // String uriString = uriLiteral.value;
700 // // prepare referenced File
701 // JavaFile newFile;
702 // {
703 // Uri uri = parseUriWithException(uriString);
704 // if (uri.isAbsolute) {
705 // return;
706 // }
707 // newFile = new JavaFile.relative(_unitLibraryFolder, uriString);
708 // }
709 // if (!newFile.exists()) {
710 // // prepare new source
711 // String source;
712 // {
713 // String eol = utils.endOfLine;
714 // String libraryName = _unitLibraryElement.displayName;
715 // source = "part of ${libraryName};${eol}${eol}";
716 // }
717 // // add proposal
718 // _proposals.add(
719 // new CreateFileCorrectionProposal(
720 // newFile,
721 // source,
722 // FixKind.CREATE_PART,
723 // [uriString]));
724 // }
725 // }
726 }
727
728 void _addFix_importLibrary(FixKind kind, String importPath) {
729 // TODO(scheglov) implement
730 // CompilationUnitElement libraryUnitElement =
731 // _unitLibraryElement.definingCompilationUnit;
732 // CompilationUnit libraryUnit = libraryUnitElement.node;
733 // // prepare new import location
734 // int offset = 0;
735 // String prefix;
736 // String suffix;
737 // {
738 // String eol = utils.endOfLine;
739 // // if no directives
740 // prefix = "";
741 // suffix = eol;
742 // CorrectionUtils libraryUtils = new CorrectionUtils(libraryUnit);
743 // // after last directive in library
744 // for (Directive directive in libraryUnit.directives) {
745 // if (directive is LibraryDirective || directive is ImportDirective) {
746 // offset = directive.end;
747 // prefix = eol;
748 // suffix = "";
749 // }
750 // }
751 // // if still beginning of file, skip shebang and line comments
752 // if (offset == 0) {
753 // CorrectionUtils_InsertDesc desc = libraryUtils.insertDescTop;
754 // offset = desc.offset;
755 // prefix = desc.prefix;
756 // suffix = "${desc.suffix}${eol}";
757 // }
758 // }
759 // // insert new import
760 // String importSource = "${prefix}import '${importPath}';${suffix}";
761 // _addInsertEdit(offset, importSource);
762 // // add proposal
763 // _addUnitCorrectionProposal2(libraryUnitElement.source, kind, [importPath]) ;
764 }
765
766 void _addFix_importLibrary_withElement(String name, ElementKind kind) {
767 // TODO(scheglov) implement
768 // // ignore if private
769 // if (name.startsWith("_")) {
770 // return;
771 // }
772 // // may be there is an existing import, but it is with prefix and we don't use this prefix
773 // for (ImportElement imp in _unitLibraryElement.imports) {
774 // // prepare element
775 // LibraryElement libraryElement = imp.importedLibrary;
776 // Element element =
777 // CorrectionUtils.getExportedElement(libraryElement, name);
778 // if (element == null) {
779 // continue;
780 // }
781 // if (element is PropertyAccessorElement) {
782 // element = (element as PropertyAccessorElement).variable;
783 // }
784 // if (element.kind != kind) {
785 // continue;
786 // }
787 // // may be apply prefix
788 // PrefixElement prefix = imp.prefix;
789 // if (prefix != null) {
790 // SourceRange range = SourceRangeFactory.rangeStartLength(node, 0);
791 // _addReplaceEdit(range, "${prefix.displayName}.");
792 // _addFix(
793 // FixKind.IMPORT_LIBRARY_PREFIX,
794 // [libraryElement.displayName, prefix.displayName]);
795 // continue;
796 // }
797 // // may be update "show" directive
798 // List<NamespaceCombinator> combinators = imp.combinators;
799 // if (combinators.length == 1 && combinators[0] is ShowElementCombinator) {
800 // ShowElementCombinator showCombinator =
801 // combinators[0] as ShowElementCombinator;
802 // // prepare new set of names to show
803 // Set<String> showNames = new Set<String>();
804 // showNames.addAll(showCombinator.shownNames);
805 // showNames.add(name);
806 // // prepare library name - unit name or 'dart:name' for SDK library
807 // String libraryName = libraryElement.definingCompilationUnit.displayNam e;
808 // if (libraryElement.isInSdk) {
809 // libraryName = imp.uri;
810 // }
811 // // update library
812 // String newShowCode = "show ${StringUtils.join(showNames, ", ")}";
813 // // TODO(scheglov)
814 // _addReplaceEdit(
815 // SourceRangeFactory.rangeShowCombinator(showCombinator),
816 // newShowCode);
817 // _addUnitCorrectionProposal2(
818 // _unitLibraryElement.source,
819 // FixKind.IMPORT_LIBRARY_SHOW,
820 // [libraryName]);
821 // // we support only one import without prefix
822 // return;
823 // }
824 // }
825 // // check SDK libraries
826 // AnalysisContext context = _unitLibraryElement.context;
827 // {
828 // DartSdk sdk = context.sourceFactory.dartSdk;
829 // List<SdkLibrary> sdkLibraries = sdk.sdkLibraries;
830 // for (SdkLibrary sdkLibrary in sdkLibraries) {
831 // SourceFactory sdkSourceFactory = context.sourceFactory;
832 // String libraryUri = sdkLibrary.shortName;
833 // Source librarySource = sdkSourceFactory.resolveUri(null, libraryUri);
834 // // prepare LibraryElement
835 // LibraryElement libraryElement =
836 // context.getLibraryElement(librarySource);
837 // if (libraryElement == null) {
838 // continue;
839 // }
840 // // prepare exported Element
841 // Element element =
842 // CorrectionUtils.getExportedElement(libraryElement, name);
843 // if (element == null) {
844 // continue;
845 // }
846 // if (element is PropertyAccessorElement) {
847 // element = (element as PropertyAccessorElement).variable;
848 // }
849 // if (element.kind != kind) {
850 // continue;
851 // }
852 // // add import
853 // _addFix_importLibrary(FixKind.IMPORT_LIBRARY_SDK, libraryUri);
854 // }
855 // }
856 // // check project libraries
857 // {
858 // List<Source> librarySources = context.librarySources;
859 // for (Source librarySource in librarySources) {
860 // // we don't need SDK libraries here
861 // if (librarySource.isInSystemLibrary) {
862 // continue;
863 // }
864 // // prepare LibraryElement
865 // LibraryElement libraryElement =
866 // context.getLibraryElement(librarySource);
867 // if (libraryElement == null) {
868 // continue;
869 // }
870 // // prepare exported Element
871 // Element element =
872 // CorrectionUtils.getExportedElement(libraryElement, name);
873 // if (element == null) {
874 // continue;
875 // }
876 // if (element.kind != kind) {
877 // continue;
878 // }
879 // // prepare "library" file
880 // JavaFile libraryFile = getSourceFile(librarySource);
881 // if (libraryFile == null) {
882 // continue;
883 // }
884 // // may be "package:" URI
885 // {
886 // Uri libraryPackageUri = _findPackageUri(context, libraryFile);
887 // if (libraryPackageUri != null) {
888 // _addFix_importLibrary(
889 // FixKind.IMPORT_LIBRARY_PROJECT,
890 // libraryPackageUri.toString());
891 // continue;
892 // }
893 // }
894 // // relative URI
895 // String relative =
896 // URIUtils.computeRelativePath(
897 // _unitLibraryFolder.getAbsolutePath(),
898 // libraryFile.getAbsolutePath());
899 // _addFix_importLibrary(
900 // FixKind.IMPORT_LIBRARY_PROJECT,
901 // relative);
902 // }
903 // }
904 }
905
906 void _addFix_importLibrary_withFunction() {
907 // TODO(scheglov) implement
908 // if (node is SimpleIdentifier && node.parent is MethodInvocation) {
909 // MethodInvocation invocation = node.parent as MethodInvocation;
910 // if (invocation.realTarget == null &&
911 // identical(invocation.methodName, node)) {
912 // String name = (node as SimpleIdentifier).name;
913 // _addFix_importLibrary_withElement(name, ElementKind.FUNCTION);
914 // }
915 // }
916 }
917
918 void _addFix_importLibrary_withTopLevelVariable() {
919 // TODO(scheglov) implement
920 // if (node is SimpleIdentifier) {
921 // String name = (node as SimpleIdentifier).name;
922 // _addFix_importLibrary_withElement(name, ElementKind.TOP_LEVEL_VARIABLE);
923 // }
924 }
925
926 void _addFix_importLibrary_withType() {
927 // TODO(scheglov) implement
928 // if (_mayBeTypeIdentifier(node)) {
929 // String typeName = (node as SimpleIdentifier).name;
930 // _addFix_importLibrary_withElement(typeName, ElementKind.CLASS);
931 // }
932 }
933
934 void _addFix_insertSemicolon() {
935 if (error.message.contains("';'")) {
936 int insertOffset = error.offset + error.length;
937 _addInsertEdit(insertOffset, ";");
938 _addFix(FixKind.INSERT_SEMICOLON, []);
939 }
940 }
941
942 void _addFix_isNotNull() {
943 if (coveredNode is IsExpression) {
944 IsExpression isExpression = coveredNode as IsExpression;
945 _addReplaceEdit(
946 rf.rangeEndEnd(isExpression.expression, isExpression),
947 " != null");
948 _addFix(FixKind.USE_NOT_EQ_NULL, []);
949 }
950 }
951
952 void _addFix_isNull() {
953 if (coveredNode is IsExpression) {
954 IsExpression isExpression = coveredNode as IsExpression;
955 _addReplaceEdit(
956 rf.rangeEndEnd(isExpression.expression, isExpression),
957 " == null");
958 _addFix(FixKind.USE_EQ_EQ_NULL, []);
959 }
960 }
961
962 void _addFix_makeEnclosingClassAbstract() {
963 ClassDeclaration enclosingClass =
964 node.getAncestor((node) => node is ClassDeclaration);
965 String className = enclosingClass.name.name;
966 _addInsertEdit(enclosingClass.classKeyword.offset, "abstract ");
967 _addFix(FixKind.MAKE_CLASS_ABSTRACT, [className]);
968 }
969
970 void _addFix_removeParameters_inGetterDeclaration() {
971 if (node is SimpleIdentifier && node.parent is MethodDeclaration) {
972 MethodDeclaration method = node.parent as MethodDeclaration;
973 FunctionBody body = method.body;
974 if (method.name == node && body != null) {
975 _addReplaceEdit(rf.rangeEndStart(node, body), " ");
976 _addFix(FixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, []);
977 }
978 }
979 }
980
981 void _addFix_removeParentheses_inGetterInvocation() {
982 if (node is SimpleIdentifier && node.parent is MethodInvocation) {
983 MethodInvocation invocation = node.parent as MethodInvocation;
984 if (invocation.methodName == node && invocation.target != null) {
985 _addRemoveEdit(rf.rangeEndEnd(node, invocation));
986 _addFix(FixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, []);
987 }
988 }
989 }
990
991 void _addFix_removeUnnecessaryCast() {
992 if (coveredNode is! AsExpression) {
993 return;
994 }
995 AsExpression asExpression = coveredNode as AsExpression;
996 Expression expression = asExpression.expression;
997 int expressionPrecedence = getExpressionPrecedence(expression);
998 // remove 'as T' from 'e as T'
999 _addRemoveEdit(rf.rangeEndEnd(expression, asExpression));
1000 _removeEnclosingParentheses(asExpression, expressionPrecedence);
1001 // done
1002 _addFix(FixKind.REMOVE_UNNECASSARY_CAST, []);
1003 }
1004
1005 void _addFix_removeUnusedImport() {
1006 // prepare ImportDirective
1007 ImportDirective importDirective =
1008 node.getAncestor((node) => node is ImportDirective);
1009 if (importDirective == null) {
1010 return;
1011 }
1012 // remove the whole line with import
1013 _addRemoveEdit(utils.getLinesRange(rf.rangeNode(importDirective)));
1014 // done
1015 _addFix(FixKind.REMOVE_UNUSED_IMPORT, []);
1016 }
1017
1018 void _addFix_replaceWithConstInstanceCreation() {
1019 if (coveredNode is InstanceCreationExpression) {
1020 var instanceCreation = coveredNode as InstanceCreationExpression;
1021 _addReplaceEdit(rf.rangeToken(instanceCreation.keyword), "const");
1022 _addFix(FixKind.USE_CONST, []);
1023 }
1024 }
1025
1026 void _addFix_undefinedClass_useSimilar() {
1027 // TODO(scheglov) implement
1028 // if (_mayBeTypeIdentifier(node)) {
1029 // String name = (node as SimpleIdentifier).name;
1030 // QuickFixProcessorImpl_ClosestElementFinder finder =
1031 // new QuickFixProcessorImpl_ClosestElementFinder(
1032 // name,
1033 // new Predicate_QuickFixProcessorImpl_addFix_undefinedClass_useSim ilar());
1034 // // find closest element
1035 // {
1036 // // elements of this library
1037 // _unitLibraryElement.accept(
1038 // new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefined Class_useSimilar(
1039 // finder));
1040 // // elements from imports
1041 // for (ImportElement importElement in _unitLibraryElement.imports) {
1042 // if (importElement.prefix == null) {
1043 // Map<String, Element> namespace =
1044 // CorrectionUtils.getImportNamespace(importElement);
1045 // finder._update2(namespace.values);
1046 // }
1047 // }
1048 // }
1049 // // if we have close enough element, suggest to use it
1050 // if (finder != null && finder._distance < 5) {
1051 // String closestName = finder._element.name;
1052 // _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
1053 // // add proposal
1054 // if (closestName != null) {
1055 // _addFix(
1056 // FixKind.CHANGE_TO,
1057 // [closestName]);
1058 // }
1059 // }
1060 // }
1061 }
1062
1063 void _addFix_undefinedFunction_create() {
1064 // TODO(scheglov) implement
1065 // // should be the name of the invocation
1066 // if (node is SimpleIdentifier && node.parent is MethodInvocation) {
1067 // } else {
1068 // return;
1069 // }
1070 // String name = (node as SimpleIdentifier).name;
1071 // MethodInvocation invocation = node.parent as MethodInvocation;
1072 // // function invocation has no target
1073 // Expression target = invocation.realTarget;
1074 // if (target != null) {
1075 // return;
1076 // }
1077 // // prepare environment
1078 // String eol = utils.endOfLine;
1079 // int insertOffset;
1080 // String sourcePrefix;
1081 // AstNode enclosingMember =
1082 // node.getAncestor((node) => node is CompilationUnitMember);
1083 // insertOffset = enclosingMember.end;
1084 // sourcePrefix = "${eol}${eol}";
1085 // // build method source
1086 // SourceBuilder sb = new SourceBuilder.con1(insertOffset);
1087 // {
1088 // sb.append(sourcePrefix);
1089 // // may be return type
1090 // {
1091 // DartType type =
1092 // _addFix_undefinedMethod_create_getReturnType(invocation);
1093 // if (type != null) {
1094 // String typeSource = utils.getTypeSource2(type);
1095 // if (typeSource != "dynamic") {
1096 // sb.startPosition("RETURN_TYPE");
1097 // sb.append(typeSource);
1098 // sb.endPosition();
1099 // sb.append(" ");
1100 // }
1101 // }
1102 // }
1103 // // append name
1104 // {
1105 // sb.startPosition("NAME");
1106 // sb.append(name);
1107 // sb.endPosition();
1108 // }
1109 // _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList);
1110 // sb.append(") {${eol}}");
1111 // }
1112 // // insert source
1113 // _addInsertEdit(insertOffset, sb.toString());
1114 // // add linked positions
1115 // _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node));
1116 // _addLinkedPositions(sb);
1117 // // add proposal
1118 // _addFix(FixKind.CREATE_FUNCTION, [name]);
1119 }
1120
1121 void _addFix_undefinedFunction_useSimilar() {
1122 // TODO(scheglov) implement
1123 // if (node is SimpleIdentifier) {
1124 // String name = (node as SimpleIdentifier).name;
1125 // QuickFixProcessorImpl_ClosestElementFinder finder =
1126 // new QuickFixProcessorImpl_ClosestElementFinder(
1127 // name,
1128 // new Predicate_QuickFixProcessorImpl_addFix_undefinedFunction_use Similar());
1129 // // this library
1130 // _unitLibraryElement.accept(
1131 // new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefinedFu nction_useSimilar(
1132 // finder));
1133 // // imports
1134 // for (ImportElement importElement in _unitLibraryElement.imports) {
1135 // if (importElement.prefix == null) {
1136 // Map<String, Element> namespace =
1137 // CorrectionUtils.getImportNamespace(importElement);
1138 // finder._update2(namespace.values);
1139 // }
1140 // }
1141 // // if we have close enough element, suggest to use it
1142 // String closestName = null;
1143 // if (finder != null && finder._distance < 5) {
1144 // closestName = finder._element.name;
1145 // _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
1146 // _addFix(FixKind.CHANGE_TO, [closestName]);
1147 // }
1148 // }
1149 }
1150
1151 void _addFix_undefinedMethod_create() {
1152 // TODO(scheglov) implement
1153 // if (node is SimpleIdentifier && node.parent is MethodInvocation) {
1154 // String name = (node as SimpleIdentifier).name;
1155 // MethodInvocation invocation = node.parent as MethodInvocation;
1156 // // prepare environment
1157 // String eol = utils.endOfLine;
1158 // Source targetSource;
1159 // String prefix;
1160 // int insertOffset;
1161 // String sourcePrefix;
1162 // String sourceSuffix;
1163 // bool staticModifier = false;
1164 // Expression target = invocation.realTarget;
1165 // if (target == null) {
1166 // targetSource = _source;
1167 // ClassMember enclosingMember =
1168 // node.getAncestor((node) => node is ClassMember);
1169 // staticModifier = _inStaticMemberContext2(enclosingMember);
1170 // prefix = utils.getNodePrefix(enclosingMember);
1171 // insertOffset = enclosingMember.end;
1172 // sourcePrefix = "${eol}${prefix}${eol}";
1173 // sourceSuffix = "";
1174 // } else {
1175 // // prepare target interface type
1176 // DartType targetType = target.bestType;
1177 // if (targetType is! InterfaceType) {
1178 // return;
1179 // }
1180 // ClassElement targetElement = targetType.element as ClassElement;
1181 // targetSource = targetElement.source;
1182 // // may be static
1183 // if (target is Identifier) {
1184 // staticModifier = target.bestElement.kind == ElementKind.CLASS;
1185 // }
1186 // // prepare insert offset
1187 // ClassDeclaration targetClass = targetElement.node;
1188 // prefix = " ";
1189 // insertOffset = targetClass.end - 1;
1190 // if (targetClass.members.isEmpty) {
1191 // sourcePrefix = "";
1192 // } else {
1193 // sourcePrefix = "${prefix}${eol}";
1194 // }
1195 // sourceSuffix = eol;
1196 // }
1197 // // build method source
1198 // SourceBuilder sb = new SourceBuilder.con1(insertOffset);
1199 // {
1200 // sb.append(sourcePrefix);
1201 // sb.append(prefix);
1202 // // may be "static"
1203 // if (staticModifier) {
1204 // sb.append("static ");
1205 // }
1206 // // may be return type
1207 // {
1208 // DartType type =
1209 // _addFix_undefinedMethod_create_getReturnType(invocation);
1210 // if (type != null) {
1211 // String typeSource = utils.getTypeSource2(type);
1212 // if (typeSource != "dynamic") {
1213 // sb.startPosition("RETURN_TYPE");
1214 // sb.append(typeSource);
1215 // sb.endPosition();
1216 // sb.append(" ");
1217 // }
1218 // }
1219 // }
1220 // // append name
1221 // {
1222 // sb.startPosition("NAME");
1223 // sb.append(name);
1224 // sb.endPosition();
1225 // }
1226 // _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList) ;
1227 // sb.append(") {${eol}${prefix}}");
1228 // sb.append(sourceSuffix);
1229 // }
1230 // // insert source
1231 // _addInsertEdit(insertOffset, sb.toString());
1232 // // add linked positions
1233 // if (targetSource == _source) {
1234 // _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node));
1235 // }
1236 // _addLinkedPositions(sb);
1237 // // add proposal
1238 // _addUnitCorrectionProposal2(
1239 // targetSource,
1240 // FixKind.CREATE_METHOD,
1241 // [name]);
1242 // }
1243 }
1244
1245 /**
1246 * @return the possible return [Type], may be <code>null</code> if can not be identified.
1247 */
1248 DartType
1249 _addFix_undefinedMethod_create_getReturnType(MethodInvocation invocation) {
1250 // TODO(scheglov) implement
1251 // AstNode parent = invocation.parent;
1252 // // myFunction();
1253 // if (parent is ExpressionStatement) {
1254 // return VoidTypeImpl.instance;
1255 // }
1256 // // return myFunction();
1257 // if (parent is ReturnStatement) {
1258 // ExecutableElement executable =
1259 // CorrectionUtils.getEnclosingExecutableElement(invocation);
1260 // return executable != null ? executable.returnType : null;
1261 // }
1262 // // int v = myFunction();
1263 // if (parent is VariableDeclaration) {
1264 // VariableDeclaration variableDeclaration = parent;
1265 // if (identical(variableDeclaration.initializer, invocation)) {
1266 // VariableElement variableElement = variableDeclaration.element;
1267 // if (variableElement != null) {
1268 // return variableElement.type;
1269 // }
1270 // }
1271 // }
1272 // // v = myFunction();
1273 // if (parent is AssignmentExpression) {
1274 // AssignmentExpression assignment = parent;
1275 // if (identical(assignment.rightHandSide, invocation)) {
1276 // if (assignment.operator.type == TokenType.EQ) {
1277 // // v = myFunction();
1278 // Expression lhs = assignment.leftHandSide;
1279 // if (lhs != null) {
1280 // return lhs.bestType;
1281 // }
1282 // } else {
1283 // // v += myFunction();
1284 // MethodElement method = assignment.bestElement;
1285 // if (method != null) {
1286 // List<ParameterElement> parameters = method.parameters;
1287 // if (parameters.length == 1) {
1288 // return parameters[0].type;
1289 // }
1290 // }
1291 // }
1292 // }
1293 // }
1294 // // v + myFunction();
1295 // if (parent is BinaryExpression) {
1296 // BinaryExpression binary = parent;
1297 // MethodElement method = binary.bestElement;
1298 // if (method != null) {
1299 // if (identical(binary.rightOperand, invocation)) {
1300 // List<ParameterElement> parameters = method.parameters;
1301 // return parameters.length == 1 ? parameters[0].type : null;
1302 // }
1303 // }
1304 // }
1305 // // foo( myFunction() );
1306 // if (parent is ArgumentList) {
1307 // ParameterElement parameter = invocation.bestParameterElement;
1308 // return parameter != null ? parameter.type : null;
1309 // }
1310 // // bool
1311 // {
1312 // // assert( myFunction() );
1313 // if (parent is AssertStatement) {
1314 // AssertStatement statement = parent;
1315 // if (identical(statement.condition, invocation)) {
1316 // return coreTypeBool;
1317 // }
1318 // }
1319 // // if ( myFunction() ) {}
1320 // if (parent is IfStatement) {
1321 // IfStatement statement = parent;
1322 // if (identical(statement.condition, invocation)) {
1323 // return coreTypeBool;
1324 // }
1325 // }
1326 // // while ( myFunction() ) {}
1327 // if (parent is WhileStatement) {
1328 // WhileStatement statement = parent;
1329 // if (identical(statement.condition, invocation)) {
1330 // return coreTypeBool;
1331 // }
1332 // }
1333 // // do {} while ( myFunction() );
1334 // if (parent is DoStatement) {
1335 // DoStatement statement = parent;
1336 // if (identical(statement.condition, invocation)) {
1337 // return coreTypeBool;
1338 // }
1339 // }
1340 // // !myFunction()
1341 // if (parent is PrefixExpression) {
1342 // PrefixExpression prefixExpression = parent;
1343 // if (prefixExpression.operator.type == TokenType.BANG) {
1344 // return coreTypeBool;
1345 // }
1346 // }
1347 // // binary expression '&&' or '||'
1348 // if (parent is BinaryExpression) {
1349 // BinaryExpression binaryExpression = parent;
1350 // TokenType operatorType = binaryExpression.operator.type;
1351 // if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
1352 // operatorType == TokenType.BAR_BAR) {
1353 // return coreTypeBool;
1354 // }
1355 // }
1356 // }
1357 // we don't know
1358 return null;
1359 }
1360
1361 void _addFix_undefinedMethod_create_parameters(SourceBuilder sb,
1362 ArgumentList argumentList) {
1363 // append parameters
1364 sb.append("(");
1365 Set<String> excluded = new Set();
1366 List<Expression> arguments = argumentList.arguments;
1367 for (int i = 0; i < arguments.length; i++) {
1368 Expression argument = arguments[i];
1369 // append separator
1370 if (i != 0) {
1371 sb.append(", ");
1372 }
1373 // append type name
1374 DartType type = argument.bestType;
1375 String typeSource = utils.getTypeSource2(type);
1376 {
1377 sb.startPosition("TYPE${i}");
1378 sb.append(typeSource);
1379 _addSuperTypeProposals(sb, new Set(), type);
1380 sb.endPosition();
1381 }
1382 sb.append(" ");
1383 // append parameter name
1384 {
1385 List<String> suggestions =
1386 _getArgumentNameSuggestions(excluded, type, argument, i);
1387 String favorite = suggestions[0];
1388 excluded.add(favorite);
1389 sb.startPosition("ARG${i}");
1390 sb.append(favorite);
1391 sb.addProposals(suggestions);
1392 sb.endPosition();
1393 }
1394 }
1395 }
1396
1397 void _addFix_undefinedMethod_useSimilar() {
1398 // TODO(scheglov) implement
1399 // if (node is SimpleIdentifier && node.parent is MethodInvocation) {
1400 // MethodInvocation invocation = node.parent as MethodInvocation;
1401 // String name = (node as SimpleIdentifier).name;
1402 // QuickFixProcessorImpl_ClosestElementFinder finder =
1403 // new QuickFixProcessorImpl_ClosestElementFinder(
1404 // name,
1405 // new Predicate_QuickFixProcessorImpl_addFix_undefinedMethod_useSi milar());
1406 // // unqualified invocation
1407 // Expression target = invocation.realTarget;
1408 // if (target == null) {
1409 // ClassDeclaration clazz =
1410 // invocation.getAncestor((node) => node is ClassDeclaration);
1411 // if (clazz != null) {
1412 // ClassElement classElement = clazz.element;
1413 // _updateFinderWithClassMembers(finder, classElement);
1414 // }
1415 // } else {
1416 // DartType type = target.bestType;
1417 // if (type is InterfaceType) {
1418 // ClassElement classElement = type.element;
1419 // _updateFinderWithClassMembers(finder, classElement);
1420 // }
1421 // }
1422 // // if we have close enough element, suggest to use it
1423 // String closestName = null;
1424 // if (finder != null && finder._distance < 5) {
1425 // closestName = finder._element.name;
1426 // _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
1427 // _addFix(FixKind.CHANGE_TO, [closestName]);
1428 // }
1429 // }
1430 }
1431
1432 void _addFix_useEffectiveIntegerDivision() {
1433 for (AstNode n = node; n != null; n = n.parent) {
1434 if (n is MethodInvocation &&
1435 n.offset == errorOffset &&
1436 n.length == errorLength) {
1437 MethodInvocation invocation = n as MethodInvocation;
1438 Expression target = invocation.target;
1439 while (target is ParenthesizedExpression) {
1440 target = (target as ParenthesizedExpression).expression;
1441 }
1442 // replace "/" with "~/"
1443 BinaryExpression binary = target as BinaryExpression;
1444 _addReplaceEdit(rf.rangeToken(binary.operator), "~/");
1445 // remove everything before and after
1446 _addRemoveEdit(rf.rangeStartStart(invocation, binary.leftOperand));
1447 _addRemoveEdit(rf.rangeEndEnd(binary.rightOperand, invocation));
1448 // add proposal
1449 _addFix(FixKind.USE_EFFECTIVE_INTEGER_DIVISION, []);
1450 // done
1451 break;
1452 }
1453 }
1454 }
1455
1456 void _addFix_useStaticAccess_method() {
1457 if (node is SimpleIdentifier && node.parent is MethodInvocation) {
1458 MethodInvocation invocation = node.parent as MethodInvocation;
1459 if (invocation.methodName == node) {
1460 Expression target = invocation.target;
1461 String targetType = utils.getTypeSource(target);
1462 // replace "target" with class name
1463 SourceRange range = rf.rangeNode(target);
1464 _addReplaceEdit(range, targetType);
1465 // add proposal
1466 _addFix(FixKind.CHANGE_TO_STATIC_ACCESS, [targetType]);
1467 }
1468 }
1469 }
1470
1471 void _addFix_useStaticAccess_property() {
1472 if (node is SimpleIdentifier) {
1473 if (node.parent is PrefixedIdentifier) {
1474 PrefixedIdentifier prefixed = node.parent as PrefixedIdentifier;
1475 if (prefixed.identifier == node) {
1476 Expression target = prefixed.prefix;
1477 String targetType = utils.getTypeSource(target);
1478 // replace "target" with class name
1479 SourceRange range = rf.rangeNode(target);
1480 _addReplaceEdit(range, targetType);
1481 // add proposal
1482 _addFix(FixKind.CHANGE_TO_STATIC_ACCESS, [targetType]);
1483 }
1484 }
1485 }
1486 }
1487
1488 /**
1489 * Adds a new [Edit] to [edits].
1490 */
1491 void _addInsertEdit(int offset, String text) {
1492 Edit edit = new Edit(offset, 0, text);
1493 edits.add(edit);
1494 }
1495
1496 /**
1497 * Adds a single linked position to [groupId].
1498 */
1499 void _addLinkedPosition(String groupId, SourceRange range) {
1500 _addLinkedPosition2(
1501 groupId,
1502 new Position(file, range.offset, range.length));
1503 }
1504
1505 /**
1506 * Adds a single linked position to [groupId].
1507 */
1508 void _addLinkedPosition2(String groupId, Position position) {
1509 PositionGroup group = positionGroups[groupId];
1510 if (group == null) {
1511 group = new PositionGroup(groupId);
1512 positionGroups[groupId] = group;
1513 }
1514 group.add(position);
1515 }
1516
1517 /**
1518 * Adds a new [Edit] to [edits].
1519 */
1520 void _addRemoveEdit(SourceRange range) {
1521 _addReplaceEdit(range, '');
1522 }
1523
1524 /**
1525 * Adds a new [Edit] to [edits].
1526 */
1527 void _addReplaceEdit(SourceRange range, String text) {
1528 Edit edit = new Edit.range(range, text);
1529 edits.add(edit);
1530 }
1531
1532 void _appendParameterSource(StringBuffer sb, DartType type, String name) {
1533 String parameterSource = utils.getParameterSource(type, name);
1534 sb.write(parameterSource);
1535 }
1536
1537 void _appendParameters(StringBuffer sb, List<ParameterElement> parameters,
1538 Map<ParameterElement, String> defaultValueMap) {
1539 sb.write("(");
1540 bool firstParameter = true;
1541 bool sawNamed = false;
1542 bool sawPositional = false;
1543 for (ParameterElement parameter in parameters) {
1544 if (!firstParameter) {
1545 sb.write(", ");
1546 } else {
1547 firstParameter = false;
1548 }
1549 // may be optional
1550 ParameterKind parameterKind = parameter.parameterKind;
1551 if (parameterKind == ParameterKind.NAMED) {
1552 if (!sawNamed) {
1553 sb.write("{");
1554 sawNamed = true;
1555 }
1556 }
1557 if (parameterKind == ParameterKind.POSITIONAL) {
1558 if (!sawPositional) {
1559 sb.write("[");
1560 sawPositional = true;
1561 }
1562 }
1563 // parameter
1564 _appendParameterSource(sb, parameter.type, parameter.name);
1565 // default value
1566 if (defaultValueMap != null) {
1567 String defaultSource = defaultValueMap[parameter];
1568 if (defaultSource != null) {
1569 if (sawPositional) {
1570 sb.write(" = ");
1571 } else {
1572 sb.write(": ");
1573 }
1574 sb.write(defaultSource);
1575 }
1576 }
1577 }
1578 // close parameters
1579 if (sawNamed) {
1580 sb.write("}");
1581 }
1582 if (sawPositional) {
1583 sb.write("]");
1584 }
1585 sb.write(")");
1586 }
1587
1588 // void _addLinkedPositionProposal(String group,
1589 // LinkedPositionProposal proposal) {
1590 // List<LinkedPositionProposal> nodeProposals = linkedPositionProposals[group ];
1591 // if (nodeProposals == null) {
1592 // nodeProposals = <LinkedPositionProposal>[];
1593 // linkedPositionProposals[group] = nodeProposals;
1594 // }
1595 // nodeProposals.add(proposal);
1596 // }
1597
1598 /**
1599 * @return the string to display as the name of the given constructor in a pro posal name.
1600 */
1601 String _getConstructorProposalName(ConstructorElement constructor) {
1602 StringBuffer proposalNameBuffer = new StringBuffer();
1603 proposalNameBuffer.write("super");
1604 // may be named
1605 String constructorName = constructor.displayName;
1606 if (!constructorName.isEmpty) {
1607 proposalNameBuffer.write(".");
1608 proposalNameBuffer.write(constructorName);
1609 }
1610 // parameters
1611 _appendParameters(proposalNameBuffer, constructor.parameters, null);
1612 // done
1613 return proposalNameBuffer.toString();
1614 }
1615
1616 /**
1617 * Inserts the given [SourceBuilder] at its offset.
1618 */
1619 void _insertBuilder(SourceBuilder builder) {
1620 String text = builder.toString();
1621 _addInsertEdit(builder.offset, text);
1622 // add linked positions
1623 builder.positionGroups.forEach((PositionGroup group) {
1624 group.positions.forEach((Position position) {
1625 _addLinkedPosition2(group.id, position);
1626 });
1627 });
1628 }
1629
1630 QuickFixProcessorImpl_NewConstructorLocation
1631 _prepareNewConstructorLocation(ClassDeclaration classDeclaration, String e ol) {
1632 List<ClassMember> members = classDeclaration.members;
1633 // find the last field/constructor
1634 ClassMember lastFieldOrConstructor = null;
1635 for (ClassMember member in members) {
1636 if (member is FieldDeclaration || member is ConstructorDeclaration) {
1637 lastFieldOrConstructor = member;
1638 } else {
1639 break;
1640 }
1641 }
1642 // after the field/constructor
1643 if (lastFieldOrConstructor != null) {
1644 return new QuickFixProcessorImpl_NewConstructorLocation(
1645 "${eol}${eol}",
1646 lastFieldOrConstructor.end,
1647 "");
1648 }
1649 // at the beginning of the class
1650 String suffix = members.isEmpty ? "" : eol;
1651 return new QuickFixProcessorImpl_NewConstructorLocation(
1652 eol,
1653 classDeclaration.leftBracket.end,
1654 suffix);
1655 }
1656
1657 /**
1658 * Removes any [ParenthesizedExpression] enclosing [expr].
1659 *
1660 * [exprPrecedence] - the effective precedence of [expr].
1661 */
1662 void _removeEnclosingParentheses(Expression expr, int exprPrecedence) {
1663 while (expr.parent is ParenthesizedExpression) {
1664 ParenthesizedExpression parenthesized =
1665 expr.parent as ParenthesizedExpression;
1666 if (getExpressionParentPrecedence(parenthesized) > exprPrecedence) {
1667 break;
1668 }
1669 _addRemoveEdit(rf.rangeToken(parenthesized.leftParenthesis));
1670 _addRemoveEdit(rf.rangeToken(parenthesized.rightParenthesis));
1671 expr = parenthesized;
1672 }
1673 }
1674
1675 static void _addSuperTypeProposals(SourceBuilder sb,
1676 Set<DartType> alreadyAdded, DartType type) {
1677 if (type != null &&
1678 !alreadyAdded.contains(type) &&
1679 type.element is ClassElement) {
1680 alreadyAdded.add(type);
1681 ClassElement element = type.element as ClassElement;
1682 sb.addProposal(element.name);
1683 _addSuperTypeProposals(sb, alreadyAdded, element.supertype);
1684 for (InterfaceType interfaceType in element.interfaces) {
1685 _addSuperTypeProposals(sb, alreadyAdded, interfaceType);
1686 }
1687 }
1688 }
1689
1690 /**
1691 * @return the suggestions for given [Type] and [DartExpression], not empty.
1692 */
1693 static List<String> _getArgumentNameSuggestions(Set<String> excluded,
1694 DartType type, Expression expression, int index) {
1695 List<String> suggestions =
1696 getVariableNameSuggestions2(type, expression, excluded);
1697 if (suggestions.length != 0) {
1698 return suggestions;
1699 }
1700 return <String>["arg${index}"];
1701 }
1702
1703 /**
1704 * Returns `true` if [node] is a type name.
1705 */
1706 static bool _mayBeTypeIdentifier(AstNode node) {
1707 if (node is SimpleIdentifier) {
1708 AstNode parent = node.parent;
1709 if (parent is TypeName) {
1710 return true;
1711 }
1712 if (parent is MethodInvocation) {
1713 return parent.realTarget == node;
1714 }
1715 if (parent is PrefixedIdentifier) {
1716 return parent.prefix == node;
1717 }
1718 }
1719 return false;
1720 }
1721 }
1722
1723
1724 /**
1725 * Describes the location for a newly created [ConstructorDeclaration].
1726 *
1727 * TODO(scheglov) rename
1728 */
1729 class QuickFixProcessorImpl_NewConstructorLocation {
1730 final String _prefix;
1731 final int _offset;
1732 final String _suffix;
1733
1734 QuickFixProcessorImpl_NewConstructorLocation(this._prefix, this._offset,
1735 this._suffix);
1736 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698