Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // This code was auto-generated, is not intended to be edited, and is subject to | 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. | 6 // significant change. Please see the README file for more information. |
| 7 | 7 |
| 8 library services.src.correction.fix; | 8 library services.src.correction.fix; |
| 9 | 9 |
| 10 import 'package:analysis_services/correction/change.dart'; | 10 import 'package:analysis_services/correction/change.dart'; |
| 11 import 'package:analysis_services/correction/fix.dart'; | 11 import 'package:analysis_services/correction/fix.dart'; |
| 12 import 'package:analysis_services/search/hierarchy.dart'; | |
| 12 import 'package:analysis_services/search/search_engine.dart'; | 13 import 'package:analysis_services/search/search_engine.dart'; |
| 14 import 'package:analysis_services/src/correction/levenshtein.dart'; | |
| 13 import 'package:analysis_services/src/correction/name_suggestion.dart'; | 15 import 'package:analysis_services/src/correction/name_suggestion.dart'; |
| 14 import 'package:analysis_services/src/correction/source_buffer.dart'; | 16 import 'package:analysis_services/src/correction/source_buffer.dart'; |
| 15 import 'package:analysis_services/src/correction/source_range.dart' as rf; | 17 import 'package:analysis_services/src/correction/source_range.dart' as rf; |
| 16 import 'package:analysis_services/src/correction/strings.dart'; | 18 import 'package:analysis_services/src/correction/strings.dart'; |
| 17 import 'package:analysis_services/src/correction/util.dart'; | 19 import 'package:analysis_services/src/correction/util.dart'; |
| 18 import 'package:analyzer/src/generated/ast.dart'; | 20 import 'package:analyzer/src/generated/ast.dart'; |
| 19 import 'package:analyzer/src/generated/element.dart'; | 21 import 'package:analyzer/src/generated/element.dart'; |
| 20 import 'package:analyzer/src/generated/error.dart'; | 22 import 'package:analyzer/src/generated/error.dart'; |
| 21 import 'package:analyzer/src/generated/java_core.dart'; | 23 import 'package:analyzer/src/generated/java_core.dart'; |
| 22 import 'package:analyzer/src/generated/parser.dart'; | 24 import 'package:analyzer/src/generated/parser.dart'; |
| 23 import 'package:analyzer/src/generated/scanner.dart'; | 25 import 'package:analyzer/src/generated/scanner.dart'; |
| 24 import 'package:analyzer/src/generated/source.dart'; | 26 import 'package:analyzer/src/generated/source.dart'; |
| 25 import 'package:analyzer/src/generated/utilities_dart.dart'; | 27 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 26 | 28 |
| 27 | 29 |
| 28 /** | 30 /** |
| 31 * A predicate is a one-argument function that returns a boolean value. | |
| 32 */ | |
| 33 typedef bool Predicate<E>(E argument); | |
| 34 | |
| 35 | |
| 36 /** | |
| 29 * The computer for Dart fixes. | 37 * The computer for Dart fixes. |
| 30 */ | 38 */ |
| 31 class FixProcessor { | 39 class FixProcessor { |
| 32 final SearchEngine searchEngine; | 40 final SearchEngine searchEngine; |
| 33 final Source source; | 41 final Source source; |
| 34 final String file; | 42 final String file; |
| 35 final CompilationUnit unit; | 43 final CompilationUnit unit; |
| 36 final AnalysisError error; | 44 final AnalysisError error; |
| 37 CompilationUnitElement unitElement; | 45 CompilationUnitElement unitElement; |
| 38 LibraryElement unitLibraryElement; | 46 LibraryElement unitLibraryElement; |
| (...skipping 972 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1011 | 1019 |
| 1012 void _addFix_replaceWithConstInstanceCreation() { | 1020 void _addFix_replaceWithConstInstanceCreation() { |
| 1013 if (coveredNode is InstanceCreationExpression) { | 1021 if (coveredNode is InstanceCreationExpression) { |
| 1014 var instanceCreation = coveredNode as InstanceCreationExpression; | 1022 var instanceCreation = coveredNode as InstanceCreationExpression; |
| 1015 _addReplaceEdit(rf.rangeToken(instanceCreation.keyword), "const"); | 1023 _addReplaceEdit(rf.rangeToken(instanceCreation.keyword), "const"); |
| 1016 _addFix(FixKind.USE_CONST, []); | 1024 _addFix(FixKind.USE_CONST, []); |
| 1017 } | 1025 } |
| 1018 } | 1026 } |
| 1019 | 1027 |
| 1020 void _addFix_undefinedClass_useSimilar() { | 1028 void _addFix_undefinedClass_useSimilar() { |
| 1021 // TODO(scheglov) implement | 1029 if (_mayBeTypeIdentifier(node)) { |
| 1022 // if (_mayBeTypeIdentifier(node)) { | 1030 String name = (node as SimpleIdentifier).name; |
| 1023 // String name = (node as SimpleIdentifier).name; | 1031 _ClosestElementFinder finder = |
| 1024 // QuickFixProcessorImpl_ClosestElementFinder finder = | 1032 new _ClosestElementFinder(name, (Element element) => element is ClassE lement); |
| 1025 // new QuickFixProcessorImpl_ClosestElementFinder( | 1033 // find closest element |
| 1026 // name, | 1034 { |
| 1027 // new Predicate_QuickFixProcessorImpl_addFix_undefinedClass_useSim ilar()); | 1035 // elements of this library |
| 1028 // // find closest element | 1036 for (CompilationUnitElement unit in unitLibraryElement.units) { |
| 1029 // { | 1037 finder._updateList(unit.types); |
| 1030 // // elements of this library | 1038 } |
| 1031 // _unitLibraryElement.accept( | 1039 // elements from imports |
| 1032 // new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefined Class_useSimilar( | 1040 for (ImportElement importElement in unitLibraryElement.imports) { |
| 1033 // finder)); | 1041 if (importElement.prefix == null) { |
| 1034 // // elements from imports | 1042 Map<String, Element> namespace = getImportNamespace(importElement); |
| 1035 // for (ImportElement importElement in _unitLibraryElement.imports) { | 1043 finder._updateList(namespace.values); |
| 1036 // if (importElement.prefix == null) { | 1044 } |
| 1037 // Map<String, Element> namespace = | 1045 } |
| 1038 // CorrectionUtils.getImportNamespace(importElement); | 1046 } |
| 1039 // finder._update2(namespace.values); | 1047 // if we have close enough element, suggest to use it |
| 1040 // } | 1048 if (finder != null && finder._distance < 5) { |
| 1041 // } | 1049 String closestName = finder._element.name; |
| 1042 // } | 1050 _addReplaceEdit(rf.rangeNode(node), closestName); |
| 1043 // // if we have close enough element, suggest to use it | 1051 // add proposal |
| 1044 // if (finder != null && finder._distance < 5) { | 1052 if (closestName != null) { |
| 1045 // String closestName = finder._element.name; | 1053 _addFix(FixKind.CHANGE_TO, [closestName]); |
| 1046 // _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName); | 1054 } |
| 1047 // // add proposal | 1055 } |
| 1048 // if (closestName != null) { | 1056 } |
| 1049 // _addFix( | |
| 1050 // FixKind.CHANGE_TO, | |
| 1051 // [closestName]); | |
| 1052 // } | |
| 1053 // } | |
| 1054 // } | |
| 1055 } | 1057 } |
| 1056 | 1058 |
| 1057 void _addFix_undefinedFunction_create() { | 1059 void _addFix_undefinedFunction_create() { |
| 1058 // should be the name of the invocation | 1060 // should be the name of the invocation |
| 1059 if (node is SimpleIdentifier && node.parent is MethodInvocation) { | 1061 if (node is SimpleIdentifier && node.parent is MethodInvocation) { |
| 1060 } else { | 1062 } else { |
| 1061 return; | 1063 return; |
| 1062 } | 1064 } |
| 1063 String name = (node as SimpleIdentifier).name; | 1065 String name = (node as SimpleIdentifier).name; |
| 1064 MethodInvocation invocation = node.parent as MethodInvocation; | 1066 MethodInvocation invocation = node.parent as MethodInvocation; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1092 _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList); | 1094 _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList); |
| 1093 sb.append(") {${eol}}"); | 1095 sb.append(") {${eol}}"); |
| 1094 } | 1096 } |
| 1095 // insert source | 1097 // insert source |
| 1096 _insertBuilder(sb); | 1098 _insertBuilder(sb); |
| 1097 _addLinkedPosition3('NAME', sb, rf.rangeNode(node)); | 1099 _addLinkedPosition3('NAME', sb, rf.rangeNode(node)); |
| 1098 // add proposal | 1100 // add proposal |
| 1099 _addFix(FixKind.CREATE_FUNCTION, [name]); | 1101 _addFix(FixKind.CREATE_FUNCTION, [name]); |
| 1100 } | 1102 } |
| 1101 | 1103 |
| 1102 void _addFix_undefinedFunction_useSimilar() { | 1104 void _addFix_undefinedFunction_useSimilar() { |
|
Paul Berry
2014/07/25 18:10:36
Any way we could share code between this function
| |
| 1103 // TODO(scheglov) implement | 1105 if (node is SimpleIdentifier) { |
| 1104 // if (node is SimpleIdentifier) { | 1106 String name = (node as SimpleIdentifier).name; |
| 1105 // String name = (node as SimpleIdentifier).name; | 1107 _ClosestElementFinder finder = |
| 1106 // QuickFixProcessorImpl_ClosestElementFinder finder = | 1108 new _ClosestElementFinder( |
| 1107 // new QuickFixProcessorImpl_ClosestElementFinder( | 1109 name, |
| 1108 // name, | 1110 (Element element) => element is FunctionElement); |
| 1109 // new Predicate_QuickFixProcessorImpl_addFix_undefinedFunction_use Similar()); | 1111 // this library |
| 1110 // // this library | 1112 for (CompilationUnitElement unit in unitLibraryElement.units) { |
| 1111 // _unitLibraryElement.accept( | 1113 finder._updateList(unit.functions); |
| 1112 // new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefinedFu nction_useSimilar( | 1114 } |
| 1113 // finder)); | 1115 // imports |
| 1114 // // imports | 1116 for (ImportElement importElement in unitLibraryElement.imports) { |
| 1115 // for (ImportElement importElement in _unitLibraryElement.imports) { | 1117 if (importElement.prefix == null) { |
| 1116 // if (importElement.prefix == null) { | 1118 Map<String, Element> namespace = getImportNamespace(importElement); |
| 1117 // Map<String, Element> namespace = | 1119 finder._updateList(namespace.values); |
| 1118 // CorrectionUtils.getImportNamespace(importElement); | 1120 } |
| 1119 // finder._update2(namespace.values); | 1121 } |
| 1120 // } | 1122 // if we have close enough element, suggest to use it |
| 1121 // } | 1123 String closestName = null; |
| 1122 // // if we have close enough element, suggest to use it | 1124 if (finder != null && finder._distance < 5) { |
| 1123 // String closestName = null; | 1125 closestName = finder._element.name; |
| 1124 // if (finder != null && finder._distance < 5) { | 1126 _addReplaceEdit(rf.rangeNode(node), closestName); |
| 1125 // closestName = finder._element.name; | 1127 _addFix(FixKind.CHANGE_TO, [closestName]); |
| 1126 // _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName); | 1128 } |
| 1127 // _addFix(FixKind.CHANGE_TO, [closestName]); | 1129 } |
| 1128 // } | |
| 1129 // } | |
| 1130 } | 1130 } |
| 1131 | 1131 |
| 1132 void _addFix_undefinedMethod_create() { | 1132 void _addFix_undefinedMethod_create() { |
| 1133 if (node is SimpleIdentifier && node.parent is MethodInvocation) { | 1133 if (node is SimpleIdentifier && node.parent is MethodInvocation) { |
| 1134 String name = (node as SimpleIdentifier).name; | 1134 String name = (node as SimpleIdentifier).name; |
| 1135 MethodInvocation invocation = node.parent as MethodInvocation; | 1135 MethodInvocation invocation = node.parent as MethodInvocation; |
| 1136 // prepare environment | 1136 // prepare environment |
| 1137 Source targetSource; | 1137 Source targetSource; |
| 1138 String prefix; | 1138 String prefix; |
| 1139 int insertOffset; | 1139 int insertOffset; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1236 excluded.add(favorite); | 1236 excluded.add(favorite); |
| 1237 sb.startPosition("ARG${i}"); | 1237 sb.startPosition("ARG${i}"); |
| 1238 sb.append(favorite); | 1238 sb.append(favorite); |
| 1239 sb.addProposals(suggestions); | 1239 sb.addProposals(suggestions); |
| 1240 sb.endPosition(); | 1240 sb.endPosition(); |
| 1241 } | 1241 } |
| 1242 } | 1242 } |
| 1243 } | 1243 } |
| 1244 | 1244 |
| 1245 void _addFix_undefinedMethod_useSimilar() { | 1245 void _addFix_undefinedMethod_useSimilar() { |
| 1246 // TODO(scheglov) implement | 1246 if (node is SimpleIdentifier && node.parent is MethodInvocation) { |
| 1247 // if (node is SimpleIdentifier && node.parent is MethodInvocation) { | 1247 MethodInvocation invocation = node.parent as MethodInvocation; |
| 1248 // MethodInvocation invocation = node.parent as MethodInvocation; | 1248 String name = (node as SimpleIdentifier).name; |
| 1249 // String name = (node as SimpleIdentifier).name; | 1249 _ClosestElementFinder finder = |
| 1250 // QuickFixProcessorImpl_ClosestElementFinder finder = | 1250 new _ClosestElementFinder(name, (Element element) { |
| 1251 // new QuickFixProcessorImpl_ClosestElementFinder( | 1251 return element is MethodElement && !element.isOperator; |
| 1252 // name, | 1252 }); |
| 1253 // new Predicate_QuickFixProcessorImpl_addFix_undefinedMethod_useSi milar()); | 1253 // unqualified invocation |
| 1254 // // unqualified invocation | 1254 Expression target = invocation.realTarget; |
| 1255 // Expression target = invocation.realTarget; | 1255 if (target == null) { |
| 1256 // if (target == null) { | 1256 ClassDeclaration clazz = |
| 1257 // ClassDeclaration clazz = | 1257 invocation.getAncestor((node) => node is ClassDeclaration); |
| 1258 // invocation.getAncestor((node) => node is ClassDeclaration); | 1258 if (clazz != null) { |
| 1259 // if (clazz != null) { | 1259 ClassElement classElement = clazz.element; |
| 1260 // ClassElement classElement = clazz.element; | 1260 _updateFinderWithClassMembers(finder, classElement); |
| 1261 // _updateFinderWithClassMembers(finder, classElement); | 1261 } |
| 1262 // } | 1262 } else { |
| 1263 // } else { | 1263 DartType type = target.bestType; |
| 1264 // DartType type = target.bestType; | 1264 if (type is InterfaceType) { |
| 1265 // if (type is InterfaceType) { | 1265 ClassElement classElement = type.element; |
| 1266 // ClassElement classElement = type.element; | 1266 _updateFinderWithClassMembers(finder, classElement); |
| 1267 // _updateFinderWithClassMembers(finder, classElement); | 1267 } |
| 1268 // } | 1268 } |
| 1269 // } | 1269 // if we have close enough element, suggest to use it |
| 1270 // // if we have close enough element, suggest to use it | 1270 String closestName = null; |
| 1271 // String closestName = null; | 1271 if (finder != null && finder._distance < 5) { |
| 1272 // if (finder != null && finder._distance < 5) { | 1272 closestName = finder._element.name; |
| 1273 // closestName = finder._element.name; | 1273 _addReplaceEdit(rf.rangeNode(node), closestName); |
| 1274 // _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName); | 1274 _addFix(FixKind.CHANGE_TO, [closestName]); |
| 1275 // _addFix(FixKind.CHANGE_TO, [closestName]); | 1275 } |
| 1276 // } | 1276 } |
| 1277 // } | |
| 1278 } | 1277 } |
| 1279 | 1278 |
| 1280 void _addFix_useEffectiveIntegerDivision() { | 1279 void _addFix_useEffectiveIntegerDivision() { |
| 1281 for (AstNode n = node; n != null; n = n.parent) { | 1280 for (AstNode n = node; n != null; n = n.parent) { |
| 1282 if (n is MethodInvocation && | 1281 if (n is MethodInvocation && |
| 1283 n.offset == errorOffset && | 1282 n.offset == errorOffset && |
| 1284 n.length == errorLength) { | 1283 n.length == errorLength) { |
| 1285 MethodInvocation invocation = n as MethodInvocation; | 1284 MethodInvocation invocation = n as MethodInvocation; |
| 1286 Expression target = invocation.target; | 1285 Expression target = invocation.target; |
| 1287 while (target is ParenthesizedExpression) { | 1286 while (target is ParenthesizedExpression) { |
| (...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1853 expr.parent as ParenthesizedExpression; | 1852 expr.parent as ParenthesizedExpression; |
| 1854 if (getExpressionParentPrecedence(parenthesized) > exprPrecedence) { | 1853 if (getExpressionParentPrecedence(parenthesized) > exprPrecedence) { |
| 1855 break; | 1854 break; |
| 1856 } | 1855 } |
| 1857 _addRemoveEdit(rf.rangeToken(parenthesized.leftParenthesis)); | 1856 _addRemoveEdit(rf.rangeToken(parenthesized.leftParenthesis)); |
| 1858 _addRemoveEdit(rf.rangeToken(parenthesized.rightParenthesis)); | 1857 _addRemoveEdit(rf.rangeToken(parenthesized.rightParenthesis)); |
| 1859 expr = parenthesized; | 1858 expr = parenthesized; |
| 1860 } | 1859 } |
| 1861 } | 1860 } |
| 1862 | 1861 |
| 1862 void _updateFinderWithClassMembers(_ClosestElementFinder finder, | |
| 1863 ClassElement clazz) { | |
| 1864 if (clazz != null) { | |
| 1865 List<Element> members = getMembers(clazz); | |
| 1866 finder._updateList(members); | |
| 1867 } | |
| 1868 } | |
| 1869 | |
| 1863 static void _addSuperTypeProposals(SourceBuilder sb, | 1870 static void _addSuperTypeProposals(SourceBuilder sb, |
| 1864 Set<DartType> alreadyAdded, DartType type) { | 1871 Set<DartType> alreadyAdded, DartType type) { |
| 1865 if (type != null && | 1872 if (type != null && |
| 1866 !alreadyAdded.contains(type) && | 1873 !alreadyAdded.contains(type) && |
| 1867 type.element is ClassElement) { | 1874 type.element is ClassElement) { |
| 1868 alreadyAdded.add(type); | 1875 alreadyAdded.add(type); |
| 1869 ClassElement element = type.element as ClassElement; | 1876 ClassElement element = type.element as ClassElement; |
| 1870 sb.addProposal(element.name); | 1877 sb.addProposal(element.name); |
| 1871 _addSuperTypeProposals(sb, alreadyAdded, element.supertype); | 1878 _addSuperTypeProposals(sb, alreadyAdded, element.supertype); |
| 1872 for (InterfaceType interfaceType in element.interfaces) { | 1879 for (InterfaceType interfaceType in element.interfaces) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1901 return parent.realTarget == node; | 1908 return parent.realTarget == node; |
| 1902 } | 1909 } |
| 1903 if (parent is PrefixedIdentifier) { | 1910 if (parent is PrefixedIdentifier) { |
| 1904 return parent.prefix == node; | 1911 return parent.prefix == node; |
| 1905 } | 1912 } |
| 1906 } | 1913 } |
| 1907 return false; | 1914 return false; |
| 1908 } | 1915 } |
| 1909 } | 1916 } |
| 1910 | 1917 |
| 1918 /** | |
| 1919 * Helper for finding [Element] with name closest to the given. | |
| 1920 */ | |
| 1921 class _ClosestElementFinder { | |
| 1922 final String _targetName; | |
| 1923 final Predicate<Element> _predicate; | |
| 1924 | |
| 1925 Element _element = null; | |
| 1926 int _distance = 1 << 10; | |
| 1927 | |
| 1928 _ClosestElementFinder(this._targetName, this._predicate); | |
| 1929 | |
| 1930 void _update(Element element) { | |
| 1931 if (_predicate(element)) { | |
| 1932 int memberDistance = getLevenshteinDistance(element.name, _targetName); | |
|
Paul Berry
2014/07/25 18:10:36
Levenshtein distance is O(n*m) to compute in the w
scheglov
2014/07/25 18:53:29
https://codereview.chromium.org/417263003
| |
| 1933 if (memberDistance < _distance) { | |
| 1934 _element = element; | |
| 1935 _distance = memberDistance; | |
| 1936 } | |
| 1937 } | |
| 1938 } | |
| 1939 | |
| 1940 void _updateList(Iterable<Element> elements) { | |
| 1941 for (Element element in elements) { | |
| 1942 _update(element); | |
| 1943 } | |
| 1944 } | |
| 1945 } | |
| 1911 | 1946 |
| 1912 /** | 1947 /** |
| 1913 * Describes the location for a newly created [ConstructorDeclaration]. | 1948 * Describes the location for a newly created [ConstructorDeclaration]. |
| 1914 */ | 1949 */ |
| 1915 class _ConstructorLocation { | 1950 class _ConstructorLocation { |
| 1916 final String _prefix; | 1951 final String _prefix; |
| 1917 final int _offset; | 1952 final int _offset; |
| 1918 final String _suffix; | 1953 final String _suffix; |
| 1919 | 1954 |
| 1920 _ConstructorLocation(this._prefix, this._offset, this._suffix); | 1955 _ConstructorLocation(this._prefix, this._offset, this._suffix); |
| 1921 } | 1956 } |
| OLD | NEW |