| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library kernel.library_index; | 4 library kernel.library_index; |
| 5 | 5 |
| 6 import 'ast.dart'; | 6 import 'ast.dart'; |
| 7 | 7 |
| 8 /// Provides name-based access to library, class, and member AST nodes. | 8 /// Provides name-based access to library, class, and member AST nodes. |
| 9 /// | 9 /// |
| 10 /// When constructed, a given set of libraries are indexed immediately, and | 10 /// When constructed, a given set of libraries are indexed immediately, and |
| 11 /// will not be up-to-date with changes made after it was created. | 11 /// will not be up-to-date with changes made after it was created. |
| 12 class LibraryIndex { | 12 class LibraryIndex { |
| 13 static const String getterPrefix = 'get:'; | 13 static const String getterPrefix = 'get:'; |
| 14 static const String setterPrefix = 'set:'; | 14 static const String setterPrefix = 'set:'; |
| 15 | 15 |
| 16 /// A special class name that can be used to access the top-level members | 16 /// A special class name that can be used to access the top-level members |
| 17 /// of a library. | 17 /// of a library. |
| 18 static const String topLevel = '::'; | 18 static const String topLevel = '::'; |
| 19 | 19 |
| 20 final Map<String, _ClassTable> _libraries = <String, _ClassTable>{}; | 20 final Map<String, _ClassTable> _libraries = <String, _ClassTable>{}; |
| 21 | 21 |
| 22 /// Indexes the libraries with the URIs given in [libraryUris]. | 22 /// Indexes the libraries with the URIs given in [libraryUris]. |
| 23 LibraryIndex(Program program, Iterable<String> libraryUris) { | 23 LibraryIndex(Program program, Iterable<String> libraryUris) { |
| 24 for (var uri in libraryUris) { | 24 var libraryUriSet = libraryUris.toSet(); |
| 25 _libraries[uri] = new _ClassTable(); | |
| 26 } | |
| 27 for (var library in program.libraries) { | 25 for (var library in program.libraries) { |
| 28 var index = _libraries['${library.importUri}']; | 26 var uri = '${library.importUri}'; |
| 29 if (index != null) { | 27 if (libraryUriSet.contains(uri)) { |
| 30 index.build(library); | 28 _libraries[uri] = new _ClassTable(library); |
| 31 } | 29 } |
| 32 } | 30 } |
| 33 } | 31 } |
| 34 | 32 |
| 35 /// Indexes the libraries with the URIs given in [libraryUris]. | 33 /// Indexes the libraries with the URIs given in [libraryUris]. |
| 36 LibraryIndex.byUri(Program program, Iterable<Uri> libraryUris) | 34 LibraryIndex.byUri(Program program, Iterable<Uri> libraryUris) |
| 37 : this(program, libraryUris.map((uri) => '$uri')); | 35 : this(program, libraryUris.map((uri) => '$uri')); |
| 38 | 36 |
| 39 /// Indexes the libraries with the URIs given in [libraryUris]. | 37 /// Indexes `dart:` libraries. |
| 40 LibraryIndex.coreLibraries(Program program) { | 38 LibraryIndex.coreLibraries(Program program) { |
| 41 for (var library in program.libraries) { | 39 for (var library in program.libraries) { |
| 42 if (library.importUri.scheme == 'dart') { | 40 if (library.importUri.scheme == 'dart') { |
| 43 _libraries['${library.importUri}'] = new _ClassTable()..build(library); | 41 _libraries['${library.importUri}'] = new _ClassTable(library); |
| 44 } | 42 } |
| 45 } | 43 } |
| 46 } | 44 } |
| 47 | 45 |
| 48 /// Indexes the entire program. | 46 /// Indexes the entire program. |
| 49 /// | 47 /// |
| 50 /// Consider using another constructor to only index the libraries that | 48 /// Consider using another constructor to only index the libraries that |
| 51 /// are needed. | 49 /// are needed. |
| 52 LibraryIndex.all(Program program) { | 50 LibraryIndex.all(Program program) { |
| 53 for (var library in program.libraries) { | 51 for (var library in program.libraries) { |
| 54 _libraries['${library.importUri}'] = new _ClassTable()..build(library); | 52 _libraries['${library.importUri}'] = new _ClassTable(library); |
| 55 } | 53 } |
| 56 } | 54 } |
| 57 | 55 |
| 58 _ClassTable _getLibraryIndex(String uri) { | 56 _ClassTable _getLibraryIndex(String uri) { |
| 59 _ClassTable libraryIndex = _libraries[uri]; | 57 _ClassTable libraryIndex = _libraries[uri]; |
| 60 if (libraryIndex == null) { | 58 if (libraryIndex == null) { |
| 61 throw "The library '$uri' has not been indexed"; | 59 throw "The library '$uri' has not been indexed"; |
| 62 } | 60 } |
| 63 return libraryIndex; | 61 return libraryIndex; |
| 64 } | 62 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 } | 121 } |
| 124 | 122 |
| 125 /// Like [getTopLevelMember] but returns `null` if not found. | 123 /// Like [getTopLevelMember] but returns `null` if not found. |
| 126 Member tryGetTopLevelMember( | 124 Member tryGetTopLevelMember( |
| 127 String library, String className, String memberName) { | 125 String library, String className, String memberName) { |
| 128 return tryGetMember(library, topLevel, memberName); | 126 return tryGetMember(library, topLevel, memberName); |
| 129 } | 127 } |
| 130 } | 128 } |
| 131 | 129 |
| 132 class _ClassTable { | 130 class _ClassTable { |
| 133 Library library; | 131 final Library library; |
| 134 final Map<String, _MemberTable> classes = <String, _MemberTable>{}; | |
| 135 | 132 |
| 136 void build(Library library) { | 133 Map<String, _MemberTable> _classes; |
| 137 this.library = library; | 134 |
| 138 classes[LibraryIndex.topLevel] = new _MemberTable.topLevel(this); | 135 _ClassTable(this.library); |
| 139 for (var class_ in library.classes) { | 136 |
| 140 classes[class_.name] = new _MemberTable(this, class_); | 137 Map<String, _MemberTable> get classes { |
| 138 if (_classes == null) { |
| 139 _classes = <String, _MemberTable>{}; |
| 140 _classes[LibraryIndex.topLevel] = new _MemberTable.topLevel(this); |
| 141 for (var class_ in library.classes) { |
| 142 _classes[class_.name] = new _MemberTable(this, class_); |
| 143 } |
| 141 } | 144 } |
| 145 return _classes; |
| 142 } | 146 } |
| 143 | 147 |
| 144 String get containerName { | 148 String get containerName { |
| 145 // For useful error messages, it can be helpful to indicate if the library | 149 // For useful error messages, it can be helpful to indicate if the library |
| 146 // is external. If a class or member was not found in an external library, | 150 // is external. If a class or member was not found in an external library, |
| 147 // it might be that it exists in the actual library, but its interface was | 151 // it might be that it exists in the actual library, but its interface was |
| 148 // not included in this build unit. | 152 // not included in this build unit. |
| 149 return library.isExternal | 153 return library.isExternal |
| 150 ? "external library '${library.importUri}'" | 154 ? "external library '${library.importUri}'" |
| 151 : "library '${library.importUri}'"; | 155 : "library '${library.importUri}'"; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 172 } | 176 } |
| 173 | 177 |
| 174 Member tryGetMember(String className, String memberName) { | 178 Member tryGetMember(String className, String memberName) { |
| 175 return classes[className]?.tryGetMember(memberName); | 179 return classes[className]?.tryGetMember(memberName); |
| 176 } | 180 } |
| 177 } | 181 } |
| 178 | 182 |
| 179 class _MemberTable { | 183 class _MemberTable { |
| 180 final _ClassTable parent; | 184 final _ClassTable parent; |
| 181 final Class class_; // Null for top-level. | 185 final Class class_; // Null for top-level. |
| 182 final Map<String, Member> members = <String, Member>{}; | 186 Map<String, Member> _members; |
| 183 | 187 |
| 184 Library get library => parent.library; | 188 Library get library => parent.library; |
| 185 | 189 |
| 186 _MemberTable(this.parent, this.class_) { | 190 _MemberTable(this.parent, this.class_); |
| 187 class_.procedures.forEach(addMember); | |
| 188 class_.fields.forEach(addMember); | |
| 189 class_.constructors.forEach(addMember); | |
| 190 } | |
| 191 | 191 |
| 192 _MemberTable.topLevel(this.parent) : class_ = null { | 192 _MemberTable.topLevel(this.parent) : class_ = null; |
| 193 library.procedures.forEach(addMember); | 193 |
| 194 library.fields.forEach(addMember); | 194 Map<String, Member> get members { |
| 195 if (_members == null) { |
| 196 _members = <String, Member>{}; |
| 197 if (class_ != null) { |
| 198 class_.procedures.forEach(addMember); |
| 199 class_.fields.forEach(addMember); |
| 200 class_.constructors.forEach(addMember); |
| 201 } else { |
| 202 library.procedures.forEach(addMember); |
| 203 library.fields.forEach(addMember); |
| 204 } |
| 205 } |
| 206 return _members; |
| 195 } | 207 } |
| 196 | 208 |
| 197 String getDisambiguatedName(Member member) { | 209 String getDisambiguatedName(Member member) { |
| 198 if (member is Procedure) { | 210 if (member is Procedure) { |
| 199 if (member.isGetter) return LibraryIndex.getterPrefix + member.name.name; | 211 if (member.isGetter) return LibraryIndex.getterPrefix + member.name.name; |
| 200 if (member.isSetter) return LibraryIndex.setterPrefix + member.name.name; | 212 if (member.isSetter) return LibraryIndex.setterPrefix + member.name.name; |
| 201 } | 213 } |
| 202 return member.name.name; | 214 return member.name.name; |
| 203 } | 215 } |
| 204 | 216 |
| 205 void addMember(Member member) { | 217 void addMember(Member member) { |
| 206 if (member.name.isPrivate && member.name.library != library) { | 218 if (member.name.isPrivate && member.name.library != library) { |
| 207 // Members whose name is private to other libraries cannot currently | 219 // Members whose name is private to other libraries cannot currently |
| 208 // be found with the LibraryIndex class. | 220 // be found with the LibraryIndex class. |
| 209 return; | 221 return; |
| 210 } | 222 } |
| 211 members[getDisambiguatedName(member)] = member; | 223 _members[getDisambiguatedName(member)] = member; |
| 212 } | 224 } |
| 213 | 225 |
| 214 String get containerName { | 226 String get containerName { |
| 215 if (class_ == null) { | 227 if (class_ == null) { |
| 216 return "top-level of ${parent.containerName}"; | 228 return "top-level of ${parent.containerName}"; |
| 217 } else { | 229 } else { |
| 218 return "class '${class_.name}' in ${parent.containerName}"; | 230 return "class '${class_.name}' in ${parent.containerName}"; |
| 219 } | 231 } |
| 220 } | 232 } |
| 221 | 233 |
| 222 Member getMember(String name) { | 234 Member getMember(String name) { |
| 223 var member = members[name]; | 235 var member = members[name]; |
| 224 if (member == null) { | 236 if (member == null) { |
| 225 String message = "A member with disambiguated name '$name' was not found " | 237 String message = "A member with disambiguated name '$name' was not found " |
| 226 "in $containerName"; | 238 "in $containerName"; |
| 227 var getter = LibraryIndex.getterPrefix + name; | 239 var getter = LibraryIndex.getterPrefix + name; |
| 228 var setter = LibraryIndex.setterPrefix + name; | 240 var setter = LibraryIndex.setterPrefix + name; |
| 229 if (members[getter] != null || members[setter] != null) { | 241 if (members[getter] != null || members[setter] != null) { |
| 230 throw "$message. Did you mean '$getter' or '$setter'?"; | 242 throw "$message. Did you mean '$getter' or '$setter'?"; |
| 231 } | 243 } |
| 232 throw message; | 244 throw message; |
| 233 } | 245 } |
| 234 return member; | 246 return member; |
| 235 } | 247 } |
| 236 | 248 |
| 237 Member tryGetMember(String name) => members[name]; | 249 Member tryGetMember(String name) => members[name]; |
| 238 } | 250 } |
| OLD | NEW |