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 |
} |