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

Side by Side Diff: pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart

Issue 2875323002: Remove unintentional dependency on analysis_server (Closed)
Patch Set: Created 3 years, 7 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) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 import 'dart:async'; 5 import 'dart:async';
6 6
7 import 'package:analysis_server/protocol/protocol_generated.dart'
8 hide Element, ElementKind;
9 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
10 import 'package:analysis_server/src/services/correction/util.dart';
11 import 'package:analyzer/dart/ast/ast.dart'; 7 import 'package:analyzer/dart/ast/ast.dart';
12 import 'package:analyzer/dart/ast/token.dart'; 8 import 'package:analyzer/dart/ast/token.dart';
13 import 'package:analyzer/dart/element/element.dart'; 9 import 'package:analyzer/dart/element/element.dart';
14 import 'package:analyzer/dart/element/type.dart'; 10 import 'package:analyzer/dart/element/type.dart';
15 import 'package:analyzer/src/dart/analysis/driver.dart'; 11 import 'package:analyzer/src/dart/analysis/driver.dart';
16 import 'package:analyzer/src/dart/ast/utilities.dart'; 12 import 'package:analyzer/src/dart/ast/utilities.dart';
17 import 'package:analyzer/src/generated/resolver.dart'; 13 import 'package:analyzer/src/generated/resolver.dart';
18 import 'package:analyzer/src/generated/source.dart'; 14 import 'package:analyzer/src/generated/source.dart';
19 import 'package:analyzer/src/generated/utilities_dart.dart'; 15 import 'package:analyzer/src/generated/utilities_dart.dart';
16 import 'package:analyzer_plugin/protocol/protocol_generated.dart'
17 hide Element, ElementKind;
20 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core .dart'; 18 import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core .dart';
19 import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
21 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dar t'; 20 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dar t';
22 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dar t'; 21 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dar t';
23 import 'package:analyzer_plugin/utilities/range_factory.dart'; 22 import 'package:analyzer_plugin/utilities/range_factory.dart';
23 import 'package:charcode/ascii.dart';
24 import 'package:path/path.dart' as path;
24 25
25 /** 26 /**
26 * A [ChangeBuilder] used to build changes in Dart files. 27 * A [ChangeBuilder] used to build changes in Dart files.
27 */ 28 */
28 class DartChangeBuilderImpl extends ChangeBuilderImpl 29 class DartChangeBuilderImpl extends ChangeBuilderImpl
29 implements DartChangeBuilder { 30 implements DartChangeBuilder {
30 /** 31 /**
31 * The analysis driver in which the files being edited were analyzed. 32 * The analysis driver in which the files being edited were analyzed.
32 */ 33 */
33 final AnalysisDriver driver; 34 final AnalysisDriver driver;
34 35
35 /** 36 /**
36 * Initialize a newly created change builder. 37 * Initialize a newly created change builder.
37 */ 38 */
38 DartChangeBuilderImpl(this.driver); 39 DartChangeBuilderImpl(this.driver);
39 40
40 @override 41 @override
41 Future<DartFileEditBuilderImpl> createFileEditBuilder( 42 Future<DartFileEditBuilderImpl> createFileEditBuilder(
42 String path, int fileStamp) async { 43 String path, int fileStamp) async {
43 AnalysisResult result = await driver.getResult(path); 44 AnalysisResult result = await driver.getResult(path);
44 return new DartFileEditBuilderImpl(this, path, fileStamp, result.unit); 45 return new DartFileEditBuilderImpl(this, path, fileStamp, result.unit);
45 } 46 }
46 } 47 }
47 48
48 /** 49 /**
49 * An [EditBuilder] used to build edits in Dart files. 50 * An [EditBuilder] used to build edits in Dart files.
50 */ 51 */
51 class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder { 52 class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
53 List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
54
52 /** 55 /**
53 * Initialize a newly created builder to build a source edit. 56 * Initialize a newly created builder to build a source edit.
54 */ 57 */
55 DartEditBuilderImpl( 58 DartEditBuilderImpl(
56 DartFileEditBuilderImpl sourceFileEditBuilder, int offset, int length) 59 DartFileEditBuilderImpl sourceFileEditBuilder, int offset, int length)
57 : super(sourceFileEditBuilder, offset, length); 60 : super(sourceFileEditBuilder, offset, length);
58 61
59 DartFileEditBuilderImpl get dartFileEditBuilder => fileEditBuilder; 62 DartFileEditBuilderImpl get dartFileEditBuilder => fileEditBuilder;
60 63
61 @override 64 @override
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 write(prefix); 539 write(prefix);
537 } 540 }
538 first = false; 541 first = false;
539 } else { 542 } else {
540 write(', '); 543 write(', ');
541 } 544 }
542 writeType(type); 545 writeType(type);
543 } 546 }
544 } 547 }
545 548
549 /**
550 * Adds [toAdd] items which are not excluded.
551 */
552 void _addAll(
553 Set<String> excluded, Set<String> result, Iterable<String> toAdd) {
554 for (String item in toAdd) {
555 // add name based on "item", but not "excluded"
556 for (int suffix = 1;; suffix++) {
557 // prepare name, just "item" or "item2", "item3", etc
558 String name = item;
559 if (suffix > 1) {
560 name += suffix.toString();
561 }
562 // add once found not excluded
563 if (!excluded.contains(name)) {
564 result.add(name);
565 break;
566 }
567 }
568 }
569 }
570
571 /**
572 * Adds to [result] either [c] or the first ASCII character after it.
573 */
574 void _addSingleCharacterName(
575 Set<String> excluded, Set<String> result, int c) {
576 while (c < $z) {
577 String name = new String.fromCharCode(c);
578 // may be done
579 if (!excluded.contains(name)) {
580 result.add(name);
581 break;
582 }
583 // next character
584 c = c + 1;
585 }
586 }
587
546 void _addSuperTypeProposals( 588 void _addSuperTypeProposals(
547 LinkedEditBuilder builder, DartType type, Set<DartType> alreadyAdded) { 589 LinkedEditBuilder builder, DartType type, Set<DartType> alreadyAdded) {
548 if (type != null && 590 if (type != null &&
549 type.element is ClassElement && 591 type.element is ClassElement &&
550 alreadyAdded.add(type)) { 592 alreadyAdded.add(type)) {
551 ClassElement element = type.element as ClassElement; 593 ClassElement element = type.element as ClassElement;
552 builder.addSuggestion(LinkedEditSuggestionKind.TYPE, element.name); 594 builder.addSuggestion(LinkedEditSuggestionKind.TYPE, element.name);
553 _addSuperTypeProposals(builder, element.supertype, alreadyAdded); 595 _addSuperTypeProposals(builder, element.supertype, alreadyAdded);
554 for (InterfaceType interfaceType in element.interfaces) { 596 for (InterfaceType interfaceType in element.interfaces) {
555 _addSuperTypeProposals(builder, interfaceType, alreadyAdded); 597 _addSuperTypeProposals(builder, interfaceType, alreadyAdded);
556 } 598 }
557 } 599 }
558 } 600 }
559 601
602 String _getBaseNameFromExpression(Expression expression) {
603 String name = null;
604 // e as Type
605 if (expression is AsExpression) {
606 AsExpression asExpression = expression as AsExpression;
607 expression = asExpression.expression;
608 }
609 // analyze expressions
610 if (expression is SimpleIdentifier) {
611 SimpleIdentifier node = expression;
612 return node.name;
613 } else if (expression is PrefixedIdentifier) {
614 PrefixedIdentifier node = expression;
615 return node.identifier.name;
616 } else if (expression is PropertyAccess) {
617 PropertyAccess node = expression;
618 return node.propertyName.name;
619 } else if (expression is MethodInvocation) {
620 name = expression.methodName.name;
621 } else if (expression is InstanceCreationExpression) {
622 InstanceCreationExpression creation = expression;
623 ConstructorName constructorName = creation.constructorName;
624 TypeName typeName = constructorName.type;
625 if (typeName != null) {
626 Identifier typeNameIdentifier = typeName.name;
627 // new ClassName()
628 if (typeNameIdentifier is SimpleIdentifier) {
629 return typeNameIdentifier.name;
630 }
631 // new prefix.name();
632 if (typeNameIdentifier is PrefixedIdentifier) {
633 PrefixedIdentifier prefixed = typeNameIdentifier;
634 // new prefix.ClassName()
635 if (prefixed.prefix.staticElement is PrefixElement) {
636 return prefixed.identifier.name;
637 }
638 // new ClassName.constructorName()
639 return prefixed.prefix.name;
640 }
641 }
642 }
643 // strip known prefixes
644 if (name != null) {
645 for (int i = 0; i < _KNOWN_METHOD_NAME_PREFIXES.length; i++) {
646 String prefix = _KNOWN_METHOD_NAME_PREFIXES[i];
647 if (name.startsWith(prefix)) {
648 if (name == prefix) {
649 return null;
650 } else if (isUpperCase(name.codeUnitAt(prefix.length))) {
651 return name.substring(prefix.length);
652 }
653 }
654 }
655 }
656 // done
657 return name;
658 }
659
660 String _getBaseNameFromLocationInParent(Expression expression) {
661 // value in named expression
662 if (expression.parent is NamedExpression) {
663 NamedExpression namedExpression = expression.parent as NamedExpression;
664 if (namedExpression.expression == expression) {
665 return namedExpression.name.label.name;
666 }
667 }
668 // positional argument
669 ParameterElement parameter = expression.propagatedParameterElement;
670 if (parameter == null) {
671 parameter = expression.staticParameterElement;
672 }
673 if (parameter != null) {
674 return parameter.displayName;
675 }
676
677 // unknown
678 return null;
679 }
680
681 /**
682 * Returns all variants of names by removing leading words one by one.
683 */
684 List<String> _getCamelWordCombinations(String name) {
685 List<String> result = [];
686 List<String> parts = getCamelWords(name);
687 for (int i = 0; i < parts.length; i++) {
688 String s1 = parts[i].toLowerCase();
689 String s2 = parts.skip(i + 1).join();
690 String suggestion = '$s1$s2';
691 result.add(suggestion);
692 }
693 return result;
694 }
695
560 /** 696 /**
561 * Return the import element used to import the given [element] into the given 697 * Return the import element used to import the given [element] into the given
562 * [library], or `null` if the element was not imported, such as when the 698 * [library], or `null` if the element was not imported, such as when the
563 * element is declared in the same library. 699 * element is declared in the same library.
564 */ 700 */
565 ImportElement _getImportElement(Element element, LibraryElement library) { 701 ImportElement _getImportElement(Element element, LibraryElement library) {
566 for (ImportElement imp in library.imports) { 702 for (ImportElement importElement in library.imports) {
567 Map<String, Element> definedNames = getImportNamespace(imp); 703 Map<String, Element> definedNames = _getImportNamespace(importElement);
568 if (definedNames.containsValue(element)) { 704 if (definedNames.containsValue(element)) {
569 return imp; 705 return importElement;
570 } 706 }
571 } 707 }
572 return null; 708 return null;
573 } 709 }
574 710
575 /** 711 /**
712 * Return the namespace added by the given import [element].
713 */
714 Map<String, Element> _getImportNamespace(ImportElement element) {
715 NamespaceBuilder builder = new NamespaceBuilder();
716 Namespace namespace = builder.createImportNamespaceForDirective(element);
717 return namespace.definedNames;
718 }
719
720 /**
576 * Return a list containing the suggested names for a parameter with the given 721 * Return a list containing the suggested names for a parameter with the given
577 * [type] whose value in one location is computed by the given [expression]. 722 * [type] whose value in one location is computed by the given [expression].
578 * The list will not contain any names in the set of [excluded] names. The 723 * The list will not contain any names in the set of [excluded] names. The
579 * [index] is the index of the argument, used to create a name if no better 724 * [index] is the index of the argument, used to create a name if no better
580 * name could be created. The first name in the list will be the best name. 725 * name could be created. The first name in the list will be the best name.
581 */ 726 */
582 List<String> _getParameterNameSuggestions( 727 List<String> _getParameterNameSuggestions(
583 Set<String> usedNames, DartType type, Expression expression, int index) { 728 Set<String> usedNames, DartType type, Expression expression, int index) {
584 List<String> suggestions = 729 List<String> suggestions =
585 getVariableNameSuggestionsForExpression(type, expression, usedNames); 730 _getVariableNameSuggestionsForExpression(type, expression, usedNames);
586 if (suggestions.length != 0) { 731 if (suggestions.length != 0) {
587 return suggestions; 732 return suggestions;
588 } 733 }
589 // TODO(brianwilkerson) Verify that the name below is not in the set of used names. 734 // TODO(brianwilkerson) Verify that the name below is not in the set of used names.
590 return <String>['param$index']; 735 return <String>['param$index'];
591 } 736 }
592 737
593 /** 738 /**
594 * Return the source for the parameter with the given [type] and [name]. 739 * Return the source for the parameter with the given [type] and [name].
595 */ 740 */
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 } 876 }
732 } 877 }
733 sb.write(">"); 878 sb.write(">");
734 } 879 }
735 } 880 }
736 // done 881 // done
737 return sb.toString(); 882 return sb.toString();
738 } 883 }
739 884
740 /** 885 /**
886 * Returns possible names for a variable with the given expected type and
887 * expression assigned.
888 */
889 List<String> _getVariableNameSuggestionsForExpression(DartType expectedType,
890 Expression assignedExpression, Set<String> excluded) {
891 Set<String> res = new Set();
892 // use expression
893 if (assignedExpression != null) {
894 String nameFromExpression =
895 _getBaseNameFromExpression(assignedExpression);
896 if (nameFromExpression != null) {
897 nameFromExpression = removeStart(nameFromExpression, '_');
898 _addAll(excluded, res, _getCamelWordCombinations(nameFromExpression));
899 }
900 String nameFromParent =
901 _getBaseNameFromLocationInParent(assignedExpression);
902 if (nameFromParent != null) {
903 _addAll(excluded, res, _getCamelWordCombinations(nameFromParent));
904 }
905 }
906 // use type
907 if (expectedType != null && !expectedType.isDynamic) {
908 String typeName = expectedType.name;
909 if ('int' == typeName) {
910 _addSingleCharacterName(excluded, res, $i);
911 } else if ('double' == typeName) {
912 _addSingleCharacterName(excluded, res, $d);
913 } else if ('String' == typeName) {
914 _addSingleCharacterName(excluded, res, $s);
915 } else {
916 _addAll(excluded, res, _getCamelWordCombinations(typeName));
917 }
918 res.remove(typeName);
919 }
920 // done
921 return new List.from(res);
922 }
923
924 /**
741 * Checks if [type] is visible in either the [enclosingExecutable] or 925 * Checks if [type] is visible in either the [enclosingExecutable] or
742 * [enclosingClass]. 926 * [enclosingClass].
743 */ 927 */
744 bool _isTypeVisible(DartType type, ClassElement enclosingClass, 928 bool _isTypeVisible(DartType type, ClassElement enclosingClass,
745 ExecutableElement enclosingExecutable) { 929 ExecutableElement enclosingExecutable) {
746 if (type is TypeParameterType) { 930 if (type is TypeParameterType) {
747 TypeParameterElement parameterElement = type.element; 931 TypeParameterElement parameterElement = type.element;
748 Element parameterParent = parameterElement.enclosingElement; 932 Element parameterParent = parameterElement.enclosingElement;
749 // TODO(brianwilkerson) This needs to compare the parameterParent with 933 // TODO(brianwilkerson) This needs to compare the parameterParent with
750 // each of the parents of the enclosingElement. (That means that we only 934 // each of the parents of the enclosingElement. (That means that we only
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
799 _replaceReturnTypeWithFuture(body, typeProvider); 983 _replaceReturnTypeWithFuture(body, typeProvider);
800 } 984 }
801 985
802 @override 986 @override
803 DartEditBuilderImpl createEditBuilder(int offset, int length) { 987 DartEditBuilderImpl createEditBuilder(int offset, int length) {
804 return new DartEditBuilderImpl(this, offset, length); 988 return new DartEditBuilderImpl(this, offset, length);
805 } 989 }
806 990
807 @override 991 @override
808 void finalize() { 992 void finalize() {
809 addLibraryImports( 993 _addLibraryImports(
810 changeBuilder.sourceChange, unit.element.library, librariesToImport); 994 changeBuilder.sourceChange, unit.element.library, librariesToImport);
811 } 995 }
812 996
813 // /**
814 // * Return the content of the file being edited.
815 // */
816 // String getContent() {
817 // if (_content == null) {
818 // CompilationUnitElement unitElement = unit.element;
819 // AnalysisContext context = unitElement.context;
820 // if (context == null) {
821 // throw new CancelCorrectionException();
822 // }
823 // _content = context.getContents(unitElement.source).data;
824 // }
825 // return _content;
826 // }
827
828 @override 997 @override
829 void importLibraries(Iterable<Source> libraries) { 998 void importLibraries(Iterable<Source> libraries) {
830 librariesToImport.addAll(libraries); 999 librariesToImport.addAll(libraries);
831 } 1000 }
832 1001
833 @override 1002 @override
834 void replaceTypeWithFuture( 1003 void replaceTypeWithFuture(
835 TypeAnnotation typeAnnotation, TypeProvider typeProvider) { 1004 TypeAnnotation typeAnnotation, TypeProvider typeProvider) {
836 InterfaceType futureType = typeProvider.futureType; 1005 InterfaceType futureType = typeProvider.futureType;
837 // 1006 //
838 // Check whether the type needs to be replaced. 1007 // Check whether the type needs to be replaced.
839 // 1008 //
840 DartType type = typeAnnotation?.type; 1009 DartType type = typeAnnotation?.type;
841 if (type == null || 1010 if (type == null ||
842 type.isDynamic || 1011 type.isDynamic ||
843 type is InterfaceType && type.element == futureType.element) { 1012 type is InterfaceType && type.element == futureType.element) {
844 return; 1013 return;
845 } 1014 }
846 futureType = futureType.instantiate(<DartType>[type]); 1015 futureType = futureType.instantiate(<DartType>[type]);
847 // prepare code for the types 1016 // prepare code for the types
848 addReplacement(range.node(typeAnnotation), (EditBuilder builder) { 1017 addReplacement(range.node(typeAnnotation), (EditBuilder builder) {
849 if (!(builder as DartEditBuilder).writeType(futureType)) { 1018 if (!(builder as DartEditBuilder).writeType(futureType)) {
850 builder.write('void'); 1019 builder.write('void');
851 } 1020 }
852 }); 1021 });
853 } 1022 }
854 1023
1024 /**
1025 * Adds edits to the given [change] that ensure that all the [libraries] are
1026 * imported into the given [targetLibrary].
1027 */
1028 void _addLibraryImports(SourceChange change, LibraryElement targetLibrary,
1029 Set<Source> libraries) {
1030 // Prepare information about existing imports.
1031 LibraryDirective libraryDirective;
1032 List<ImportDirective> importDirectives = <ImportDirective>[];
1033 for (Directive directive in unit.directives) {
1034 if (directive is LibraryDirective) {
1035 libraryDirective = directive;
1036 } else if (directive is ImportDirective) {
1037 importDirectives.add(directive);
1038 }
1039 }
1040
1041 // Prepare all URIs to import.
1042 List<String> uriList = libraries
1043 .map((library) => _getLibrarySourceUri(targetLibrary, library))
1044 .toList();
1045 uriList.sort((a, b) => a.compareTo(b));
1046
1047 // Insert imports: between existing imports.
1048 if (importDirectives.isNotEmpty) {
1049 bool isFirstPackage = true;
1050 for (String importUri in uriList) {
1051 bool inserted = false;
1052 bool isPackage = importUri.startsWith('package:');
1053 bool isAfterDart = false;
1054 for (ImportDirective existingImport in importDirectives) {
1055 if (existingImport.uriContent.startsWith('dart:')) {
1056 isAfterDart = true;
1057 }
1058 if (existingImport.uriContent.startsWith('package:')) {
1059 isFirstPackage = false;
1060 }
1061 if (importUri.compareTo(existingImport.uriContent) < 0) {
1062 addInsertion(existingImport.offset, (EditBuilder builder) {
1063 builder.write("import '");
1064 builder.write(importUri);
1065 builder.writeln("';");
1066 });
1067 inserted = true;
1068 break;
1069 }
1070 }
1071 if (!inserted) {
1072 addInsertion(importDirectives.last.end, (EditBuilder builder) {
1073 if (isPackage && isFirstPackage && isAfterDart) {
1074 builder.writeln();
1075 }
1076 builder.writeln();
1077 builder.write("import '");
1078 builder.write(importUri);
1079 builder.write("';");
1080 });
1081 }
1082 if (isPackage) {
1083 isFirstPackage = false;
1084 }
1085 }
1086 return;
1087 }
1088
1089 // Insert imports: after the library directive.
1090 if (libraryDirective != null) {
1091 for (int i = 0; i < uriList.length; i++) {
1092 String importUri = uriList[i];
1093 addInsertion(libraryDirective.end, (EditBuilder builder) {
1094 if (i == 0) {
1095 builder.writeln();
1096 }
1097 builder.writeln();
1098 builder.write("import '");
1099 builder.write(importUri);
1100 builder.writeln("';");
1101 });
1102 }
1103 return;
1104 }
1105
1106 // If still at the beginning of the file, skip shebang and line comments.
1107 _InsertionDescription desc = _getInsertDescTop();
1108 int offset = desc.offset;
1109 for (int i = 0; i < uriList.length; i++) {
1110 String importUri = uriList[i];
1111 addInsertion(offset, (EditBuilder builder) {
1112 if (i == 0 && desc.insertEmptyLineBefore) {
1113 builder.writeln();
1114 }
1115 builder.write("import '");
1116 builder.write(importUri);
1117 builder.writeln("';");
1118 if (i == uriList.length - 1 && desc.insertEmptyLineAfter) {
1119 builder.writeln();
1120 }
1121 });
1122 }
1123 }
1124
1125 /**
1126 * Returns a [InsertDesc] describing where to insert a new directive or a
1127 * top-level declaration at the top of the file.
1128 */
1129 _InsertionDescription _getInsertDescTop() {
1130 // skip leading line comments
1131 int offset = 0;
1132 bool insertEmptyLineBefore = false;
1133 bool insertEmptyLineAfter = false;
1134 String source = unit.element.context.getContents(unit.element.source).data;
1135 var lineInfo = unit.lineInfo;
1136 // skip hash-bang
1137 if (offset < source.length - 2) {
1138 String linePrefix = _getText(source, offset, 2);
1139 if (linePrefix == "#!") {
1140 insertEmptyLineBefore = true;
1141 offset = lineInfo.getOffsetOfLineAfter(offset);
1142 // skip empty lines to first line comment
1143 int emptyOffset = offset;
1144 while (emptyOffset < source.length - 2) {
1145 int nextLineOffset = lineInfo.getOffsetOfLineAfter(emptyOffset);
1146 String line = source.substring(emptyOffset, nextLineOffset);
1147 if (line.trim().isEmpty) {
1148 emptyOffset = nextLineOffset;
1149 continue;
1150 } else if (line.startsWith("//")) {
1151 offset = emptyOffset;
1152 break;
1153 } else {
1154 break;
1155 }
1156 }
1157 }
1158 }
1159 // skip line comments
1160 while (offset < source.length - 2) {
1161 String linePrefix = _getText(source, offset, 2);
1162 if (linePrefix == "//") {
1163 insertEmptyLineBefore = true;
1164 offset = lineInfo.getOffsetOfLineAfter(offset);
1165 } else {
1166 break;
1167 }
1168 }
1169 // determine if empty line is required after
1170 int currentLine = lineInfo.getLocation(offset).lineNumber;
1171 if (currentLine < lineInfo.lineCount) {
1172 int nextLineOffset = lineInfo.getOffsetOfLine(currentLine + 1);
1173 String insertLine = source.substring(offset, nextLineOffset);
1174 if (!insertLine.trim().isEmpty) {
1175 insertEmptyLineAfter = true;
1176 }
1177 }
1178 return new _InsertionDescription(
1179 offset, insertEmptyLineBefore, insertEmptyLineAfter);
1180 }
1181
1182 // /**
1183 // * Return the content of the file being edited.
1184 // */
1185 // String getContent() {
1186 // if (_content == null) {
1187 // CompilationUnitElement unitElement = unit.element;
1188 // AnalysisContext context = unitElement.context;
1189 // if (context == null) {
1190 // throw new CancelCorrectionException();
1191 // }
1192 // _content = context.getContents(unitElement.source).data;
1193 // }
1194 // return _content;
1195 // }
1196
1197 /**
1198 * Computes the best URI to import [what] into [from].
1199 */
1200 String _getLibrarySourceUri(LibraryElement from, Source what) {
1201 String whatPath = what.fullName;
1202 // check if an absolute URI (such as 'dart:' or 'package:')
1203 Uri whatUri = what.uri;
1204 String whatUriScheme = whatUri.scheme;
1205 if (whatUriScheme != '' && whatUriScheme != 'file') {
1206 return whatUri.toString();
1207 }
1208 // compute a relative URI
1209 String fromFolder = path.dirname(from.source.fullName);
1210 String relativeFile = path.relative(whatPath, from: fromFolder);
1211 return path.split(relativeFile).join('/');
1212 }
1213
1214 /**
1215 * Returns the text of the given range in the unit.
1216 */
1217 String _getText(String content, int offset, int length) {
1218 return content.substring(offset, offset + length);
1219 }
1220
855 // /** 1221 // /**
856 // * Returns the text of the given [AstNode] in the unit. 1222 // * Returns the text of the given [AstNode] in the unit.
857 // */ 1223 // */
858 // String _getNodeText(AstNode node) { 1224 // String _getNodeText(AstNode node) {
859 // return _getText(node.offset, node.length); 1225 // return _getText(node.offset, node.length);
860 // } 1226 // }
861 // 1227 //
862 // /** 1228 // /**
863 // * Returns the text of the given range in the unit. 1229 // * Returns the text of the given range in the unit.
864 // */ 1230 // */
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 enclosingExecutable = node.element; 1299 enclosingExecutable = node.element;
934 } else if (node is MethodDeclaration) { 1300 } else if (node is MethodDeclaration) {
935 enclosingExecutable = node.element; 1301 enclosingExecutable = node.element;
936 } else if (node is FunctionDeclaration) { 1302 } else if (node is FunctionDeclaration) {
937 enclosingExecutable = node.element; 1303 enclosingExecutable = node.element;
938 } 1304 }
939 node = node.parent; 1305 node = node.parent;
940 } 1306 }
941 } 1307 }
942 } 1308 }
1309
1310 class _InsertionDescription {
1311 final int offset;
1312 final bool insertEmptyLineBefore;
1313 final bool insertEmptyLineAfter;
1314 _InsertionDescription(
1315 this.offset, this.insertEmptyLineBefore, this.insertEmptyLineAfter);
1316 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698