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

Side by Side Diff: pkg/analyzer/lib/src/task/incremental_element_builder.dart

Issue 1119683004: Incrementally build unit member elements. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/analyzer/test/src/task/incremental_element_builder_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 analyzer.src.task.incremental_element_builder; 5 library analyzer.src.task.incremental_element_builder;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/src/generated/ast.dart'; 9 import 'package:analyzer/src/generated/ast.dart';
10 import 'package:analyzer/src/generated/element.dart'; 10 import 'package:analyzer/src/generated/element.dart';
11 import 'package:analyzer/src/generated/resolver.dart'; 11 import 'package:analyzer/src/generated/resolver.dart';
12 import 'package:analyzer/src/generated/scanner.dart'; 12 import 'package:analyzer/src/generated/scanner.dart';
13 import 'package:analyzer/src/generated/source.dart'; 13 import 'package:analyzer/src/generated/source.dart';
14 14
15 /** 15 /**
16 * Incrementally updates the existing [oldUnitElement] and builds elements for 16 * Incrementally updates the existing [unitElement] and builds elements for
17 * the [newUnit]. 17 * the [newUnit].
18 */ 18 */
19 class IncrementalCompilationUnitElementBuilder { 19 class IncrementalCompilationUnitElementBuilder {
20 final Source source; 20 final Source source;
21 final CompilationUnit oldUnit; 21 final CompilationUnit oldUnit;
22 final CompilationUnitElement oldUnitElement; 22 final CompilationUnitElementImpl unitElement;
23 final CompilationUnit newUnit; 23 final CompilationUnit newUnit;
24 final ElementHolder holder = new ElementHolder();
24 25
25 IncrementalCompilationUnitElementBuilder( 26 IncrementalCompilationUnitElementBuilder(
26 CompilationUnit oldUnit, this.newUnit) 27 CompilationUnit oldUnit, this.newUnit)
27 : oldUnit = oldUnit, 28 : oldUnit = oldUnit,
28 oldUnitElement = oldUnit.element, 29 unitElement = oldUnit.element,
29 source = oldUnit.element.source; 30 source = oldUnit.element.source;
30 31
31 void build() { 32 void build() {
32 new CompilationUnitBuilder().buildCompilationUnit(source, newUnit); 33 new CompilationUnitBuilder().buildCompilationUnit(source, newUnit);
33 _processDirectives(); 34 _processDirectives();
35 _processUnitMembers();
36 newUnit.element = unitElement;
37 }
38
39 void _addElementsToHolder(CompilationUnitMember node) {
40 List<Element> elements = _getElements(node);
41 elements.forEach(_addElementToHolder);
42 }
43
44 void _addElementToHolder(Element element) {
45 if (element is PropertyAccessorElement) {
46 holder.addAccessor(element);
47 } else if (element is ClassElement) {
48 if (element.isEnum) {
49 holder.addEnum(element);
50 } else {
51 holder.addType(element);
52 }
53 } else if (element is FunctionElement) {
54 holder.addFunction(element);
55 } else if (element is FunctionTypeAliasElement) {
56 holder.addTypeAlias(element);
57 } else if (element is TopLevelVariableElement) {
58 holder.addTopLevelVariable(element);
59 }
34 } 60 }
35 61
36 void _processDirectives() { 62 void _processDirectives() {
37 Map<String, Directive> oldDirectiveMap = <String, Directive>{}; 63 Map<String, Directive> oldDirectiveMap = new HashMap<String, Directive>();
38 // Fill the old directives map.
39 for (Directive oldDirective in oldUnit.directives) { 64 for (Directive oldDirective in oldUnit.directives) {
40 String code = TokenUtils.getFullCode(oldDirective); 65 String code = TokenUtils.getFullCode(oldDirective);
41 oldDirectiveMap[code] = oldDirective; 66 oldDirectiveMap[code] = oldDirective;
42 } 67 }
43 // Replace new nodes with the identical old nodes. 68 // Replace new nodes with the identical old nodes.
44 for (Directive newDirective in newUnit.directives) { 69 for (Directive newDirective in newUnit.directives) {
45 String code = TokenUtils.getFullCode(newDirective); 70 String code = TokenUtils.getFullCode(newDirective);
46 // Prepare an old directive. 71 // Prepare an old directive.
47 Directive oldDirective = oldDirectiveMap[code]; 72 Directive oldDirective = oldDirectiveMap[code];
48 if (oldDirective == null) { 73 if (oldDirective == null) {
49 continue; 74 continue;
50 } 75 }
51 // URI's must be resolved to the same sources. 76 // URI's must be resolved to the same sources.
52 if (newDirective is UriBasedDirective && 77 if (newDirective is UriBasedDirective &&
53 oldDirective is UriBasedDirective) { 78 oldDirective is UriBasedDirective) {
54 if (oldDirective.source != newDirective.source) { 79 if (oldDirective.source != newDirective.source) {
55 continue; 80 continue;
56 } 81 }
57 } 82 }
58 // Do replacement. 83 // Do replacement.
59 _replaceNode(newDirective, oldDirective, oldDirective.element); 84 _replaceNode(newDirective, oldDirective);
60 } 85 }
61 } 86 }
62 87
88 void _processUnitMembers() {
89 Map<String, CompilationUnitMember> oldNodeMap =
90 new HashMap<String, CompilationUnitMember>();
91 for (CompilationUnitMember oldNode in oldUnit.declarations) {
92 String code = TokenUtils.getFullCode(oldNode);
93 oldNodeMap[code] = oldNode;
94 }
95 // Replace new nodes with the identical old nodes.
96 for (CompilationUnitMember newNode in newUnit.declarations) {
97 String code = TokenUtils.getFullCode(newNode);
98 // Prepare an old node.
99 CompilationUnitMember oldNode = oldNodeMap[code];
100 if (oldNode == null) {
101 _addElementsToHolder(newNode);
102 continue;
103 }
104 // Do replacement.
105 _replaceNode(newNode, oldNode);
106 _addElementsToHolder(oldNode);
107 }
108 // Update CompilationUnitElement.
109 unitElement.accessors = holder.accessors;
110 unitElement.enums = holder.enums;
111 unitElement.functions = holder.functions;
112 unitElement.typeAliases = holder.typeAliases;
113 unitElement.types = holder.types;
114 unitElement.topLevelVariables = holder.topLevelVariables;
115 holder.validate();
116 }
117
63 /** 118 /**
64 * Replaces [newNode] with [oldNode], updates tokens and elements. 119 * Replaces [newNode] with [oldNode], updates tokens and elements.
65 * The nodes must have the same tokens, but offsets may be different. 120 * The nodes must have the same tokens, but offsets may be different.
66 */ 121 */
67 void _replaceNode(AstNode newNode, AstNode oldNode, Element oldElement) { 122 void _replaceNode(AstNode newNode, AstNode oldNode) {
68 // Replace node. 123 // Replace node.
69 NodeReplacer.replace(newNode, oldNode); 124 NodeReplacer.replace(newNode, oldNode);
70 // Replace tokens. 125 // Replace tokens.
71 { 126 {
72 Token oldBeginToken = TokenUtils.getBeginTokenNotComment(newNode); 127 Token oldBeginToken = TokenUtils.getBeginTokenNotComment(newNode);
73 Token newBeginToken = TokenUtils.getBeginTokenNotComment(oldNode); 128 Token newBeginToken = TokenUtils.getBeginTokenNotComment(oldNode);
74 oldBeginToken.previous.setNext(newBeginToken); 129 oldBeginToken.previous.setNext(newBeginToken);
75 oldNode.endToken.setNext(newNode.endToken.next); 130 oldNode.endToken.setNext(newNode.endToken.next);
76 } 131 }
77 // Change tokens offsets. 132 // Change tokens offsets.
78 Map<int, int> offsetMap = new HashMap<int, int>(); 133 Map<int, int> offsetMap = new HashMap<int, int>();
79 TokenUtils.copyTokenOffsets(offsetMap, oldNode.beginToken, 134 TokenUtils.copyTokenOffsets(offsetMap, oldNode.beginToken,
80 newNode.beginToken, oldNode.endToken, newNode.endToken, true); 135 newNode.beginToken, oldNode.endToken, newNode.endToken, true);
81 // Change elements offsets. 136 // Change elements offsets.
82 oldElement.accept(new _UpdateElementOffsetsVisitor(offsetMap)); 137 {
138 var visitor = new _UpdateElementOffsetsVisitor(offsetMap);
139 List<Element> elements = _getElements(oldNode);
140 for (Element element in elements) {
141 element.accept(visitor);
142 }
143 }
144 }
145
146 /**
147 * Returns [Element]s that are declared directly by the given [node].
148 * This does not include any child elements - parameters, local variables.
149 *
150 * Usually just one [Element] is returned, but [VariableDeclarationList]
151 * nodes may declare more than one.
152 */
153 static List<Element> _getElements(AstNode node) {
154 List<Element> elements = <Element>[];
155 if (node is TopLevelVariableDeclaration) {
156 VariableDeclarationList variableList = node.variables;
157 if (variableList != null) {
158 for (VariableDeclaration variable in variableList.variables) {
159 TopLevelVariableElement element = variable.element;
160 elements.add(element);
161 elements.add(element.getter);
162 elements.add(element.setter);
163 }
164 }
165 } else if (node is Directive && node.element != null) {
166 elements.add(node.element);
167 } else if (node is Declaration && node.element != null) {
168 Element element = node.element;
169 elements.add(element);
170 if (element is PropertyAccessorElement) {
171 elements.add(element.variable);
172 }
173 }
174 return elements;
83 } 175 }
84 } 176 }
85 177
86 /** 178 /**
87 * Utilities for [Token] manipulations. 179 * Utilities for [Token] manipulations.
88 */ 180 */
89 class TokenUtils { 181 class TokenUtils {
90 static const String _SEPARATOR = "\uFFFF"; 182 static const String _SEPARATOR = "\uFFFF";
91 183
92 /** 184 /**
93 * Copy offsets from [newToken]s to [oldToken]s. 185 * Copy offsets from [newToken]s to [oldToken]s.
94 */ 186 */
95 static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken, 187 static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken,
96 Token newToken, Token oldEndToken, Token newEndToken, 188 Token newToken, Token oldEndToken, Token newEndToken,
97 [bool goUpComment = false]) { 189 [bool goUpComment = false]) {
98 if (oldToken is CommentToken && newToken is CommentToken) { 190 if (oldToken is CommentToken && newToken is CommentToken) {
99 if (goUpComment) { 191 if (goUpComment) {
100 copyTokenOffsets(offsetMap, (oldToken as CommentToken).parent, 192 copyTokenOffsets(offsetMap, (oldToken as CommentToken).parent,
101 (newToken as CommentToken).parent, oldEndToken, newEndToken); 193 (newToken as CommentToken).parent, oldEndToken, newEndToken);
102 } 194 }
103 while (oldToken.type != TokenType.EOF) { 195 while (oldToken != null) {
104 offsetMap[oldToken.offset] = newToken.offset; 196 offsetMap[oldToken.offset] = newToken.offset;
105 oldToken.offset = newToken.offset; 197 oldToken.offset = newToken.offset;
106 oldToken = oldToken.next; 198 oldToken = oldToken.next;
107 newToken = newToken.next; 199 newToken = newToken.next;
108 } 200 }
201 assert(oldToken == null);
202 assert(newToken == null);
203 return;
109 } 204 }
110 while (true) { 205 while (true) {
111 if (oldToken.precedingComments != null) { 206 if (oldToken.precedingComments != null) {
112 assert(newToken.precedingComments == null); 207 assert(newToken.precedingComments != null);
113 copyTokenOffsets(offsetMap, oldToken.precedingComments, 208 copyTokenOffsets(offsetMap, oldToken.precedingComments,
114 newToken.precedingComments, oldEndToken, newEndToken); 209 newToken.precedingComments, oldEndToken, newEndToken);
115 } 210 }
116 offsetMap[oldToken.offset] = newToken.offset; 211 offsetMap[oldToken.offset] = newToken.offset;
117 oldToken.offset = newToken.offset; 212 oldToken.offset = newToken.offset;
118 if (oldToken == oldEndToken) { 213 if (oldToken == oldEndToken) {
119 assert(newToken == newEndToken); 214 assert(newToken == newEndToken);
120 break; 215 break;
121 } 216 }
122 oldToken = oldToken.next; 217 oldToken = oldToken.next;
(...skipping 10 matching lines...) Expand all
133 } 228 }
134 229
135 /** 230 /**
136 * Return the token string of all the [node] tokens. 231 * Return the token string of all the [node] tokens.
137 */ 232 */
138 static String getFullCode(AstNode node) { 233 static String getFullCode(AstNode node) {
139 List<Token> tokens = getTokens(node); 234 List<Token> tokens = getTokens(node);
140 return joinTokens(tokens); 235 return joinTokens(tokens);
141 } 236 }
142 237
238 /**
239 * Returns all tokends (including comments) of the given [node].
240 */
143 static List<Token> getTokens(AstNode node) { 241 static List<Token> getTokens(AstNode node) {
144 List<Token> tokens = <Token>[]; 242 List<Token> tokens = <Token>[];
145 Token token = node.beginToken; 243 Token token = getBeginTokenNotComment(node);
146 Token endToken = node.endToken; 244 Token endToken = node.endToken;
147 while (true) { 245 while (true) {
148 // append comment tokens 246 // append comment tokens
149 for (Token commentToken = token.precedingComments; 247 for (Token commentToken = token.precedingComments;
150 commentToken != null; 248 commentToken != null;
151 commentToken = commentToken.next) { 249 commentToken = commentToken.next) {
152 tokens.add(commentToken); 250 tokens.add(commentToken);
153 } 251 }
154 // append token 252 // append token
155 tokens.add(token); 253 tokens.add(token);
(...skipping 14 matching lines...) Expand all
170 /** 268 /**
171 * Updates name offsets of [Element]s according to the [map]. 269 * Updates name offsets of [Element]s according to the [map].
172 */ 270 */
173 class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor { 271 class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor {
174 final Map<int, int> map; 272 final Map<int, int> map;
175 273
176 _UpdateElementOffsetsVisitor(this.map); 274 _UpdateElementOffsetsVisitor(this.map);
177 275
178 visitElement(Element element) { 276 visitElement(Element element) {
179 int oldOffset = element.nameOffset; 277 int oldOffset = element.nameOffset;
180 int newOffset = map[oldOffset]; 278 if (oldOffset != -1) {
181 assert(newOffset != null); 279 int newOffset = map[oldOffset];
182 (element as ElementImpl).nameOffset = newOffset; 280 assert(newOffset != null);
281 (element as ElementImpl).nameOffset = newOffset;
282 }
183 if (element is! LibraryElement) { 283 if (element is! LibraryElement) {
184 super.visitElement(element); 284 super.visitElement(element);
185 } 285 }
186 } 286 }
187 } 287 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/task/incremental_element_builder_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698