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

Side by Side Diff: lib/src/codegen/assignments_index.dart

Issue 1751963002: refactor/simplify nullable inference code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 9 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
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 import 'package:analyzer/dart/ast/token.dart';
6 import 'package:analyzer/src/generated/ast.dart';
7 import 'package:analyzer/src/generated/element.dart';
8
9 import 'ast_builder.dart';
10
11 /// Creates an index of variable assignments and declarations occurring in all
12 /// the provided [nodes].
13 ///
14 /// Expands any compound assignment expression (e.g. `i += 2` yields an assigned
15 /// expression of `i + 2`), and treats declarations with no assignment as having
16 /// a `null` assigned expression.
17 Map<LocalVariableElement, List<Expression>> indexLocalAssignments(
18 Iterable<AstNode> nodes) {
19 var visitor = new _LocalAssignmentsVisitor();
20 nodes.forEach((n) => n.accept(visitor));
21 return visitor.assignedExpressions;
22 }
23
24 /// Visits variable declarations and assignments and exposes an
25 /// [AssignmentIndex] interface.
26 ///
27 // TODO(ochafik): Introduce flow analysis (a variable may be nullable in
28 // some places and not in others).
29 class _LocalAssignmentsVisitor extends RecursiveAstVisitor {
30 final assignedExpressions = <LocalVariableElement, List<Expression>>{};
31
32 @override
33 visitVariableDeclaration(VariableDeclaration node) {
34 var element = node.element;
35 if (element is LocalVariableElement) {
36 _addAssignment(element, node.initializer ?? AstBuilder.nullLiteral());
37 }
38 super.visitVariableDeclaration(node);
39 }
40
41 @override
42 visitCatchClause(CatchClause node) {
43 for (var ident in [node.exceptionParameter, node.stackTraceParameter]) {
44 if (ident == null) continue;
45 assert(ident.staticElement is LocalVariableElement);
46 _addAssignment(ident.staticElement, AstBuilder.nullLiteral());
47 }
48 }
49
50 @override
51 visitAssignmentExpression(AssignmentExpression node) {
52 var lhs = node.leftHandSide;
53 var e = _getLocalVariable(lhs);
54 if (e != null) _addAssignment(e, node.rightHandSide);
55 super.visitAssignmentExpression(node);
56 }
57
58 @override
59 visitBinaryExpression(BinaryExpression node) {
60 var op = node.operator.type;
61 if (op.isAssignmentOperator) {
62 var e = _getLocalVariable(node.leftOperand);
63 if (e != null) {
64 // TODO(ochafik): Once we have non-nullable types, compute the static
65 // type for this AST node.
66 _addAssignment(
67 e,
68 RawAstBuilder.binaryExpression(node.leftOperand,
69 _opToken(_expandAssignmentOp(op)), node.rightOperand));
70 }
71 }
72 super.visitBinaryExpression(node);
73 }
74
75 @override
76 visitPostfixExpression(PostfixExpression node) {
77 var op = node.operator.type;
78 if (op.isAssignmentOperator) {
79 // Treat `x++` as statically assigning `x + 1` to variable `x`.
80 var e = _getLocalVariable(node.operand);
81 if (e != null) _handleIncrOrDecr(e, node.operand, op);
82 }
83 super.visitPostfixExpression(node);
84 }
85
86 @override
87 visitPrefixExpression(PrefixExpression node) {
88 var op = node.operator.type;
89 if (op.isAssignmentOperator) {
90 // Treat `++x` as statically assigning `x + 1` to variable `x`.
91 var e = _getLocalVariable(node.operand);
92 if (e != null) _handleIncrOrDecr(e, node.operand, op);
93 }
94 super.visitPrefixExpression(node);
95 }
96
97 /// Note: we're not interested in differences between prefix & suffix.
98 _handleIncrOrDecr(LocalVariableElement e, Expression operand, TokenType op) {
99 if (!op.isIncrementOperator) throw new ArgumentError('Unexpected op: $op');
100 // TODO(ochafik): Once we have non-nullable types, compute the static
101 // type for this AST node.
102 _addAssignment(
103 e,
104 RawAstBuilder.binaryExpression(
105 operand, _opToken(op), AstBuilder.integerLiteral(1)));
106 }
107
108 void _addAssignment(VariableElement e, Expression value) =>
109 assignedExpressions.putIfAbsent(e, () => <Expression>[]).add(value);
110
111 LocalVariableElement _getLocalVariable(Expression target) {
112 if (target is SimpleIdentifier) {
113 var e = target.bestElement;
114 if (e is LocalVariableElement && e is! PropertyAccessorElement) {
115 return e;
116 }
117 }
118 return null;
119 }
120 }
121
122 const Map<TokenType, TokenType> _opByAssignmentOp = const {
123 TokenType.AMPERSAND_EQ: TokenType.AMPERSAND,
124 TokenType.BAR_EQ: TokenType.BAR,
125 TokenType.CARET_EQ: TokenType.CARET,
126 TokenType.GT_GT_EQ: TokenType.GT_GT,
127 TokenType.LT_LT_EQ: TokenType.LT_LT,
128 TokenType.MINUS_EQ: TokenType.MINUS,
129 TokenType.PERCENT_EQ: TokenType.PERCENT,
130 TokenType.PLUS_EQ: TokenType.PLUS,
131 TokenType.QUESTION_QUESTION_EQ: TokenType.QUESTION_QUESTION,
132 TokenType.SLASH_EQ: TokenType.SLASH,
133 TokenType.STAR_EQ: TokenType.STAR,
134 TokenType.TILDE_SLASH_EQ: TokenType.TILDE_SLASH,
135 };
136
137 Token _opToken(TokenType t) => new Token(t, 0);
138
139 /// Transforms `+=` to `+`, `??=` to `??`, etc.
140 TokenType _expandAssignmentOp(TokenType assignmentOp) {
141 assert(assignmentOp.isAssignmentOperator);
142 var op = _opByAssignmentOp[assignmentOp];
143 if (op == null) throw new ArgumentError("Can't expand op $assignmentOp");
144 return op;
145 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698