/*
* Copyright 2011-present Greg Shrago
*
* 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.intellij.jflex.psi.impl;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.TreeTraversal;
import org.intellij.jflex.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author gregsh
*/
public class JavaRefHelper {
public static PsiReference[] getReferences(JFlexJavaCode o) {
PsiElement parent = o.getParent();
if (parent instanceof JFlexRule) {
return getRuleReferences(o);
}
//else if (parent instanceof JFlexUserCodeSection) {
// return PsiReference.EMPTY_ARRAY;
//}
//else if (parent instanceof JFlexOption) {
// return PsiReference.EMPTY_ARRAY;
//}
return PsiReference.EMPTY_ARRAY;
}
private static final Pattern RETURN_PAT = Pattern.compile("return\\s+([^;\\}]+)");
private static final Pattern YYBEGIN_PAT = Pattern.compile("yybegin\\s*\\(\\s*([^\\)]+)\\)");
@NotNull
private static PsiReference[] getRuleReferences(@NotNull JFlexJavaCode o) {
String text = o.getText();
List<PsiReference> list = ContainerUtil.newSmartList();
{
Matcher matcher = YYBEGIN_PAT.matcher(text);
for (int offset = 0; matcher.find(offset); offset = matcher.end() + 1) {
list.add(new StateRef(o, TextRange.create(matcher.start(1), matcher.end(1))));
}
}
{
Matcher matcher = RETURN_PAT.matcher(text);
for (int offset = 0; matcher.find(offset); offset = matcher.end() + 1) {
String refText = matcher.group(1);
PsiFile javaFile = createJavaFileForExpr("return " + refText + ";", o);
ContainerUtil.addAll(list, wrapJavaReferences(o, matcher.start(1), javaFile, refText));
}
}
return list.isEmpty() ? PsiReference.EMPTY_ARRAY : list.toArray(new PsiReference[list.size()]);
}
@NotNull
public static PsiReference[] getReferences(@NotNull JFlexJavaType o) {
String refText = o.getText();
PsiFile javaFile = createJavaFileForExpr(refText + " val", o);
return wrapJavaReferences(o, 0, javaFile, refText);
}
private static PsiReference[] wrapJavaReferences(@NotNull final PsiElement o, int javaOffset, PsiFile javaFile, String targetText) {
int start = javaFile.getText().lastIndexOf(targetText);
int end = start + targetText.length();
List<PsiReference> list = ContainerUtil.newSmartList();
for (PsiElement e : SyntaxTraverser.psiTraverser(javaFile).traverse(TreeTraversal.LEAVES_BFS)) {
TextRange r = e.getTextRange();
if (!r.intersects(start, end)) continue;
final PsiReference ref = javaFile.findReferenceAt(r.getStartOffset());
if (ref != null) {
TextRange rr = ref.getRangeInElement();
TextRange er = ref.getElement().getTextRange();
list.add(new PsiReferenceBase<PsiElement>(o, rr.shiftRight(javaOffset + er.getStartOffset() - start)) {
@Nullable
@Override
public PsiElement resolve() {
return ref.resolve();
}
@Override
public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
PsiElement e = getElement();
String text = StringUtil.replaceSubstring(e.getText(), getRangeInElement(), newElementName);
return e.replace(JFlexPsiElementFactory.createJavaTypeFromText(e.getProject(), text));
}
@NotNull
@Override
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
});
}
}
return list.isEmpty() ? PsiReference.EMPTY_ARRAY : list.toArray(new PsiReference[list.size()]);
}
@NotNull
public static PsiFile createJavaFileForExpr(String text, PsiElement context) {
JFlexJavaCode userCode = SyntaxTraverser.psiTraverser(context.getContainingFile()).filter(JFlexJavaCode.class).first();
String imports = userCode == null || !(userCode.getParent() instanceof JFlexUserCodeSection) ? "" : userCode.getText();
String fileText = imports + "\n" + "class A { void f() { " + text + " } }";
FileType javaType = FileTypeManager.getInstance().getFileTypeByExtension("java");
return PsiFileFactory.getInstance(context.getProject()).createFileFromText("a.java", javaType, fileText);
}
}