Skip to content

Commit

Permalink
Fix for issue #147: content assist for annotation members
Browse files Browse the repository at this point in the history
Completion support is very basic at this point. Only annotation
attributes should be suggested within an annotation's parenthesis.
  • Loading branch information
eric-milles committed Dec 11, 2016
1 parent 71fdae3 commit 5b63fb6
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 338 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,8 @@ protected void proposalExists(ICompletionProposal[] proposals, String name, int
protected void proposalExists(ICompletionProposal[] proposals, String name, int expectedCount, boolean isType) {
int foundCount = 0;
for (ICompletionProposal proposal : proposals) {

// if a field
String propName = proposal.getDisplayString();
// if a field
if (propName.startsWith(name + " ")) {
foundCount += 1;
} else
Expand All @@ -126,13 +125,8 @@ protected void proposalExists(ICompletionProposal[] proposals, String name, int
foundCount += 1;
}
}

if (foundCount != expectedCount) {
StringBuffer sb = new StringBuffer();
for (ICompletionProposal proposal : proposals) {
sb.append("\n" + proposal.toString());
}
fail("Expected to find proposal '" + name + "' " + expectedCount + " times, but found it " + foundCount + " times.\nAll Proposals:" + sb);
fail("Expected to find proposal '" + name + "' " + expectedCount + " times, but found it " + foundCount + " times.\nAll Proposals: " + printProposals(proposals));
}
}

Expand Down Expand Up @@ -346,9 +340,11 @@ public int compare(ICompletionProposal lhs, ICompletionProposal rhs) {

protected String printProposals(ICompletionProposal[] proposals) {
StringBuilder sb = new StringBuilder();
sb.append("Incorrect proposals:\n");
for (ICompletionProposal proposal : proposals) {
sb.append(proposal.getDisplayString() + "\n");
sb.append('\n').append(proposal.getDisplayString());
if (proposal instanceof IJavaCompletionProposal) {
sb.append(" (").append(((IJavaCompletionProposal) proposal).getRelevance()).append(')');
}
}
return sb.toString();
}
Expand All @@ -374,20 +370,25 @@ protected void checkProposalApplication(String contents, int proposalLocation, S
ICompletionProposal[] proposals = createProposalsAtOffset(contents, proposalLocation);
for (int i = 0; i < expecteds.length; i++) {
ICompletionProposal firstProposal = findFirstProposal(proposals, proposalNames[i], false);
if (firstProposal == null) {
fail("Expected at least one proposal, but found none");
}
assertNotNull("Expected at least one proposal, but found none", firstProposal);
applyProposalAndCheck(new Document(contents), firstProposal, expecteds[i]);
}
}

protected void assertProposalOrdering(ICompletionProposal[] proposals, String...order) {
int startFrom = 0;
for (String propName : order) {
startFrom = findProposal(proposals, propName, false, startFrom) + 1;
if (startFrom == 0) {
fail("Failed to find '" + propName + "' in order inside of:\n" + printProposals(proposals));
protected void assertProposalOrdering(ICompletionProposal[] proposals, String... order) {
int prev = -1;
for (int i = 0, n = order.length; i < n; i += 1) {
int next = findProposal(proposals, order[i], false, prev + 1);

String message;
if (i == 0) {
message = String.format("Proposal '%s' should have been found in: ", order[i]);
} else {
message = String.format("Proposal '%s' should have followed proposal '%s' in: ", order[i - 1], order[i]);
}
assertTrue(message + printProposals(proposals), next > prev);

prev = next;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,26 @@ public void testClass2() throws Exception {
proposalExists(proposals, "util", 1);
}

public void testAnnotationMembers0() throws Exception {
String contents = "@SuppressWarnings()\nclass C { }";
ICompilationUnit unit = addGroovySource(contents, "File", "");
ICompletionProposal[] proposals = performContentAssist(unit, getIndexOf(contents, "@SuppressWarnings("), GroovyCompletionProposalComputer.class);
assertTrue("Proposal for 'value()' should have been found", -1 != findProposal(proposals, "value", false, 0));
assertTrue("Proposal for 'equals()' should not have been found", -1 == findProposal(proposals, "equals", false, 0));
assertTrue("Proposal for 'public' should not have been found", -1 == findProposal(proposals, "public", false, 0));
}

public void testAnnotationMembers1() throws Exception {
String contents = "@SuppressWarnings(v)\nclass C { }";
ICompilationUnit unit = addGroovySource(contents, "File", "");
ICompletionProposal[] proposals = performContentAssist(unit, getIndexOf(contents, "@SuppressWarnings(v"), GroovyCompletionProposalComputer.class);
assertTrue("Proposal for 'value()' should have been found", -1 != findProposal(proposals, "value", false, 0));
assertTrue("Proposal for 'equals()' should not have been found", -1 == findProposal(proposals, "equals", false, 0));
assertTrue("Proposal for 'public' should not have been found", -1 == findProposal(proposals, "public", false, 0));
}

//

private List<MethodNode> delegateTestParameterNames(GroovyCompilationUnit unit) throws Exception {
// for some reason, need to wait for indices to be built before this can work
SynchronizationUtils.waitForIndexingToComplete(unit);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2009-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.codeassist.factories;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.eclipse.codeassist.creators.MethodProposalCreator;
import org.codehaus.groovy.eclipse.codeassist.processors.AbstractGroovyCompletionProcessor;
import org.codehaus.groovy.eclipse.codeassist.processors.IGroovyCompletionProcessor;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyMethodProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.IGroovyProposal;
import org.codehaus.groovy.eclipse.codeassist.requestor.ContentAssistContext;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
import org.eclipse.jface.text.contentassist.ICompletionProposal;

public class AnnotationMemberValueCompletionProcessorFactory implements IGroovyCompletionProcessorFactory {

public IGroovyCompletionProcessor createProcessor(ContentAssistContext context,
JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) {

return new AbstractGroovyCompletionProcessor(context, javaContext, nameEnvironment) {

public List<ICompletionProposal> generateProposals(IProgressMonitor monitor) {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask("Assist in annotation", 2);
try {
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();

generateAnnotationAttributeProposals(proposals);
monitor.worked(1);

//VariableExpression

// annotation values can be found as static final fields

// if (value type is class or class[]) types

return proposals;
} finally {
monitor.done();
}
}

protected void generateAnnotationAttributeProposals(List<ICompletionProposal> proposals) {
MethodProposalCreator mpc = new MethodProposalCreator();
mpc.setCurrentScope(getContext().currentScope);
List<IGroovyProposal> methodProposals = mpc.findAllProposals(
((AnnotationNode) getContext().containingCodeBlock).getClassNode(),
Collections.<ClassNode>emptySet(),
getContext().completionExpression,
false, // isStatic
true); // isPrimary

for (IGroovyProposal methodProposal : methodProposals) {
if (((GroovyMethodProposal) methodProposal).getMethod()
.getDeclaringClass().getName().equals("java.lang.annotation.Annotation")) {
continue;
}
proposals.add(methodProposal.createJavaProposal(getContext(), getJavaContext()));
}
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@
/**
* @author Andrew Eisenberg
* @created Nov 10, 2009
*
*/
public class TypeCompletionProcessorFactory implements IGroovyCompletionProcessorFactory {
public IGroovyCompletionProcessor createProcessor(
ContentAssistContext context, JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) {
public IGroovyCompletionProcessor createProcessor(ContentAssistContext context,
JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) {
return new TypeCompletionProcessor(context, javaContext, nameEnvironment);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
*/
public class TypeCompletionProcessor extends AbstractGroovyCompletionProcessor {

// GRECLIPSE-1527 field modifiers collection
private static final Set<String> FIELD_MODIFIERS = new HashSet<String>();
static {
FIELD_MODIFIERS.add("private");
Expand All @@ -48,10 +47,8 @@ public class TypeCompletionProcessor extends AbstractGroovyCompletionProcessor {
FIELD_MODIFIERS.add("static");
FIELD_MODIFIERS.add("final");
}
// GRECLIPSE end

public TypeCompletionProcessor(ContentAssistContext context,
JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) {
public TypeCompletionProcessor(ContentAssistContext context, JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) {
super(context, javaContext, nameEnvironment);
}

Expand Down Expand Up @@ -120,7 +117,6 @@ protected int getSearchFor() {
}

private boolean isBeforeTypeName(ContentAssistLocation location, GroovyCompilationUnit unit, int completionLocation) {
// GRECLIPE-1527 Updated logic
if (location != ContentAssistLocation.CLASS_BODY) {
return false;
}
Expand All @@ -133,6 +129,5 @@ private boolean isBeforeTypeName(ContentAssistLocation location, GroovyCompilati
return false;
}
return !FIELD_MODIFIERS.contains(nameAndLocation.name.trim());
// GRECLIPSE end
}
}
Loading

0 comments on commit 5b63fb6

Please sign in to comment.