Skip to content

Commit 485d20d

Browse files
committed
Collect instanceof and switch pattern variable bindings
Fixes #1130 Signed-off-by: David Thompson <[email protected]>
1 parent e0066d6 commit 485d20d

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/DOMCompletionEngine.java

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,11 @@ private Collection<? extends IBinding> visibleBindings(ASTNode node) {
165165
visibleBindings.add(typeDecl.resolveBinding());
166166
}
167167

168-
if (node instanceof Block block) {
168+
if (node instanceof Block block && node.getStartPosition() + node.getLength() > this.offset) {
169+
// TODO: handle negative if statements eg.
170+
// if (!(node instanceof IfStatement ifStatement))
171+
// return;
172+
// ifState|
169173
var bindings = ((List<Statement>) block.statements()).stream()
170174
.filter(statement -> statement.getStartPosition() < this.offset)
171175
.filter(VariableDeclarationStatement.class::isInstance)
@@ -175,10 +179,91 @@ private Collection<? extends IBinding> visibleBindings(ASTNode node) {
175179
.map(VariableDeclarationFragment::resolveBinding)
176180
.toList();
177181
visibleBindings.addAll(bindings);
182+
for (Statement statement : ((List<Statement>)block.statements())) {
183+
if (statement.getStartPosition() >= this.offset || statement.getStartPosition() + statement.getLength() >= this.offset) {
184+
break;
185+
}
186+
if (statement instanceof IfStatement ifStatement && ifStatement.getElseStatement() == null) {
187+
visibleBindings.addAll(collectTrueFalseBindings(ifStatement.getExpression()).falseBindings());
188+
}
189+
}
190+
}
191+
192+
if (node.getParent() instanceof IfStatement ifStatement && node.getStartPosition() + node.getLength() > this.offset) {
193+
TrueFalseBindings leftRightBindings = collectTrueFalseBindings(ifStatement.getExpression());
194+
if (ifStatement.getThenStatement() == node) {
195+
visibleBindings.addAll(leftRightBindings.trueBindings());
196+
} else {
197+
visibleBindings.addAll(leftRightBindings.falseBindings());
198+
}
178199
}
200+
201+
if (node instanceof SwitchStatement switchStatement) {
202+
int i;
203+
for (i = 0; i < switchStatement.statements().size(); i++) {
204+
if (((List<Statement>)switchStatement.statements()).get(i).getStartPosition() >= this.offset) {
205+
break;
206+
}
207+
if (((List<Statement>)switchStatement.statements()).get(i) instanceof SwitchCase switchCase) {
208+
DOMCompletionUtil.visitChildren(switchCase, ASTNode.TYPE_PATTERN, (TypePattern e) -> {
209+
visibleBindings.add(e.getPatternVariable().resolveBinding());
210+
});
211+
}
212+
}
213+
}
214+
215+
if (node instanceof SwitchExpression switchExpression) {
216+
int i;
217+
for (i = 0; i < switchExpression.statements().size(); i++) {
218+
if (((List<Statement>)switchExpression.statements()).get(i).getStartPosition() >= this.offset) {
219+
break;
220+
}
221+
if (((List<Statement>)switchExpression.statements()).get(i) instanceof SwitchCase switchCase) {
222+
DOMCompletionUtil.visitChildren(switchCase, ASTNode.TYPE_PATTERN, (TypePattern e) -> {
223+
visibleBindings.add(e.getPatternVariable().resolveBinding());
224+
});
225+
}
226+
}
227+
}
228+
179229
return visibleBindings;
180230
}
181231

232+
/**
233+
* Represents collections of bindings that might be accessible depending on whether a boolean expression is true or false.
234+
*
235+
* @param trueBindings the bindings that are accessible when the expression is true
236+
* @param falseBindings the bindings that are accessible when the expression is false
237+
*/
238+
record TrueFalseBindings(List<IVariableBinding> trueBindings, List<IVariableBinding> falseBindings) {}
239+
240+
private TrueFalseBindings collectTrueFalseBindings(Expression e) {
241+
if (e instanceof PrefixExpression prefixExpression && prefixExpression.getOperator() == PrefixExpression.Operator.NOT) {
242+
TrueFalseBindings notBindings = collectTrueFalseBindings(prefixExpression.getOperand());
243+
return new TrueFalseBindings(notBindings.falseBindings(), notBindings.trueBindings());
244+
} else if (e instanceof InfixExpression infixExpression && infixExpression.getOperator() == InfixExpression.Operator.AND) {
245+
TrueFalseBindings left = collectTrueFalseBindings(infixExpression.getLeftOperand());
246+
TrueFalseBindings right = collectTrueFalseBindings(infixExpression.getRightOperand());
247+
List<IVariableBinding> combined = new ArrayList<>();
248+
combined.addAll(left.trueBindings());
249+
combined.addAll(right.trueBindings());
250+
return new TrueFalseBindings(combined, Collections.emptyList());
251+
} else if (e instanceof InfixExpression infixExpression && infixExpression.getOperator() == InfixExpression.Operator.OR) {
252+
TrueFalseBindings left = collectTrueFalseBindings(infixExpression.getLeftOperand());
253+
TrueFalseBindings right = collectTrueFalseBindings(infixExpression.getRightOperand());
254+
List<IVariableBinding> combined = new ArrayList<>();
255+
combined.addAll(left.falseBindings());
256+
combined.addAll(right.falseBindings());
257+
return new TrueFalseBindings(Collections.emptyList(), combined);
258+
} else {
259+
List<IVariableBinding> typePatternBindings = new ArrayList<>();
260+
DOMCompletionUtil.visitChildren(e, ASTNode.TYPE_PATTERN, (TypePattern patt) -> {
261+
typePatternBindings.add(patt.getPatternVariable().resolveBinding());
262+
});
263+
return new TrueFalseBindings(typePatternBindings, Collections.emptyList());
264+
}
265+
}
266+
182267
private Collection<? extends ITypeBinding> visibleTypeBindings(ASTNode node) {
183268
List<ITypeBinding> visibleBindings = new ArrayList<>();
184269
if (node instanceof AbstractTypeDeclaration typeDeclaration) {

org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/DOMCompletionUtil.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
package org.eclipse.jdt.internal.codeassist;
1212

1313
import java.util.List;
14+
import java.util.function.Consumer;
1415
import org.eclipse.jdt.core.dom.ASTNode;
16+
import org.eclipse.jdt.core.dom.ASTVisitor;
1517
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
1618
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
1719

@@ -37,6 +39,18 @@ public static ASTNode findParent(ASTNode nodeToSearch, int[] kindsToFind) {
3739
return null;
3840
}
3941

42+
public static <T extends ASTNode> void visitChildren(ASTNode root, int kind, Consumer<T> consumer) {
43+
ASTVisitor visitor = new ASTVisitor() {
44+
@Override
45+
public void preVisit(ASTNode node) {
46+
if (node.getNodeType() == kind) {
47+
consumer.accept((T)node);
48+
}
49+
}
50+
};
51+
root.accept(visitor);
52+
}
53+
4054
/**
4155
* Returns the first parent type declaration (class, enum, record, annotation, etc), or null if there is no parent type declaration.
4256
*

0 commit comments

Comments
 (0)