/*
* 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.search;
import org.codehaus.groovy.eclipse.core.search.SyntheticAccessorSearchRequestor;
import org.codehaus.jdt.groovy.model.GroovyCompilationUnit;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.search.FieldDeclarationMatch;
import org.eclipse.jdt.core.search.FieldReferenceMatch;
import org.eclipse.jdt.core.search.LocalVariableDeclarationMatch;
import org.eclipse.jdt.core.search.LocalVariableReferenceMatch;
import org.eclipse.jdt.core.search.MethodReferenceMatch;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.groovy.core.util.ReflectionUtils;
import org.eclipse.jdt.internal.core.search.JavaSearchParticipant;
import org.eclipse.jdt.internal.ui.search.JavaElementMatch;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.search.ElementQuerySpecification;
import org.eclipse.jdt.ui.search.IMatchPresentation;
import org.eclipse.jdt.ui.search.IQueryParticipant;
import org.eclipse.jdt.ui.search.ISearchRequestor;
import org.eclipse.jdt.ui.search.QuerySpecification;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.search.ui.text.Match;
import org.eclipse.ui.PartInitException;
/**
* This class handles searching for accessing synthetic getters, setters, and
* properties (ie- fields that don't exist, but have an associated getter or
* setter).
*
* @author andrew
* @created Oct 3, 2011
*/
public class SyntheticAccessorQueryParticipant implements IQueryParticipant {
class UISearchRequestor implements org.codehaus.groovy.eclipse.core.search.ISearchRequestor {
private final ISearchRequestor requestor;
private final boolean targetIsGroovy;
public UISearchRequestor(ISearchRequestor requestor, boolean targetIsGroovy) {
this.requestor = requestor;
this.targetIsGroovy = targetIsGroovy;
}
/**
* Rules for when to match and when not to match. See GRECLIPSE-1369
*
* Target is:
* Groovy property: match field and getter references in Java and Groovy. Field reference will be error in Java</br>
* Groovy getter: match field and getter references in Groovy. Getter references only in Java</br>
* Java field: match field and getter references in Groovy. Field references only in Java</br>
* Java method: match field and getter references in Groovy. Getter references only in Java</br>
*
* If Java target, then ignore extra references in Java
* If Groovy target, then ignore
*/
public void acceptMatch(SearchMatch match) {
IJavaElement enclosingElement = (IJavaElement) match.getElement();
if (enclosingElement != null) {
if (!(enclosingElement.getOpenable() instanceof GroovyCompilationUnit) && !targetIsGroovy) {
return;
}
boolean isWriteAccess = false;
boolean isReadAccess = false;
if (match instanceof FieldReferenceMatch) {
FieldReferenceMatch fieldRef = ((FieldReferenceMatch) match);
isWriteAccess = fieldRef.isWriteAccess();
isReadAccess = fieldRef.isReadAccess();
} else if (match instanceof FieldDeclarationMatch) {
isWriteAccess = true;
} else if (match instanceof LocalVariableReferenceMatch) {
LocalVariableReferenceMatch localVarRef = ((LocalVariableReferenceMatch) match);
isWriteAccess = localVarRef.isWriteAccess();
isReadAccess = localVarRef.isReadAccess();
} else if (match instanceof LocalVariableDeclarationMatch) {
isWriteAccess = true;
}
boolean isSuperInvocation = false;
if (match instanceof MethodReferenceMatch) {
MethodReferenceMatch methodRef = (MethodReferenceMatch) match;
isSuperInvocation = methodRef.isSuperInvocation();
}
requestor.reportMatch(createJavaElementMatch(enclosingElement, match.getRule(), match.getOffset(),
match.getLength(), match.getAccuracy(), isReadAccess, isWriteAccess, match.isInsideDocComment(),
isSuperInvocation));
}
}
private Match createJavaElementMatch(IJavaElement enclosingElement, int rule, int offset, int length, int accuracy,
boolean isReadAccess, boolean isWriteAccess, boolean insideDocComment, boolean isSuperInvocation) {
return ReflectionUtils.invokeConstructor(JavaElementMatch.class, new Class<?>[] {
Object.class, int.class, int.class, int.class, int.class, boolean.class, boolean.class, boolean.class, boolean.class
}, new Object[] {
enclosingElement, rule, offset, length, accuracy, isReadAccess, isWriteAccess, insideDocComment, isSuperInvocation
});
}
}
SyntheticAccessorSearchRequestor accessorRequestor;
public void search(ISearchRequestor requestor, QuerySpecification querySpecification, IProgressMonitor monitor)
throws CoreException {
if (querySpecification instanceof ElementQuerySpecification) {
accessorRequestor = new SyntheticAccessorSearchRequestor();
IJavaElement element = ((ElementQuerySpecification) querySpecification).getElement();
accessorRequestor.findSyntheticMatches(element,
querySpecification.getLimitTo(), getSearchParticipants(), querySpecification.getScope(), new UISearchRequestor(
requestor, element.getOpenable() instanceof GroovyCompilationUnit), monitor);
}
}
private SearchParticipant[] getSearchParticipants() {
return new SearchParticipant[] { new JavaSearchParticipant() };
}
public int estimateTicks(QuerySpecification specification) {
if (!(specification instanceof ElementQuerySpecification)) {
return 0;
}
return 3;
}
public IMatchPresentation getUIParticipant() {
return new IMatchPresentation() {
public ILabelProvider createLabelProvider() {
return new JavaElementLabelProvider();
}
public void showMatch(Match match, int currentOffset, int currentLength, boolean activate) throws PartInitException {
// no-op
}
};
}
}