/* * Copyright 2009-2017 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.processors; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.ModuleNode; import org.codehaus.groovy.eclipse.codeassist.CharArraySourceBuffer; import org.codehaus.groovy.eclipse.codeassist.requestor.ContentAssistContext; import org.codehaus.groovy.eclipse.codeassist.requestor.ContentAssistLocation; import org.codehaus.groovy.eclipse.core.util.ExpressionFinder; import org.codehaus.groovy.eclipse.core.util.ExpressionFinder.NameAndLocation; import org.codehaus.jdt.groovy.internal.compiler.ast.JDTResolver; import org.codehaus.jdt.groovy.model.GroovyCompilationUnit; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.groovy.search.ITypeResolver; import org.eclipse.jdt.internal.core.SearchableEnvironment; import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext; import org.eclipse.jface.text.contentassist.ICompletionProposal; public class TypeCompletionProcessor extends AbstractGroovyCompletionProcessor implements ITypeResolver { private static final Set<String> FIELD_MODIFIERS = Collections.unmodifiableSet( new HashSet<String>(Arrays.asList("private", "protected", "public", "static", "final"))); protected JDTResolver resolver; public TypeCompletionProcessor(ContentAssistContext context, JavaContentAssistInvocationContext javaContext, SearchableEnvironment nameEnvironment) { super(context, javaContext, nameEnvironment); } public void setResolverInformation(ModuleNode module, JDTResolver resolver) { this.resolver = resolver; } public List<ICompletionProposal> generateProposals(IProgressMonitor monitor) { ContentAssistContext context = getContext(); String toSearch = context.completionExpression.startsWith("new ") ? context.completionExpression.substring(4) : context.completionExpression; if (shouldShowTypes(context, toSearch)) { return Collections.emptyList(); } int expressionStart = findExpressionStart(context); GroovyProposalTypeSearchRequestor requestor = new GroovyProposalTypeSearchRequestor( context, getJavaContext(), expressionStart, context.completionEnd - expressionStart, getNameEnvironment().nameLookup, monitor); getNameEnvironment().findTypes(toSearch.toCharArray(), true, // all member types, should be false when in constructor true, // camel case match getSearchFor(), requestor, monitor); List<ICompletionProposal> typeProposals = requestor.processAcceptedTypes(resolver); return typeProposals; } /** * <ul> * <li>Don't show types if there is no previous text (except for imports or annotations) * <li>Don't show types if there is a '.' * <li>Don't show types when in a class body and there is a type declaration immediately before * </ul> */ private boolean shouldShowTypes(ContentAssistContext context, String toSearch) { if (toSearch == null || toSearch.length() == 0) { switch (context.location) { case ANNOTATION: case IMPORT: break; default: return false; } } return context.fullCompletionExpression.contains(".") || isBeforeTypeName(context.location, context.unit, context.completionLocation); } private int findExpressionStart(ContentAssistContext context) { // remove "new" int completionLength; if (context.completionExpression.startsWith("new ")) { completionLength = context.completionExpression.substring("new ".length()).trim().length(); } else { completionLength = context.completionExpression.length(); } int expressionStart = context.completionLocation-completionLength; return expressionStart; } protected int getSearchFor() { switch(getContext().location) { case EXTENDS: return IJavaSearchConstants.CLASS; case IMPLEMENTS: return IJavaSearchConstants.INTERFACE; case EXCEPTIONS: return IJavaSearchConstants.CLASS; case ANNOTATION: return IJavaSearchConstants.ANNOTATION_TYPE; default: return IJavaSearchConstants.TYPE; } } private boolean isBeforeTypeName(ContentAssistLocation location, GroovyCompilationUnit unit, int completionLocation) { if (location != ContentAssistLocation.CLASS_BODY) { return false; } NameAndLocation nameAndLocation = new ExpressionFinder() .findPreviousTypeNameToken(new CharArraySourceBuffer(unit.getContents()), completionLocation); if (nameAndLocation == null) { return false; } if (!(getContext().completionNode instanceof FieldNode)) { return false; } return !FIELD_MODIFIERS.contains(nameAndLocation.name.trim()); } }