| 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.search_engine; | 5 library services.search_engine; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/element/element.dart'; | 9 import 'package:analyzer/dart/element/element.dart'; |
| 10 import 'package:analyzer/dart/element/visitor.dart'; | |
| 11 import 'package:analyzer/src/dart/element/element.dart'; | |
| 12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | |
| 13 import 'package:analyzer/src/generated/source.dart'; | 10 import 'package:analyzer/src/generated/source.dart'; |
| 14 import 'package:analyzer/src/generated/utilities_general.dart'; | |
| 15 | 11 |
| 16 /** | 12 /** |
| 17 * Instances of the enum [MatchKind] represent the kind of reference that was | 13 * Instances of the enum [MatchKind] represent the kind of reference that was |
| 18 * found when a match represents a reference to an element. | 14 * found when a match represents a reference to an element. |
| 19 */ | 15 */ |
| 20 class MatchKind { | 16 class MatchKind { |
| 21 /** | 17 /** |
| 22 * A declaration of an element. | 18 * A declaration of an element. |
| 23 */ | 19 */ |
| 24 static const MatchKind DECLARATION = const MatchKind('DECLARATION'); | 20 static const MatchKind DECLARATION = const MatchKind('DECLARATION'); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 * [pattern] the regular expression used to match the names of the | 99 * [pattern] the regular expression used to match the names of the |
| 104 * declarations to be found. | 100 * declarations to be found. |
| 105 */ | 101 */ |
| 106 Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern); | 102 Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern); |
| 107 } | 103 } |
| 108 | 104 |
| 109 /** | 105 /** |
| 110 * Instances of the class [SearchMatch] represent a match found by | 106 * Instances of the class [SearchMatch] represent a match found by |
| 111 * [SearchEngine]. | 107 * [SearchEngine]. |
| 112 */ | 108 */ |
| 113 class SearchMatch { | 109 abstract class SearchMatch { |
| 114 /** | |
| 115 * The [AnalysisContext] containing the match. | |
| 116 */ | |
| 117 final AnalysisContext context; | |
| 118 | |
| 119 /** | |
| 120 * The URI of the source of the library containing the match. | |
| 121 */ | |
| 122 final String libraryUri; | |
| 123 | |
| 124 /** | |
| 125 * The URI of the source of the unit containing the match. | |
| 126 */ | |
| 127 final String unitUri; | |
| 128 | |
| 129 /** | |
| 130 * The kind of the match. | |
| 131 */ | |
| 132 final MatchKind kind; | |
| 133 | |
| 134 /** | |
| 135 * The source range that was matched. | |
| 136 */ | |
| 137 final SourceRange sourceRange; | |
| 138 | |
| 139 /** | |
| 140 * Is `true` if the match is a resolved reference to some [Element]. | |
| 141 */ | |
| 142 final bool isResolved; | |
| 143 | |
| 144 /** | |
| 145 * Is `true` if field or method access is done using qualifier. | |
| 146 */ | |
| 147 final bool isQualified; | |
| 148 | |
| 149 Source _librarySource; | |
| 150 Source _unitSource; | |
| 151 LibraryElement _libraryElement; | |
| 152 Element _element; | |
| 153 | |
| 154 SearchMatch(this.context, this.libraryUri, this.unitUri, this.kind, | |
| 155 this.sourceRange, this.isResolved, this.isQualified); | |
| 156 | |
| 157 /** | 110 /** |
| 158 * Return the [Element] containing the match. Can return `null` if the unit | 111 * Return the [Element] containing the match. Can return `null` if the unit |
| 159 * does not exist, or its element was invalidated, or the element cannot be | 112 * does not exist, or its element was invalidated, or the element cannot be |
| 160 * found, etc. | 113 * found, etc. |
| 161 */ | 114 */ |
| 162 Element get element { | 115 Element get element; |
| 163 if (_element == null) { | |
| 164 CompilationUnitElement unitElement = | |
| 165 context.getCompilationUnitElement(unitSource, librarySource); | |
| 166 if (unitElement != null) { | |
| 167 _ContainingElementFinder finder = | |
| 168 new _ContainingElementFinder(sourceRange.offset); | |
| 169 unitElement.accept(finder); | |
| 170 _element = finder.containingElement; | |
| 171 } | |
| 172 } | |
| 173 return _element; | |
| 174 } | |
| 175 | 116 |
| 176 /** | 117 /** |
| 177 * The absolute path of the file containing the match. | 118 * The absolute path of the file containing the match. |
| 178 */ | 119 */ |
| 179 String get file => unitSource.fullName; | 120 String get file; |
| 180 | 121 |
| 181 @override | 122 /** |
| 182 int get hashCode { | 123 * Is `true` if field or method access is done using qualifier. |
| 183 return JenkinsSmiHash.hash4(libraryUri.hashCode, unitUri.hashCode, | 124 */ |
| 184 kind.hashCode, sourceRange.hashCode); | 125 bool get isQualified; |
| 185 } | 126 |
| 127 /** |
| 128 * Is `true` if the match is a resolved reference to some [Element]. |
| 129 */ |
| 130 bool get isResolved; |
| 131 |
| 132 /** |
| 133 * The kind of the match. |
| 134 */ |
| 135 MatchKind get kind; |
| 186 | 136 |
| 187 /** | 137 /** |
| 188 * Return the [LibraryElement] for the [libraryUri] in the [context]. | 138 * Return the [LibraryElement] for the [libraryUri] in the [context]. |
| 189 */ | 139 */ |
| 190 LibraryElement get libraryElement { | 140 LibraryElement get libraryElement; |
| 191 _libraryElement ??= context.getLibraryElement(librarySource); | |
| 192 return _libraryElement; | |
| 193 } | |
| 194 | 141 |
| 195 /** | 142 /** |
| 196 * The library [Source] of the reference. | 143 * The library [Source] of the reference. |
| 197 */ | 144 */ |
| 198 Source get librarySource { | 145 Source get librarySource; |
| 199 _librarySource ??= context.sourceFactory.forUri(libraryUri); | 146 |
| 200 return _librarySource; | 147 /** |
| 201 } | 148 * The source range that was matched. |
| 149 */ |
| 150 SourceRange get sourceRange; |
| 202 | 151 |
| 203 /** | 152 /** |
| 204 * The unit [Source] of the reference. | 153 * The unit [Source] of the reference. |
| 205 */ | 154 */ |
| 206 Source get unitSource { | 155 Source get unitSource; |
| 207 _unitSource ??= context.sourceFactory.forUri(unitUri); | |
| 208 return _unitSource; | |
| 209 } | |
| 210 | |
| 211 @override | |
| 212 bool operator ==(Object object) { | |
| 213 if (identical(object, this)) { | |
| 214 return true; | |
| 215 } | |
| 216 if (object is SearchMatch) { | |
| 217 return kind == object.kind && | |
| 218 libraryUri == object.libraryUri && | |
| 219 unitUri == object.unitUri && | |
| 220 isResolved == object.isResolved && | |
| 221 isQualified == object.isQualified && | |
| 222 sourceRange == object.sourceRange; | |
| 223 } | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 @override | |
| 228 String toString() { | |
| 229 StringBuffer buffer = new StringBuffer(); | |
| 230 buffer.write("SearchMatch(kind="); | |
| 231 buffer.write(kind); | |
| 232 buffer.write(", libraryUri="); | |
| 233 buffer.write(libraryUri); | |
| 234 buffer.write(", unitUri="); | |
| 235 buffer.write(unitUri); | |
| 236 buffer.write(", range="); | |
| 237 buffer.write(sourceRange); | |
| 238 buffer.write(", isResolved="); | |
| 239 buffer.write(isResolved); | |
| 240 buffer.write(", isQualified="); | |
| 241 buffer.write(isQualified); | |
| 242 buffer.write(")"); | |
| 243 return buffer.toString(); | |
| 244 } | |
| 245 | 156 |
| 246 /** | 157 /** |
| 247 * Return elements of [matches] which has not-null elements. | 158 * Return elements of [matches] which has not-null elements. |
| 248 * | 159 * |
| 249 * When [SearchMatch.element] is not `null` we cache its value, so it cannot | 160 * When [SearchMatch.element] is not `null` we cache its value, so it cannot |
| 250 * become `null` later. | 161 * become `null` later. |
| 251 */ | 162 */ |
| 252 static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) { | 163 static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) { |
| 253 return matches.where((match) => match.element != null).toList(); | 164 return matches.where((match) => match.element != null).toList(); |
| 254 } | 165 } |
| 255 } | 166 } |
| 256 | |
| 257 /** | |
| 258 * A visitor that finds the deep-most [Element] that contains the [offset]. | |
| 259 */ | |
| 260 class _ContainingElementFinder extends GeneralizingElementVisitor { | |
| 261 final int offset; | |
| 262 Element containingElement; | |
| 263 | |
| 264 _ContainingElementFinder(this.offset); | |
| 265 | |
| 266 visitElement(Element element) { | |
| 267 if (element is ElementImpl) { | |
| 268 if (element.codeOffset != null && | |
| 269 element.codeOffset <= offset && | |
| 270 offset <= element.codeOffset + element.codeLength) { | |
| 271 containingElement = element; | |
| 272 super.visitElement(element); | |
| 273 } | |
| 274 } | |
| 275 } | |
| 276 } | |
| OLD | NEW |