| 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 library services.correction.fix; | 5 library services.correction.fix; |
| 6 | 6 |
| 7 import 'package:analysis_services/correction/change.dart'; | 7 import 'package:analysis_services/correction/change.dart'; |
| 8 import 'package:analysis_services/correction/source_range_factory.dart' as rf; | |
| 9 import 'package:analysis_services/search/search_engine.dart'; | 8 import 'package:analysis_services/search/search_engine.dart'; |
| 9 import 'package:analysis_services/src/correction/fix.dart'; |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
| 11 import 'package:analyzer/src/generated/error.dart'; | 11 import 'package:analyzer/src/generated/error.dart'; |
| 12 import 'package:analyzer/src/generated/java_core.dart'; | |
| 13 import 'package:analyzer/src/generated/source.dart'; | |
| 14 | 12 |
| 15 | 13 |
| 16 /** | 14 /** |
| 17 * Computes [Fix]s for the given [AnalysisError]. | 15 * Computes [Fix]s for the given [AnalysisError]. |
| 18 * | 16 * |
| 19 * Returns the computed [Fix]s, not `null`. | 17 * Returns the computed [Fix]s, not `null`. |
| 20 */ | 18 */ |
| 21 List<Fix> computeFixes(SearchEngine searchEngine, String file, | 19 List<Fix> computeFixes(SearchEngine searchEngine, String file, |
| 22 CompilationUnit unit, AnalysisError error) { | 20 CompilationUnit unit, AnalysisError error) { |
| 23 var processor = new _FixProcessor(searchEngine, file, unit, error); | 21 var processor = new FixProcessor(searchEngine, file, unit, error); |
| 24 return processor.compute(); | 22 return processor.compute(); |
| 25 } | 23 } |
| 26 | 24 |
| 27 | 25 |
| 28 /** | 26 /** |
| 29 * A description of a single proposed fix for some problem. | 27 * A description of a single proposed fix for some problem. |
| 30 */ | 28 */ |
| 31 class Fix { | 29 class Fix { |
| 32 final FixKind kind; | 30 final FixKind kind; |
| 33 final Change change; | 31 final Change change; |
| 34 | 32 |
| 35 Fix(this.kind, this.change); | 33 Fix(this.kind, this.change); |
| 36 | 34 |
| 37 @override | 35 @override |
| 38 String toString() { | 36 String toString() { |
| 39 return '[kind=$kind, change=$change]'; | 37 return '[kind=$kind, change=$change]'; |
| 40 } | 38 } |
| 41 } | 39 } |
| 42 | 40 |
| 43 | 41 |
| 44 /** | 42 /** |
| 45 * An enumeration of possible quick fix kinds. | 43 * An enumeration of possible quick fix kinds. |
| 46 */ | 44 */ |
| 47 class FixKind { | 45 class FixKind { |
| 48 static const ADD_PACKAGE_DEPENDENCY = | 46 static const ADD_PACKAGE_DEPENDENCY = |
| 49 const FixKind( | 47 const FixKind('ADD_PACKAGE_DEPENDENCY', 50, "Add dependency on package '%s
'"); |
| 50 'QF_ADD_PACKAGE_DEPENDENCY', | |
| 51 50, | |
| 52 "Add dependency on package '%s'"); | |
| 53 static const ADD_SUPER_CONSTRUCTOR_INVOCATION = | 48 static const ADD_SUPER_CONSTRUCTOR_INVOCATION = |
| 54 const FixKind( | 49 const FixKind( |
| 55 'QF_ADD_SUPER_CONSTRUCTOR_INVOCATION', | 50 'ADD_SUPER_CONSTRUCTOR_INVOCATION', |
| 56 50, | 51 50, |
| 57 "Add super constructor %s invocation"); | 52 "Add super constructor %s invocation"); |
| 58 static const CHANGE_TO = const FixKind('QF_CHANGE_TO', 51, "Change to '%s'"); | 53 static const CHANGE_TO = const FixKind('CHANGE_TO', 51, "Change to '%s'"); |
| 59 static const CHANGE_TO_STATIC_ACCESS = | 54 static const CHANGE_TO_STATIC_ACCESS = |
| 60 const FixKind( | 55 const FixKind( |
| 61 'QF_CHANGE_TO_STATIC_ACCESS', | 56 'CHANGE_TO_STATIC_ACCESS', |
| 62 50, | 57 50, |
| 63 "Change access to static using '%s'"); | 58 "Change access to static using '%s'"); |
| 64 static const CREATE_CLASS = | 59 static const CREATE_CLASS = |
| 65 const FixKind('QF_CREATE_CLASS', 50, "Create class '%s'"); | 60 const FixKind('CREATE_CLASS', 50, "Create class '%s'"); |
| 66 static const CREATE_CONSTRUCTOR = | 61 static const CREATE_CONSTRUCTOR = |
| 67 const FixKind('QF_CREATE_CONSTRUCTOR', 50, "Create constructor '%s'"); | 62 const FixKind('CREATE_CONSTRUCTOR', 50, "Create constructor '%s'"); |
| 68 static const CREATE_CONSTRUCTOR_SUPER = | 63 static const CREATE_CONSTRUCTOR_SUPER = |
| 69 const FixKind( | 64 const FixKind('CREATE_CONSTRUCTOR_SUPER', 50, "Create constructor to call
%s"); |
| 70 'QF_CREATE_CONSTRUCTOR_SUPER', | |
| 71 50, | |
| 72 "Create constructor to call %s"); | |
| 73 static const CREATE_FUNCTION = | 65 static const CREATE_FUNCTION = |
| 74 const FixKind('QF_CREATE_FUNCTION', 49, "Create function '%s'"); | 66 const FixKind('CREATE_FUNCTION', 49, "Create function '%s'"); |
| 75 static const CREATE_METHOD = | 67 static const CREATE_METHOD = |
| 76 const FixKind('QF_CREATE_METHOD', 50, "Create method '%s'"); | 68 const FixKind('CREATE_METHOD', 50, "Create method '%s'"); |
| 77 static const CREATE_MISSING_OVERRIDES = | 69 static const CREATE_MISSING_OVERRIDES = |
| 78 const FixKind( | 70 const FixKind('CREATE_MISSING_OVERRIDES', 50, "Create %d missing override(
s)"); |
| 79 'QF_CREATE_MISSING_OVERRIDES', | |
| 80 50, | |
| 81 "Create %d missing override(s)"); | |
| 82 static const CREATE_NO_SUCH_METHOD = | 71 static const CREATE_NO_SUCH_METHOD = |
| 83 const FixKind('QF_CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' metho
d"); | 72 const FixKind('CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method")
; |
| 84 static const CREATE_PART = | 73 static const CREATE_PART = |
| 85 const FixKind('QF_CREATE_PART', 50, "Create part '%s'"); | 74 const FixKind('CREATE_PART', 50, "Create part '%s'"); |
| 86 static const IMPORT_LIBRARY_PREFIX = | 75 static const IMPORT_LIBRARY_PREFIX = |
| 87 const FixKind( | 76 const FixKind( |
| 88 'QF_IMPORT_LIBRARY_PREFIX', | 77 'IMPORT_LIBRARY_PREFIX', |
| 89 51, | 78 51, |
| 90 "Use imported library '%s' with prefix '%s'"); | 79 "Use imported library '%s' with prefix '%s'"); |
| 91 static const IMPORT_LIBRARY_PROJECT = | 80 static const IMPORT_LIBRARY_PROJECT = |
| 92 const FixKind('QF_IMPORT_LIBRARY_PROJECT', 51, "Import library '%s'"); | 81 const FixKind('IMPORT_LIBRARY_PROJECT', 51, "Import library '%s'"); |
| 93 static const IMPORT_LIBRARY_SDK = | 82 static const IMPORT_LIBRARY_SDK = |
| 94 const FixKind('QF_IMPORT_LIBRARY_SDK', 51, "Import library '%s'"); | 83 const FixKind('IMPORT_LIBRARY_SDK', 51, "Import library '%s'"); |
| 95 static const IMPORT_LIBRARY_SHOW = | 84 static const IMPORT_LIBRARY_SHOW = |
| 96 const FixKind('QF_IMPORT_LIBRARY_SHOW', 51, "Update library '%s' import"); | 85 const FixKind('IMPORT_LIBRARY_SHOW', 51, "Update library '%s' import"); |
| 97 static const INSERT_SEMICOLON = | 86 static const INSERT_SEMICOLON = |
| 98 const FixKind('QF_INSERT_SEMICOLON', 50, "Insert ';'"); | 87 const FixKind('INSERT_SEMICOLON', 50, "Insert ';'"); |
| 99 static const MAKE_CLASS_ABSTRACT = | 88 static const MAKE_CLASS_ABSTRACT = |
| 100 const FixKind('QF_MAKE_CLASS_ABSTRACT', 50, "Make class '%s' abstract"); | 89 const FixKind('MAKE_CLASS_ABSTRACT', 50, "Make class '%s' abstract"); |
| 101 static const REMOVE_PARAMETERS_IN_GETTER_DECLARATION = | 90 static const REMOVE_PARAMETERS_IN_GETTER_DECLARATION = |
| 102 const FixKind( | 91 const FixKind( |
| 103 'QF_REMOVE_PARAMETERS_IN_GETTER_DECLARATION', | 92 'REMOVE_PARAMETERS_IN_GETTER_DECLARATION', |
| 104 50, | 93 50, |
| 105 "Remove parameters in getter declaration"); | 94 "Remove parameters in getter declaration"); |
| 106 static const REMOVE_PARENTHESIS_IN_GETTER_INVOCATION = | 95 static const REMOVE_PARENTHESIS_IN_GETTER_INVOCATION = |
| 107 const FixKind( | 96 const FixKind( |
| 108 'QF_REMOVE_PARENTHESIS_IN_GETTER_INVOCATION', | 97 'REMOVE_PARENTHESIS_IN_GETTER_INVOCATION', |
| 109 50, | 98 50, |
| 110 "Remove parentheses in getter invocation"); | 99 "Remove parentheses in getter invocation"); |
| 111 static const REMOVE_UNNECASSARY_CAST = | 100 static const REMOVE_UNNECASSARY_CAST = |
| 112 const FixKind('QF_REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast")
; | 101 const FixKind('REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast"); |
| 113 static const REMOVE_UNUSED_IMPORT = | 102 static const REMOVE_UNUSED_IMPORT = |
| 114 const FixKind('QF_REMOVE_UNUSED_IMPORT', 50, "Remove unused import"); | 103 const FixKind('REMOVE_UNUSED_IMPORT', 50, "Remove unused import"); |
| 115 static const REPLACE_BOOLEAN_WITH_BOOL = | 104 static const REPLACE_BOOLEAN_WITH_BOOL = |
| 116 const FixKind( | 105 const FixKind('REPLACE_BOOLEAN_WITH_BOOL', 50, "Replace 'boolean' with 'bo
ol'"); |
| 117 'QF_REPLACE_BOOLEAN_WITH_BOOL', | 106 static const USE_CONST = const FixKind('USE_CONST', 50, "Change to constant"); |
| 118 50, | |
| 119 "Replace 'boolean' with 'bool'"); | |
| 120 static const USE_CONST = | |
| 121 const FixKind('QF_USE_CONST', 50, "Change to constant"); | |
| 122 static const USE_EFFECTIVE_INTEGER_DIVISION = | 107 static const USE_EFFECTIVE_INTEGER_DIVISION = |
| 123 const FixKind( | 108 const FixKind( |
| 124 'QF_USE_EFFECTIVE_INTEGER_DIVISION', | 109 'USE_EFFECTIVE_INTEGER_DIVISION', |
| 125 50, | 110 50, |
| 126 "Use effective integer division ~/"); | 111 "Use effective integer division ~/"); |
| 127 static const USE_EQ_EQ_NULL = | 112 static const USE_EQ_EQ_NULL = |
| 128 const FixKind('QF_USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'")
; | 113 const FixKind('USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'"); |
| 129 static const USE_NOT_EQ_NULL = | 114 static const USE_NOT_EQ_NULL = |
| 130 const FixKind('QF_USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'
"); | 115 const FixKind('USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'"); |
| 131 | 116 |
| 132 final name; | 117 final name; |
| 133 final int relevance; | 118 final int relevance; |
| 134 final String message; | 119 final String message; |
| 135 | 120 |
| 136 const FixKind(this.name, this.relevance, this.message); | 121 const FixKind(this.name, this.relevance, this.message); |
| 122 |
| 123 @override |
| 124 String toString() => name; |
| 137 } | 125 } |
| 138 | 126 |
| 139 | 127 |
| 140 /** | |
| 141 * The computer for Dart fixes. | |
| 142 */ | |
| 143 class _FixProcessor { | |
| 144 final SearchEngine searchEngine; | |
| 145 final String file; | |
| 146 final CompilationUnit unit; | |
| 147 final AnalysisError error; | |
| 148 | |
| 149 final List<Fix> fixes = <Fix>[]; | |
| 150 final List<Edit> edits = <Edit>[]; | |
| 151 | |
| 152 | |
| 153 _FixProcessor(this.searchEngine, this.file, this.unit, this.error); | |
| 154 | |
| 155 List<Fix> compute() { | |
| 156 ErrorCode errorCode = error.errorCode; | |
| 157 if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) { | |
| 158 _addFix_boolInsteadOfBoolean(); | |
| 159 } | |
| 160 return fixes; | |
| 161 } | |
| 162 | |
| 163 void _addFix(FixKind kind, List args) { | |
| 164 FileEdit fileEdit = new FileEdit(file); | |
| 165 edits.forEach((edit) => fileEdit.add(edit)); | |
| 166 // prepare Change | |
| 167 String message = JavaString.format(kind.message, args); | |
| 168 Change change = new Change(message); | |
| 169 change.add(fileEdit); | |
| 170 // add Fix | |
| 171 var fix = new Fix(kind, change); | |
| 172 fixes.add(fix); | |
| 173 } | |
| 174 | |
| 175 void _addFix_boolInsteadOfBoolean() { | |
| 176 SourceRange range = rf.rangeError(error); | |
| 177 _addReplaceEdit(range, "bool"); | |
| 178 _addFix(FixKind.REPLACE_BOOLEAN_WITH_BOOL, []); | |
| 179 } | |
| 180 | |
| 181 /** | |
| 182 * Adds a new [Edit] to [edits]. | |
| 183 */ | |
| 184 void _addReplaceEdit(SourceRange range, String text) { | |
| 185 Edit edit = new Edit.range(range, text); | |
| 186 edits.add(edit); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 | |
| 191 ///** | 128 ///** |
| 192 // * An enumeration of possible quick assist kinds. | 129 // * An enumeration of possible quick assist kinds. |
| 193 // */ | 130 // */ |
| 194 //class AssistKind { | 131 //class AssistKind { |
| 195 // static const QA_ADD_PART_DIRECTIVE = | 132 // static const QA_ADD_PART_DIRECTIVE = |
| 196 // const AssistKind('QA_ADD_PART_DIRECTIVE', 30, "Add 'part' directive"); | 133 // const AssistKind('QA_ADD_PART_DIRECTIVE', 30, "Add 'part' directive"); |
| 197 // static const QA_ADD_TYPE_ANNOTATION = | 134 // static const QA_ADD_TYPE_ANNOTATION = |
| 198 // const AssistKind('QA_ADD_TYPE_ANNOTATION', 30, "Add type annotation"); | 135 // const AssistKind('QA_ADD_TYPE_ANNOTATION', 30, "Add type annotation"); |
| 199 // static const QA_ASSIGN_TO_LOCAL_VARIABLE = | 136 // static const QA_ASSIGN_TO_LOCAL_VARIABLE = |
| 200 // const AssistKind( | 137 // const AssistKind( |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 // "Surround with 'try-finally'"); | 213 // "Surround with 'try-finally'"); |
| 277 // static const QA_SURROUND_WITH_WHILE = | 214 // static const QA_SURROUND_WITH_WHILE = |
| 278 // const AssistKind('QA_SURROUND_WITH_WHILE', 30, "Surround with 'while'"); | 215 // const AssistKind('QA_SURROUND_WITH_WHILE', 30, "Surround with 'while'"); |
| 279 // | 216 // |
| 280 // final name; | 217 // final name; |
| 281 // final int relevance; | 218 // final int relevance; |
| 282 // final String message; | 219 // final String message; |
| 283 // | 220 // |
| 284 // const AssistKind(this.name, this.relevance, this.message); | 221 // const AssistKind(this.name, this.relevance, this.message); |
| 285 //} | 222 //} |
| OLD | NEW |