Skip to content

Commit

Permalink
Merge pull request #481 from groovy/issue451
Browse files Browse the repository at this point in the history
Fix #451
  • Loading branch information
eric-milles authored Feb 16, 2018
2 parents c3fb794 + 9177127 commit b3b5896
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2009-2017 the original author or authors.
* Copyright 2009-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -895,6 +895,12 @@ public static ClassNode clonedRange() {
return clone;
}

public static ClassNode clonedClosure() {
ClassNode clone = clone(CLOSURE_CLASS_NODE);
cleanGenerics(clone.getGenericsTypes()[0]);
return clone;
}

private static void cleanGenerics(GenericsType gt) {
gt.getType().setGenericsTypes(null);
gt.setName("java.lang.Object");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -472,19 +472,19 @@ final class MethodCompletionTests extends CompletionTestSuite {
@Test
void testMethodPointer1() {
String contents = 'String.&isE'
ICompletionProposal[] proposals = createProposalsAtOffset(contents, getLastIndexOf(contents, 'isE'))
proposalExists(proposals, 'isEmpty', 1)

applyProposalAndCheck(findFirstProposal(proposals, 'isEmpty'), 'String.&isEmpty')
applyProposalAndCheck(checkUniqueProposal(contents, 'isE', 'isEmpty'), contents + 'mpty')
}

@Test
void testMethodPointer2() {
String contents = 'String.& isE'
ICompletionProposal[] proposals = createProposalsAtOffset(contents, getLastIndexOf(contents, 'isE'))
proposalExists(proposals, 'isEmpty', 1)
applyProposalAndCheck(checkUniqueProposal(contents, 'isE', 'isEmpty'), contents + 'mpty')
}

applyProposalAndCheck(findFirstProposal(proposals, 'isEmpty'), 'String.& isEmpty')
@Test
void testMethodPointer3() {
String contents = 'String.&isEmpty.mem'
applyProposalAndCheck(checkUniqueProposal(contents, 'mem', 'memoize()'), contents + 'oize()')
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.MethodPointerExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
import org.codehaus.groovy.ast.expr.TupleExpression;
Expand All @@ -56,6 +57,7 @@
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.groovy.core.util.GroovyUtils;
import org.eclipse.jdt.groovy.search.AccessorSupport;
import org.eclipse.jdt.groovy.search.ITypeRequestor;
import org.eclipse.jdt.groovy.search.TypeInferencingVisitorFactory;
Expand Down Expand Up @@ -164,8 +166,10 @@ public VisitStatus acceptASTNode(ASTNode node, TypeLookupResult result, IJavaEle
}

private ClassNode findResultingType(TypeLookupResult result, boolean derefList) {
ContentAssistContext context = getContext();
// if completing on a method call with an implicit 'this'.
ClassNode candidate = getContext().location == ContentAssistLocation.METHOD_CONTEXT ? result.declaringType : result.type;
ClassNode candidate = (context.location == ContentAssistLocation.METHOD_CONTEXT ? result.declaringType : result.type);

if (derefList) {
for (int i = 0; i < derefCount; i += 1) {
// GRECLIPSE-742: does the LHS type have a 'getAt' method?
Expand All @@ -177,7 +181,6 @@ private ClassNode findResultingType(TypeLookupResult result, boolean derefList)
getAtFound = true;
}
}

if (!getAtFound) {
if (VariableScope.MAP_CLASS_NODE.equals(candidate)) {
// for maps, always use the type of value
Expand All @@ -191,15 +194,23 @@ private ClassNode findResultingType(TypeLookupResult result, boolean derefList)
}
}

// now look at spread expressions
// might be part of a spread operation
boolean extractElementType = false; // for spread operations

ASTNode enclosing = result.scope.getEnclosingNode();
if (enclosing instanceof MethodCallExpression) {
extractElementType = ((MethodCallExpression) enclosing).isSpreadSafe();
} else if (enclosing instanceof PropertyExpression) {
if (enclosing instanceof PropertyExpression) {
// if enclosing is method pointer expression, result type is Closure<T>, not just T
if (((PropertyExpression) enclosing).getObjectExpression() instanceof MethodPointerExpression) {
ClassNode closureType = VariableScope.clonedClosure();
Parameter[] parameters = (result.declaration instanceof MethodNode ?
((MethodNode) result.declaration).getParameters() : Parameter.EMPTY_ARRAY);
GroovyUtils.updateClosureWithInferredTypes(closureType, candidate, parameters);
return closureType;
}
extractElementType = ((PropertyExpression) enclosing).isSpreadSafe();
} else if (enclosing instanceof MethodCallExpression) {
extractElementType = ((MethodCallExpression) enclosing).isSpreadSafe();
}

if (extractElementType) {
candidate = VariableScope.extractElementType(candidate);
}
Expand Down

0 comments on commit b3b5896

Please sign in to comment.