LAB-31 introduce limited version of findTargetElement in TargetElementUtilBase (without lookup flag)

GitOrigin-RevId: 6501c5e7a06badaad410da0d87c74d49788c87a8
This commit is contained in:
Sergey Stupin
2020-01-02 15:33:10 +00:00
committed by intellij-monorepo-bot
parent 7d38f547aa
commit 7267c98c53
2 changed files with 159 additions and 116 deletions
@@ -4,19 +4,22 @@ package com.intellij.codeInsight;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.PomDeclarationSearcher;
import com.intellij.pom.PomTarget;
import com.intellij.pom.PsiDeclaredTarget;
import com.intellij.pom.references.PomService;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTreeUtilKt;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.BitUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ThreeState;
import com.intellij.util.indexing.DumbModeAccessType;
import com.intellij.util.indexing.FileBasedIndex;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,6 +29,18 @@ import java.util.List;
public final class TargetElementUtilBase {
/**
* A flag used in {@link #findTargetElement(Editor, int, int)} indicating that if a reference is found at the specified offset,
* it should be resolved and the result returned.
*/
public static final int REFERENCED_ELEMENT_ACCEPTED = 0x01;
/**
* A flag used in {@link #findTargetElement(Editor, int, int)} indicating that if a element declaration name (e.g. class name identifier)
* is found at the specified offset, the declared element should be returned.
*/
public static final int ELEMENT_NAME_ACCEPTED = 0x02;
/**
* Attempts to adjust the {@code offset} in the {@code file} to point to an {@link #isIdentifierPart(PsiFile, CharSequence, int) identifier},
* single quote, double quote, closing bracket or parentheses by moving it back by a single character. Does nothing if there are no
@@ -141,4 +156,138 @@ public final class TargetElementUtilBase {
return getNamedElement(element);
}
@Nullable
private static PsiElement doGetReferenceOrReferencedElement(@NotNull Editor editor, int flags, int offset) {
PsiReference ref = findReference(editor, offset);
if (ref == null) return null;
Project project = editor.getProject();
if (project == null) return null;
PsiElement[] result = {null};
FileBasedIndex.getInstance().ignoreDumbMode(() -> {
final Language language = ref.getElement().getLanguage();
TargetElementEvaluator evaluator = TARGET_ELEMENT_EVALUATOR.forLanguage(language);
if (evaluator != null) {
final PsiElement element = evaluator.getElementByReference(ref, flags);
if (element != null) {
result[0] = element;
return;
}
}
result[0] = ref.resolve();
}, project, DumbModeAccessType.RELIABLE_DATA_ONLY);
return result[0];
}
@Nullable
public static PsiReference findReference(@NotNull Editor editor, int offset) {
Project project = editor.getProject();
if (project == null) return null;
Document document = editor.getDocument();
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
PsiReference ref = file.findReferenceAt(adjustOffset(file, document, offset));
if (ref == null) return null;
int elementOffset = ref.getElement().getTextRange().getStartOffset();
for (TextRange range : ReferenceRange.getRanges(ref)) {
if (range.shiftRight(elementOffset).containsOffset(offset)) {
return ref;
}
}
return null;
}
@Nullable
private static PsiElement getReferenceOrReferencedElement(@NotNull PsiFile file, @NotNull Editor editor, int flags, int offset) {
PsiElement result = doGetReferenceOrReferencedElement(editor, flags, offset);
PsiElement languageElement = file.findElementAt(offset);
Language language = languageElement != null ? languageElement.getLanguage() : file.getLanguage();
TargetElementEvaluatorEx2 evaluator = getElementEvaluatorsEx2(language);
if (evaluator != null) {
result = evaluator.adjustReferenceOrReferencedElement(file, editor, offset, flags, result);
}
return result;
}
@Nullable
private static PsiElement doFindTargetElement(@NotNull Editor editor, int flags, int offset) {
Project project = editor.getProject();
if (project == null) return null;
Document document = editor.getDocument();
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
int adjusted = adjustOffset(file, document, offset);
PsiElement element = file.findElementAt(adjusted);
if (BitUtil.isSet(flags, REFERENCED_ELEMENT_ACCEPTED)) {
final PsiElement referenceOrReferencedElement = getReferenceOrReferencedElement(file, editor, flags, offset);
//if (referenceOrReferencedElement == null) {
// return getReferenceOrReferencedElement(file, editor, flags, offset);
//}
if (isAcceptableReferencedElement(element, referenceOrReferencedElement)) {
return referenceOrReferencedElement;
}
}
if (element == null) return null;
if (BitUtil.isSet(flags, ELEMENT_NAME_ACCEPTED)) {
if (element instanceof PsiNamedElement) return element;
return getNamedElement(element, adjusted - element.getTextRange().getStartOffset());
}
return null;
}
private static boolean isAcceptableReferencedElement(@Nullable PsiElement element, @Nullable PsiElement referenceOrReferencedElement) {
if (referenceOrReferencedElement == null || !referenceOrReferencedElement.isValid()) return false;
TargetElementEvaluatorEx2 evaluator = element != null ? getElementEvaluatorsEx2(element.getLanguage()) : null;
if (evaluator != null) {
ThreeState answer = evaluator.isAcceptableReferencedElement(element, referenceOrReferencedElement);
if (answer == ThreeState.YES) return true;
if (answer == ThreeState.NO) return false;
}
return true;
}
/**
* Note: this method can perform slow PSI activity (e.g. {@link PsiReference#resolve()}, so please avoid calling it from Swing thread.
*
* @param editor editor
* @param flags a combination of {@link #REFERENCED_ELEMENT_ACCEPTED}, {@link #ELEMENT_NAME_ACCEPTED}
* @return a PSI element declared or referenced at the specified offset in the editor, depending on the flags passed.
* @see #findTargetElement(Editor, int, int)
*/
@Nullable
public static PsiElement findTargetElement(Editor editor, int flags) {
int offset = editor.getCaretModel().getOffset();
return findTargetElement(editor, flags, offset);
}
/**
* Note: this method can perform slow PSI activity (e.g. {@link PsiReference#resolve()}, so please avoid calling it from Swing thread.
* @param editor editor
* @param flags a combination of {@link #REFERENCED_ELEMENT_ACCEPTED}, {@link #ELEMENT_NAME_ACCEPTED}
* @param offset offset in the editor's document
* @return a PSI element declared or referenced at the specified offset in the editor, depending on the flags passed.
* @see #findTargetElement(Editor, int)
*/
@Nullable
public static PsiElement findTargetElement(@NotNull Editor editor, int flags, int offset) {
PsiElement result = doFindTargetElement(editor, flags, offset);
TargetElementEvaluatorEx2 evaluator = result != null ? getElementEvaluatorsEx2(result.getLanguage()) : null;
if (evaluator != null) {
result = evaluator.adjustTargetElement(editor, offset, flags, result);
}
return result;
}
}
@@ -7,7 +7,6 @@ import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.ide.util.EditSourceUtil;
import com.intellij.lang.Language;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.components.ServiceManager;
@@ -16,15 +15,11 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.BitUtil;
import com.intellij.util.ThreeState;
import com.intellij.util.indexing.DumbModeAccessType;
import com.intellij.util.indexing.FileBasedIndex;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -37,16 +32,14 @@ import java.util.List;
public class TargetElementUtil {
/**
* A flag used in {@link #findTargetElement(Editor, int, int)} indicating that if a reference is found at the specified offset,
* it should be resolved and the result returned.
* @see TargetElementUtilBase#REFERENCED_ELEMENT_ACCEPTED
*/
public static final int REFERENCED_ELEMENT_ACCEPTED = 0x01;
public static final int REFERENCED_ELEMENT_ACCEPTED = TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED;
/**
* A flag used in {@link #findTargetElement(Editor, int, int)} indicating that if a element declaration name (e.g. class name identifier)
* is found at the specified offset, the declared element should be returned.
* @see TargetElementUtilBase#ELEMENT_NAME_ACCEPTED
*/
public static final int ELEMENT_NAME_ACCEPTED = 0x02;
public static final int ELEMENT_NAME_ACCEPTED = TargetElementUtilBase.ELEMENT_NAME_ACCEPTED;
/**
* A flag used in {@link #findTargetElement(Editor, int, int)} indicating that if a lookup (e.g. completion) is shown in the editor,
@@ -97,24 +90,7 @@ public class TargetElementUtil {
@Nullable
public static PsiReference findReference(@NotNull Editor editor, int offset) {
Project project = editor.getProject();
if (project == null) return null;
Document document = editor.getDocument();
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
PsiReference ref = file.findReferenceAt(TargetElementUtilBase.adjustOffset(file, document, offset));
if (ref == null) return null;
int elementOffset = ref.getElement().getTextRange().getStartOffset();
for (TextRange range : ReferenceRange.getRanges(ref)) {
if (range.shiftRight(elementOffset).containsOffset(offset)) {
return ref;
}
}
return null;
return TargetElementUtilBase.findReference(editor, offset);
}
public static int adjustOffset(@Nullable PsiFile file, Document document, final int offset) {
@@ -158,16 +134,6 @@ public class TargetElementUtil {
*/
@Nullable
public PsiElement findTargetElement(@NotNull Editor editor, int flags, int offset) {
PsiElement result = doFindTargetElement(editor, flags, offset);
TargetElementEvaluatorEx2 evaluator = result != null ? TargetElementUtilBase.getElementEvaluatorsEx2(result.getLanguage()) : null;
if (evaluator != null) {
result = evaluator.adjustTargetElement(editor, offset, flags, result);
}
return result;
}
@Nullable
private PsiElement doFindTargetElement(@NotNull Editor editor, int flags, int offset) {
Project project = editor.getProject();
if (project == null) return null;
@@ -178,30 +144,7 @@ public class TargetElementUtil {
}
}
Document document = editor.getDocument();
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
int adjusted = TargetElementUtilBase.adjustOffset(file, document, offset);
PsiElement element = file.findElementAt(adjusted);
if (BitUtil.isSet(flags, REFERENCED_ELEMENT_ACCEPTED)) {
final PsiElement referenceOrReferencedElement = getReferenceOrReferencedElement(file, editor, flags, offset);
//if (referenceOrReferencedElement == null) {
// return getReferenceOrReferencedElement(file, editor, flags, offset);
//}
if (isAcceptableReferencedElement(element, referenceOrReferencedElement)) {
return referenceOrReferencedElement;
}
}
if (element == null) return null;
if (BitUtil.isSet(flags, ELEMENT_NAME_ACCEPTED)) {
if (element instanceof PsiNamedElement) return element;
return getNamedElement(element, adjusted - element.getTextRange().getStartOffset());
}
return null;
return TargetElementUtilBase.findTargetElement(editor, flags, offset);
}
@Nullable
@@ -219,19 +162,6 @@ public class TargetElementUtil {
return null;
}
private boolean isAcceptableReferencedElement(@Nullable PsiElement element, @Nullable PsiElement referenceOrReferencedElement) {
if (referenceOrReferencedElement == null || !referenceOrReferencedElement.isValid()) return false;
TargetElementEvaluatorEx2 evaluator = element != null ? TargetElementUtilBase.getElementEvaluatorsEx2(element.getLanguage()) : null;
if (evaluator != null) {
ThreeState answer = evaluator.isAcceptableReferencedElement(element, referenceOrReferencedElement);
if (answer == ThreeState.YES) return true;
if (answer == ThreeState.NO) return false;
}
return true;
}
@Nullable
public PsiElement adjustElement(final Editor editor, final int flags, @Nullable PsiElement element, @Nullable PsiElement contextElement) {
PsiElement langElement = element == null ? contextElement : element;
@@ -260,42 +190,6 @@ public class TargetElementUtil {
return TargetElementUtilBase.getNamedElement(element);
}
@Nullable
private static PsiElement getReferenceOrReferencedElement(@NotNull PsiFile file, @NotNull Editor editor, int flags, int offset) {
PsiElement result = doGetReferenceOrReferencedElement(editor, flags, offset);
PsiElement languageElement = file.findElementAt(offset);
Language language = languageElement != null ? languageElement.getLanguage() : file.getLanguage();
TargetElementEvaluatorEx2 evaluator = TargetElementUtilBase.getElementEvaluatorsEx2(language);
if (evaluator != null) {
result = evaluator.adjustReferenceOrReferencedElement(file, editor, offset, flags, result);
}
return result;
}
@Nullable
private static PsiElement doGetReferenceOrReferencedElement(@NotNull Editor editor, int flags, int offset) {
PsiReference ref = findReference(editor, offset);
if (ref == null) return null;
Project project = editor.getProject();
if (project == null) return null;
PsiElement[] result = {null};
FileBasedIndex.getInstance().ignoreDumbMode(() -> {
final Language language = ref.getElement().getLanguage();
TargetElementEvaluator evaluator = TargetElementUtilBase.TARGET_ELEMENT_EVALUATOR.forLanguage(language);
if (evaluator != null) {
final PsiElement element = evaluator.getElementByReference(ref, flags);
if (element != null) {
result[0] = element;
return;
}
}
result[0] = ref.resolve();
}, project, DumbModeAccessType.RELIABLE_DATA_ONLY);
return result[0];
}
@NotNull
public Collection<PsiElement> getTargetCandidates(@NotNull PsiReference reference) {
PsiElement refElement = reference.getElement();