View | Details | Raw Unified | Return to bug 271526 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ConstantChecks.java (-6 / +84 lines)
Lines 7-31 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 *     Jerome Cambon <jerome.cambon@oracle.com> - [extract constant] blocked for anonymous and lambdas that declare variables - https://bugs.eclipse.org/271526
10
 *******************************************************************************/
11
 *******************************************************************************/
11
package org.eclipse.jdt.internal.corext.refactoring.code;
12
package org.eclipse.jdt.internal.corext.refactoring.code;
12
13
14
import java.util.ArrayList;
15
import java.util.List;
16
13
import org.eclipse.core.runtime.Assert;
17
import org.eclipse.core.runtime.Assert;
14
18
15
import org.eclipse.jdt.core.dom.ASTVisitor;
19
import org.eclipse.jdt.core.dom.ASTVisitor;
20
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
16
import org.eclipse.jdt.core.dom.FieldAccess;
21
import org.eclipse.jdt.core.dom.FieldAccess;
22
import org.eclipse.jdt.core.dom.FieldDeclaration;
17
import org.eclipse.jdt.core.dom.IBinding;
23
import org.eclipse.jdt.core.dom.IBinding;
18
import org.eclipse.jdt.core.dom.IMethodBinding;
24
import org.eclipse.jdt.core.dom.IMethodBinding;
19
import org.eclipse.jdt.core.dom.ITypeBinding;
25
import org.eclipse.jdt.core.dom.ITypeBinding;
20
import org.eclipse.jdt.core.dom.IVariableBinding;
26
import org.eclipse.jdt.core.dom.IVariableBinding;
27
import org.eclipse.jdt.core.dom.LambdaExpression;
28
import org.eclipse.jdt.core.dom.MethodDeclaration;
21
import org.eclipse.jdt.core.dom.MethodInvocation;
29
import org.eclipse.jdt.core.dom.MethodInvocation;
22
import org.eclipse.jdt.core.dom.Modifier;
30
import org.eclipse.jdt.core.dom.Modifier;
23
import org.eclipse.jdt.core.dom.Name;
31
import org.eclipse.jdt.core.dom.Name;
24
import org.eclipse.jdt.core.dom.QualifiedName;
32
import org.eclipse.jdt.core.dom.QualifiedName;
25
import org.eclipse.jdt.core.dom.SimpleName;
33
import org.eclipse.jdt.core.dom.SimpleName;
34
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
26
import org.eclipse.jdt.core.dom.SuperFieldAccess;
35
import org.eclipse.jdt.core.dom.SuperFieldAccess;
27
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
36
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
28
import org.eclipse.jdt.core.dom.ThisExpression;
37
import org.eclipse.jdt.core.dom.ThisExpression;
38
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
29
39
30
import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
40
import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
31
import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
41
import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
Lines 35-44 class ConstantChecks { Link Here
35
45
36
		private final IExpressionFragment fExpression;
46
		private final IExpressionFragment fExpression;
37
		protected boolean fResult= true;
47
		protected boolean fResult= true;
38
48
		protected boolean fAnonymous= false;
49
		protected boolean fLambda= false;
50
		protected List<String> fLambdaAnonymousNames= new ArrayList<String>();
51
        
39
		public ExpressionChecker(IExpressionFragment ex) {
52
		public ExpressionChecker(IExpressionFragment ex) {
40
			fExpression= ex;
53
			fExpression= ex;
41
		}
54
		}
55
56
		public ExpressionChecker(IExpressionFragment ex, List<String> lambdaAnonymousNames) {
57
			fExpression= ex;
58
			fLambdaAnonymousNames= lambdaAnonymousNames;
59
		}
42
		public boolean check() {
60
		public boolean check() {
43
			fResult= true;
61
			fResult= true;
44
			fExpression.getAssociatedNode().accept(this);
62
			fExpression.getAssociatedNode().accept(this);
Lines 50-55 class ConstantChecks { Link Here
50
		public LoadTimeConstantChecker(IExpressionFragment ex) {
68
		public LoadTimeConstantChecker(IExpressionFragment ex) {
51
			super(ex);
69
			super(ex);
52
		}
70
		}
71
		public LoadTimeConstantChecker(IExpressionFragment ex, List<String> lambdaAnonymousNames) {
72
			super(ex, lambdaAnonymousNames);
73
		}
53
74
54
		@Override
75
		@Override
55
		public boolean visit(SuperFieldAccess node) {
76
		public boolean visit(SuperFieldAccess node) {
Lines 67-84 class ConstantChecks { Link Here
67
			return false;
88
			return false;
68
		}
89
		}
69
		@Override
90
		@Override
91
		public boolean visit(FieldDeclaration node) {
92
			// Is it really needed ? Seems one never jump into this for anonymous/lambda
93
			if (isAnonymousOrLambda()) {
94
				for (Object fragment : node.fragments()) {
95
					Assert.isTrue(fragment instanceof VariableDeclarationFragment);
96
					fLambdaAnonymousNames.add(((VariableDeclarationFragment) fragment).getName().toString());
97
				}
98
				return true;
99
			}
100
			return true;
101
		}
102
103
		@Override
70
		public boolean visit(FieldAccess node) {
104
		public boolean visit(FieldAccess node) {
71
			fResult&= new LoadTimeConstantChecker((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(node.getExpression())).check();
105
			fResult&= new LoadTimeConstantChecker((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(node.getExpression()), fLambdaAnonymousNames).check();
72
			return false;
106
			return false;
73
		}
107
		}
74
		@Override
108
		@Override
109
		public boolean visit(VariableDeclarationFragment node) {
110
			if (isAnonymousOrLambda()) {
111
				fLambdaAnonymousNames.add(node.getName().toString());
112
			}
113
			return true;
114
		}
115
		@Override
116
		public boolean visit(MethodDeclaration node) {
117
			if (isAnonymousOrLambda()) {
118
				fLambdaAnonymousNames.add(node.getName().toString());
119
				for (Object param : node.parameters()) {
120
					Assert.isTrue(param instanceof SingleVariableDeclaration);
121
					SingleVariableDeclaration varDeclaration= (SingleVariableDeclaration) param;
122
					fLambdaAnonymousNames.add(varDeclaration.getName().toString());
123
				}
124
			}
125
			return true;
126
		}
127
		@Override
75
		public boolean visit(MethodInvocation node) {
128
		public boolean visit(MethodInvocation node) {
76
			if(node.getExpression() == null) {
129
			if (node.getExpression() == null) {
77
				visitName(node.getName());
130
				visitName(node.getName());
78
			} else {
131
			} else {
79
				fResult&= new LoadTimeConstantChecker((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(node.getExpression())).check();
132
				if (node.getExpression().resolveTypeBinding().isAnonymous()) {
133
					// If the expression is anonymous, this method invocation cannot be a load time constant
134
					fResult= false;
135
				} else {
136
					fResult&= new LoadTimeConstantChecker((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(node.getExpression()), fLambdaAnonymousNames).check();
137
				}
80
			}
138
			}
81
82
			return false;
139
			return false;
83
		}
140
		}
84
		@Override
141
		@Override
Lines 89-94 class ConstantChecks { Link Here
89
		public boolean visit(SimpleName node) {
146
		public boolean visit(SimpleName node) {
90
			return visitName(node);
147
			return visitName(node);
91
		}
148
		}
149
		@Override
150
		public boolean visit(AnonymousClassDeclaration node) {
151
			fAnonymous= true;
152
			return true;
153
		}
154
		@Override
155
		public boolean visit(LambdaExpression node) {
156
			fLambda= true;
157
			return true;
158
		}
159
160
		private boolean isAnonymousOrLambda() {
161
			if (fAnonymous || fLambda) {
162
				return true;
163
			}
164
			return false;
165
		}
92
166
93
		private boolean visitName(Name name) {
167
		private boolean visitName(Name name) {
94
			fResult&= checkName(name);
168
			fResult&= checkName(name);
Lines 102-112 class ConstantChecks { Link Here
102
				                  scenarios which may have been deemed unacceptable in
176
				                  scenarios which may have been deemed unacceptable in
103
				                  the presence of semantic information will be admitted. */
177
				                  the presence of semantic information will be admitted. */
104
178
179
			// Check if the name is declared in anonymous/lambda
180
			if (fLambdaAnonymousNames.contains(name.toString()))
181
				return true;
182
105
			// If name represents a member:
183
			// If name represents a member:
106
			if (binding instanceof IVariableBinding || binding instanceof IMethodBinding)
184
			if (binding instanceof IVariableBinding || binding instanceof IMethodBinding)
107
				return isMemberReferenceValidInClassInitialization(name);
185
				return isMemberReferenceValidInClassInitialization(name);
108
			else if (binding instanceof ITypeBinding)
186
			else if (binding instanceof ITypeBinding)
109
				return ! ((ITypeBinding) binding).isTypeVariable();
187
				return !((ITypeBinding) binding).isTypeVariable();
110
			else {
188
			else {
111
				return true; // e.g. a NameQualifiedType's qualifier, which can be a package binding
189
				return true; // e.g. a NameQualifiedType's qualifier, which can be a package binding
112
			}
190
			}

Return to bug 271526