Skip to content

Commit

Permalink
Some work on expected types (down to 49 failures)
Browse files Browse the repository at this point in the history
  • Loading branch information
mickaelistria committed Dec 9, 2024
1 parent 376e448 commit f2a823b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,113 +45,29 @@ class DOMCompletionContext extends CompletionContext {
this.offset = offset;
// Use the raw text to walk back the offset to the first non-whitespace spot
int adjustedOffset = this.offset;
if (cuBuffer != null) {
if (adjustedOffset >= cuBuffer.getLength()) {
adjustedOffset = cuBuffer.getLength() - 1;
}
if (adjustedOffset + 1 >= cuBuffer.getLength()
|| !Character.isJavaIdentifierStart(cuBuffer.getChar(adjustedOffset))) {
while (adjustedOffset > 0 && Character.isWhitespace(cuBuffer.getChar(adjustedOffset - 1)) ) {
adjustedOffset--;
}
}
if (cuBuffer.getChar(adjustedOffset - 1) == ',' && Character.isWhitespace(cuBuffer.getChar(adjustedOffset))) {
// probably an empty parameter
adjustedOffset = this.offset;
while (adjustedOffset < cuBuffer.getLength() && Character.isWhitespace(cuBuffer.getChar(adjustedOffset))) {
adjustedOffset++;
}
if (adjustedOffset >= cuBuffer.getLength()) {
adjustedOffset = cuBuffer.getLength() - 1;
}
if (adjustedOffset + 1 >= cuBuffer.getLength()
|| !Character.isJavaIdentifierStart(cuBuffer.getChar(adjustedOffset))) {
while (adjustedOffset > 0 && Character.isWhitespace(cuBuffer.getChar(adjustedOffset - 1)) ) {
adjustedOffset--;
}
}
ASTNode previousNodeBeforeWhitespaces = NodeFinder.perform(domUnit, adjustedOffset, 0);
// if (cuBuffer.getChar(adjustedOffset - 1) == ',' && Character.isWhitespace(cuBuffer.getChar(adjustedOffset))) {
// // probably an empty parameter
// adjustedOffset = this.offset;
// while (adjustedOffset < cuBuffer.getLength() && Character.isWhitespace(cuBuffer.getChar(adjustedOffset))) {
// adjustedOffset++;
// }
// }
this.node = previousNodeBeforeWhitespaces instanceof SimpleName || previousNodeBeforeWhitespaces instanceof StringLiteral || previousNodeBeforeWhitespaces instanceof CharacterLiteral || previousNodeBeforeWhitespaces instanceof NumberLiteral
? NodeFinder.perform(domUnit, this.offset, 0) // keep default node from initial offset
: previousNodeBeforeWhitespaces; // use previous node
this.expectedTypes = new ExpectedTypes(assistOptions, this.node);
this.expectedTypes = new ExpectedTypes(assistOptions, this.node, offset);
this.token = tokenBefore(cuBuffer).toCharArray();
this.enclosingElement = computeEnclosingElement(modelUnit);
// if (this.toComplete instanceof SimpleName simpleName) {
// int charCount = this.offset - simpleName.getStartPosition();
// if (!FAKE_IDENTIFIER.equals(simpleName.getIdentifier())) {
// completeAfter = simpleName.getIdentifier().substring(0, simpleName.getIdentifier().length() <= charCount ? simpleName.getIdentifier().length() : charCount);
// }
// if (this.cuBuffer != null) {
// if (this.cuBuffer.getChar(this.offset - 1) == '.' || this.cuBuffer.getChar(this.offset - 1) == '/') {
// completeAfter = ""; //$NON-NLS-1$
// }
// }
// if (simpleName.getParent() instanceof FieldAccess || simpleName.getParent() instanceof MethodInvocation
// || simpleName.getParent() instanceof VariableDeclaration || simpleName.getParent() instanceof QualifiedName
// || simpleName.getParent() instanceof SuperFieldAccess || simpleName.getParent() instanceof SingleMemberAnnotation
// || simpleName.getParent() instanceof ExpressionMethodReference) {
// if (!this.toComplete.getLocationInParent().getId().equals(QualifiedName.QUALIFIER_PROPERTY.getId())) {
// context = this.toComplete.getParent();
// }
// }
// if (simpleName.getParent() instanceof SimpleType simpleType && (simpleType.getParent() instanceof ClassInstanceCreation)) {
// context = simpleName.getParent().getParent();
// }
// } else if (this.toComplete instanceof TextElement textElement) {
// if (offset >= textElement.getStartPosition() + textElement.getLength()) {
// completeAfter = "";
// ASTNode parent = textElement.getParent();
// while (parent != null && !(parent instanceof Javadoc)) {
// parent = parent.getParent();
// }
// if (parent instanceof Javadoc javadoc) {
// context = javadoc.getParent();
// }
// } else {
// int charCount = this.offset - textElement.getStartPosition();
// completeAfter = textElement.getText().substring(0, textElement.getText().length() <= charCount ? textElement.getText().length() : charCount);
// context = textElement.getParent();
// }
// } else if (this.toComplete instanceof TagElement tagElement) {
// completeAfter = tagElement.getTagName();
// int atIndex = completeAfter.indexOf('@');
// if (atIndex >= 0) {
// completeAfter = completeAfter.substring(atIndex + 1);
// }
// } if (this.toComplete instanceof SimpleType simpleType) {
// if (FAKE_IDENTIFIER.equals(simpleType.getName().toString())) {
// context = this.toComplete.getParent();
// } else if (simpleType.getName() instanceof QualifiedName qualifiedName) {
// context = qualifiedName;
// }
// } else if (this.toComplete instanceof Block block && this.offset == block.getStartPosition()) {
// context = this.toComplete.getParent();
// } else if (this.toComplete instanceof FieldAccess fieldAccess) {
// completeAfter = fieldAccess.getName().toString();
// if (FAKE_IDENTIFIER.equals(completeAfter)) {
// completeAfter = ""; //$NON-NLS-1$
// } else if (this.cuBuffer != null) {
// if (this.cuBuffer.getChar(this.offset - 1) == '.') {
// completeAfter = ""; //$NON-NLS-1$
// }
// }
// } else if (this.toComplete instanceof MethodInvocation methodInvocation) {
// if (this.offset < methodInvocation.getName().getStartPosition() + methodInvocation.getName().getLength()) {
// completeAfter = methodInvocation.getName().toString();
// }
// if (FAKE_IDENTIFIER.equals(completeAfter)) {
// completeAfter = ""; //$NON-NLS-1$
// } else if (this.cuBuffer != null) {
// if (this.cuBuffer.getChar(this.offset - 1) == '.') {
// completeAfter = ""; //$NON-NLS-1$
// }
// }
// } else if (this.toComplete instanceof NormalAnnotation || this.toComplete instanceof ExpressionMethodReference || (this.toComplete instanceof MethodDeclaration md && md.getName().getStartPosition() + md.getName().getLength() + 1 < this.offset)) {
// // handle potentially unrecovered/unparented identifier characters
// if (this.cuBuffer != null) {
// int cursor = this.offset;
// while (cursor > 0 && Character.isJavaIdentifierPart(this.cuBuffer.getChar(cursor - 1)) ) {
// cursor--;
// }
// completeAfter = this.cuBuffer.getText(cursor, this.offset - cursor);
// }
// } else if (this.toComplete instanceof StringLiteral stringLiteral && (this.offset <= stringLiteral.getStartPosition() || stringLiteral.getStartPosition() + stringLiteral.getLength() <= this.offset)) {
// context = stringLiteral.getParent();
// }
this.bindingsAcquirer = bindings::stream;
}

Expand All @@ -178,54 +94,6 @@ private IJavaElement computeEnclosingElement(ICompilationUnit modelUnit) {
}
}

DOMCompletionContext(int offset, char[] token, IJavaElement enclosingElement,
Supplier<Stream<IBinding>> bindingHaver, ExpectedTypes expectedTypes, ASTNode node) {
this.offset = offset;
this.enclosingElement = enclosingElement;
this.token = token;
this.bindingsAcquirer = bindingHaver;
this.expectedTypes = expectedTypes;
this.node = node;
// populateExpectedTypes();
}

// private int argIndex(List<ASTNode> nodes) {
// for (int i = 0; i < nodes.size(); i++) {
// ASTNode current = nodes.get(i);
// if (current.getStartPosition() <= this.offset && this.offset <= current.getStartPosition() + current.getLength()) {
// return i;
// }
// }
// return -1;
// }

// private void populateExpectedTypes() {
// ASTNode parent = node;
// while (parent != null) {
// if (parent instanceof MethodInvocation method) {
// int argIndex = argIndex(method.arguments());
// var types = method.resolveMethodBinding().getParameterTypes();
// if (types.length <= argIndex) {
// expectedTypes.
// }
// }
// if (parent instanceof ClassInstanceCreation newObj) {
//
// }
// if (parent instanceof Assignment assign) {
//
// }
// }
// if (node instanceof ClassInstanceCreation classNew && this.offset > classNew.getStartPosition() + classNew.getLength()) {
// // trying to find if it's an argument, its position and then will resolve to
// // possible types according to method binding
// Set<ASTNode> nodes = new HashSet<>();
// nodes.add(classNew.getType());
// nodes.addAll(classNew.typeArguments());
// int lastOffsetBeforeArgs = nodes.stream().mapToInt(node -> node.getStartPosition() + node.getLength()).max().orElse(0);
// }
// }

@Override
public int getOffset() {
return this.offset;
Expand Down Expand Up @@ -280,10 +148,20 @@ public static boolean matchesSignature(IBinding binding, String typeSignature) {

@Override
public char[][] getExpectedTypesKeys() {
return this.expectedTypes.getExpectedTypes().stream() //
var res = this.expectedTypes.getExpectedTypes().stream() //
.map(ITypeBinding::getKey) //
.map(String::toCharArray) //
.toArray(char[][]::new);
return res.length == 0 ? null : res;
}
@Override
public char[][] getExpectedTypesSignatures() {
var res = this.expectedTypes.getExpectedTypes().stream() //
.map(type -> type.getKey()) //
.map(name -> name.replace('/', '.'))
.map(String::toCharArray) //
.toArray(char[][]::new);
return res.length == 0 ? null : res;
}

@Override
Expand All @@ -299,7 +177,7 @@ public int getTokenLocation() {
return TL_IN_IMPORT;
}
if (parent instanceof ClassInstanceCreation newObj) {
return getTokenStart() == newObj.getStartPosition() ? TL_CONSTRUCTOR_START : 0;
return getTokenStart() <= newObj.getType().getStartPosition() ? TL_CONSTRUCTOR_START : 0;
}
if (parent instanceof Statement stmt && getTokenStart() == stmt.getStartPosition()) {
return getTokenStart() == stmt.getStartPosition() ? TL_STATEMENT_START : 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private static enum TypeFilter {
SUPERTYPE, SUBTYPE;
}

private final int offset;
private Collection<TypeFilter> expectedTypesFilters = Set.of(TypeFilter.SUPERTYPE, TypeFilter.SUBTYPE);
private final Collection<ITypeBinding> expectedTypes = new LinkedHashSet<>();
private final Collection<ITypeBinding> uninterestingBindings = new LinkedHashSet<>();
Expand All @@ -42,23 +43,50 @@ private static enum TypeFilter {
private final ASTNode node;
private boolean isReady;

public ExpectedTypes(AssistOptions options, ASTNode toComplete) {
public ExpectedTypes(AssistOptions options, ASTNode toComplete, int offset) {
this.offset = offset;
this.options = options;
this.node = toComplete;
}

private void computeExpectedTypes(){

ASTNode parent =
this.node instanceof VariableDeclarationFragment
|| this.node instanceof MethodInvocation
|| this.node instanceof InfixExpression ?
this.node : this.node.getParent();
ASTNode parent2 = this.node;
// find the parent that contains type information
while (parent2 != null) {
if (parent2 instanceof VariableDeclarationFragment fragment && this.offset > fragment.getName().getStartPosition() + fragment.getName().getLength()) {
this.expectedTypes.add(fragment.resolveBinding().getType());
}
if (parent2 instanceof MethodInvocation method && this.offset > method.getName().getStartPosition() + method.getName().getLength()) {
// consider params, implemented out of this loop
break;
}
if (parent2 instanceof InfixExpression) {
break;
}
if (parent2 instanceof Assignment assign && this.offset > assign.getLeftHandSide().getStartPosition() + assign.getLeftHandSide().getLength()) {
this.expectedTypes.add(assign.resolveTypeBinding());
return;
}
if (parent2 instanceof ClassInstanceCreation newObj && this.offset > newObj.getType().getStartPosition() + newObj.getType().getLength()) {
// TODO find params
break;
}
if (parent2 instanceof CastExpression cast && this.offset > cast.getType().getStartPosition() + cast.getType().getLength()) {
this.expectedTypes.add(cast.getType().resolveBinding());
return;
}
parent2 = parent2.getParent();
}
ASTNode parent = parent2;
if (parent == null) {
return; // no construct to infer possible types
}
// default filter
this.expectedTypesFilters = Set.of(TypeFilter.SUBTYPE);

// find types from parent
if(parent instanceof VariableDeclaration variable && !(parent instanceof TypeParameter)) {
if(parent instanceof VariableDeclaration variable && !(parent instanceof TypeParameter)
&& this.offset > variable.getName().getStartPosition() + variable.getName().getLength()) {
ITypeBinding binding = variable.resolveBinding().getType();
if(binding != null) {
if(!(variable.getInitializer() instanceof ArrayInitializer)) {
Expand Down Expand Up @@ -436,9 +464,11 @@ private void computeExpectedTypesForAllocationExpression(
continue nextMethod;
}

ITypeBinding expectedType = method.getParameterTypes()[arguments.size() - 1];
if(expectedType != null) {
this.expectedTypes.add(expectedType);
if (arguments.size() > 0) {
ITypeBinding expectedType = method.getParameterTypes()[arguments.size() - 1];
if(expectedType != null) {
this.expectedTypes.add(expectedType);
}
}
}
}
Expand Down

0 comments on commit f2a823b

Please sign in to comment.