blob: 722f987c5e6437af07505b5b4b5ff6accf036e0e [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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.jetbrains.plugins.groovy.spock;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Sergey Evdokimov
*/
public class SpockUnrollReferenceProvider extends PsiReferenceProvider {
private static final Pattern PATTERN = Pattern.compile("\\#([\\w_]+)");
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
GrAnnotationNameValuePair nvp = (GrAnnotationNameValuePair)element.getParent();
String name = nvp.getName();
if (name != null && !name.equals("value")) return PsiReference.EMPTY_ARRAY;
PsiElement argumentList = nvp.getParent();
if (!(argumentList instanceof GrAnnotationArgumentList)) return PsiReference.EMPTY_ARRAY;
PsiElement eAnnotation = argumentList.getParent();
if (!(eAnnotation instanceof GrAnnotation)) return PsiReference.EMPTY_ARRAY;
GrAnnotation annotation = (GrAnnotation)eAnnotation;
String shortName = annotation.getShortName();
if (!shortName.equals("Unroll") && !shortName.equals("spock.lang.Unroll")) return PsiReference.EMPTY_ARRAY;
PsiElement modifierList = annotation.getParent();
if (!(modifierList instanceof GrModifierList)) return PsiReference.EMPTY_ARRAY;
PsiElement eMethod = modifierList.getParent();
if (!(eMethod instanceof GrMethod)) return PsiReference.EMPTY_ARRAY;
final GrMethod method = (GrMethod)eMethod;
ElementManipulator<PsiElement> manipulator = ElementManipulators.getManipulator(element);
TextRange rangeInElement = manipulator.getRangeInElement(element);
String text = rangeInElement.substring(element.getText());
final List<SpockVariableReference> references = new ArrayList<SpockVariableReference>();
Matcher matcher = PATTERN.matcher(text);
while (matcher.find()) {
TextRange range = new TextRange(rangeInElement.getStartOffset() + matcher.start(1), rangeInElement.getStartOffset() + matcher.end(1));
references.add(new SpockVariableReference(element, range, references, method));
}
return references.toArray(new PsiReference[references.size()]);
}
private static class SpockVariableReference extends PsiReferenceBase<PsiElement> {
private final PsiElement myLeafElement;
private final List<SpockVariableReference> myReferences;
private final GrMethod myMethod;
public SpockVariableReference(PsiElement element, TextRange range, List<SpockVariableReference> references, GrMethod method) {
super(element, range);
myReferences = references;
myMethod = method;
myLeafElement = element.getFirstChild();
}
@Override
public PsiElement resolve() {
Map<String, SpockVariableDescriptor> variableMap = SpockUtils.getVariableMap(myMethod);
String value = getValue();
SpockVariableDescriptor descriptor = variableMap.get(value);
if (descriptor == null) return null;
return descriptor.getVariable();
}
@NotNull
@Override
public Object[] getVariants() {
Map<String, SpockVariableDescriptor> variableMap = SpockUtils.getVariableMap(myMethod);
Object[] res = new Object[variableMap.size()];
int i = 0;
for (SpockVariableDescriptor descriptor : variableMap.values()) {
res[i++] = descriptor.getVariable();
}
return res;
}
@Override
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
if (getElement().getFirstChild() != myLeafElement) { // Element already renamed.
return getElement();
}
String oldValue = getValue();
PsiElement res = null;
for (int i = myReferences.size(); --i >= 0; ) {
SpockVariableReference reference = myReferences.get(i);
if (oldValue.equals(reference.getCanonicalText())) {
res = reference.superHandleRename(newElementName);
}
}
return res;
}
public PsiElement superHandleRename(String newName) {
return super.handleElementRename(newName);
}
}
}