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

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

Issue 1124553005: Initial steps for the incremental elements builder. (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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.src.task.incremental_element_builder;
6
7 import 'dart:collection';
8
9 import 'package:analyzer/src/generated/ast.dart';
10 import 'package:analyzer/src/generated/element.dart';
11 import 'package:analyzer/src/generated/resolver.dart';
12 import 'package:analyzer/src/generated/scanner.dart';
13 import 'package:analyzer/src/generated/source.dart';
14
15 /**
16 * Incrementally updates the existing [oldUnitElement] and builds elements for
17 * the [newUnit].
18 */
19 class IncrementalCompilationUnitElementBuilder {
20 final Source source;
21 final CompilationUnit oldUnit;
22 final CompilationUnitElement oldUnitElement;
23 final CompilationUnit newUnit;
24
25 IncrementalCompilationUnitElementBuilder(
26 CompilationUnit oldUnit, this.newUnit)
27 : oldUnit = oldUnit,
28 oldUnitElement = oldUnit.element,
29 source = oldUnit.element.source;
30
31 void build() {
32 new CompilationUnitBuilder().buildCompilationUnit(source, newUnit);
33 _processDirectives();
34 }
35
36 void _processDirectives() {
37 Map<String, Directive> oldDirectiveMap = <String, Directive>{};
38 // Fill the old directives map.
39 for (Directive oldDirective in oldUnit.directives) {
40 String code = TokenUtils.getFullCode(oldDirective);
41 oldDirectiveMap[code] = oldDirective;
42 }
43 // Replace new nodes with the identical old nodes.
44 for (Directive newDirective in newUnit.directives) {
45 String code = TokenUtils.getFullCode(newDirective);
46 // Prepare an old directive.
47 Directive oldDirective = oldDirectiveMap[code];
48 if (oldDirective == null) {
49 continue;
50 }
51 // URI's must be resolved to the same sources.
52 if (newDirective is UriBasedDirective &&
53 oldDirective is UriBasedDirective) {
54 if (oldDirective.source != newDirective.source) {
55 continue;
56 }
57 }
58 // Do replacement.
59 _replaceNode(newDirective, oldDirective, oldDirective.element);
60 }
61 }
62
63 /**
64 * Replaces [newNode] with [oldNode], updates tokens and elements.
65 * The nodes must have the same tokens, but offsets may be different.
66 */
67 void _replaceNode(AstNode newNode, AstNode oldNode, Element oldElement) {
68 // Replace node.
69 NodeReplacer.replace(newNode, oldNode);
70 // Replace tokens.
71 {
72 Token oldBeginToken = TokenUtils.getBeginTokenNotComment(newNode);
73 Token newBeginToken = TokenUtils.getBeginTokenNotComment(oldNode);
74 oldBeginToken.previous.setNext(newBeginToken);
75 oldNode.endToken.setNext(newNode.endToken.next);
76 }
77 // Change tokens offsets.
78 Map<int, int> offsetMap = new HashMap<int, int>();
79 TokenUtils.copyTokenOffsets(offsetMap, oldNode.beginToken,
80 newNode.beginToken, oldNode.endToken, newNode.endToken, true);
81 // Change elements offsets.
82 oldElement.accept(new _UpdateElementOffsetsVisitor(offsetMap));
83 }
84 }
85
86 /**
87 * Utilities for [Token] manipulations.
88 */
89 class TokenUtils {
90 static const String _SEPARATOR = "\uFFFF";
91
92 /**
93 * Copy offsets from [newToken]s to [oldToken]s.
94 */
95 static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken,
96 Token newToken, Token oldEndToken, Token newEndToken,
97 [bool goUpComment = false]) {
98 if (oldToken is CommentToken && newToken is CommentToken) {
99 if (goUpComment) {
100 copyTokenOffsets(offsetMap, (oldToken as CommentToken).parent,
101 (newToken as CommentToken).parent, oldEndToken, newEndToken);
102 }
103 while (oldToken.type != TokenType.EOF) {
104 offsetMap[oldToken.offset] = newToken.offset;
105 oldToken.offset = newToken.offset;
106 oldToken = oldToken.next;
107 newToken = newToken.next;
108 }
109 }
110 while (true) {
111 if (oldToken.precedingComments != null) {
112 assert(newToken.precedingComments == null);
113 copyTokenOffsets(offsetMap, oldToken.precedingComments,
114 newToken.precedingComments, oldEndToken, newEndToken);
115 }
116 offsetMap[oldToken.offset] = newToken.offset;
117 oldToken.offset = newToken.offset;
118 if (oldToken == oldEndToken) {
119 assert(newToken == newEndToken);
120 break;
121 }
122 oldToken = oldToken.next;
123 newToken = newToken.next;
124 }
125 }
126
127 static Token getBeginTokenNotComment(AstNode node) {
128 Token oldBeginToken = node.beginToken;
129 if (oldBeginToken is CommentToken) {
130 oldBeginToken = (oldBeginToken as CommentToken).parent;
131 }
132 return oldBeginToken;
133 }
134
135 /**
136 * Return the token string of all the [node] tokens.
137 */
138 static String getFullCode(AstNode node) {
139 List<Token> tokens = getTokens(node);
140 return joinTokens(tokens);
141 }
142
143 static List<Token> getTokens(AstNode node) {
144 List<Token> tokens = <Token>[];
145 Token token = node.beginToken;
146 Token endToken = node.endToken;
147 while (true) {
148 // append comment tokens
149 for (Token commentToken = token.precedingComments;
150 commentToken != null;
151 commentToken = commentToken.next) {
152 tokens.add(commentToken);
153 }
154 // append token
155 tokens.add(token);
156 // next token
157 if (token == endToken) {
158 break;
159 }
160 token = token.next;
161 }
162 return tokens;
163 }
164
165 static String joinTokens(List<Token> tokens) {
166 return tokens.map((token) => token.lexeme).join(_SEPARATOR);
167 }
168 }
169
170 /**
171 * Updates name offsets of [Element]s according to the [map].
172 */
173 class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor {
174 final Map<int, int> map;
175
176 _UpdateElementOffsetsVisitor(this.map);
177
178 visitElement(Element element) {
179 int oldOffset = element.nameOffset;
180 int newOffset = map[oldOffset];
181 assert(newOffset != null);
182 (element as ElementImpl).nameOffset = newOffset;
183 if (element is! LibraryElement) {
184 super.visitElement(element);
185 }
186 }
187 }
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