move goto base functionality from lang-impl to analysis-impl

GitOrigin-RevId: ac1c1c2d5e6ae6e71f628424179b2d50a04d79d0
This commit is contained in:
hsestupin
2019-12-03 15:11:09 +00:00
committed by intellij-monorepo-bot
parent 1545256330
commit 606f7c9d61
5 changed files with 117 additions and 74 deletions
@@ -0,0 +1,63 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtilKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class TargetElementUtilBase {
/**
* 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
* identifiers around, or the {@code offset} is already in one.
*
* @param file language source for the {@link #isIdentifierPart(PsiFile, CharSequence, int)}
* @see PsiTreeUtilKt#elementsAroundOffsetUp(PsiFile, int)
*/
public static int adjustOffset(@Nullable PsiFile file, Document document, final int offset) {
CharSequence text = document.getCharsSequence();
int correctedOffset = offset;
int textLength = document.getTextLength();
if (offset >= textLength) {
correctedOffset = textLength - 1;
}
else if (!isIdentifierPart(file, text, offset)) {
correctedOffset--;
}
if (correctedOffset >= 0) {
char charAt = text.charAt(correctedOffset);
if (charAt == '\'' || charAt == '"' || charAt == ')' || charAt == ']' ||
isIdentifierPart(file, text, correctedOffset)) {
return correctedOffset;
}
}
return offset;
}
/**
* @return true iff character at the offset may be a part of an identifier.
* @see Character#isJavaIdentifierPart(char)
* @see TargetElementEvaluatorEx#isIdentifierPart(PsiFile, CharSequence, int)
*/
private static boolean isIdentifierPart(@Nullable PsiFile file, CharSequence text, int offset) {
if (file != null) {
TargetElementEvaluatorEx evaluator = getElementEvaluatorsEx(file.getLanguage());
if (evaluator != null && evaluator.isIdentifierPart(file, text, offset)) return true;
}
return Character.isJavaIdentifierPart(text.charAt(offset));
}
static final LanguageExtension<TargetElementEvaluator> TARGET_ELEMENT_EVALUATOR =
new LanguageExtension<>("com.intellij.targetElementEvaluator");
@Nullable
private static TargetElementEvaluatorEx getElementEvaluatorsEx(@NotNull Language language) {
TargetElementEvaluator result = TARGET_ELEMENT_EVALUATOR.forLanguage(language);
return result instanceof TargetElementEvaluatorEx ? (TargetElementEvaluatorEx)result : null;
}
}
@@ -0,0 +1,44 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.navigation.action;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
import com.intellij.diagnostic.PluginException;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class GotoDeclarationUtil {
private static final Logger LOG = Logger.getInstance(GotoDeclarationUtil.class);
@Nullable
public static PsiElement[] findTargetElementsFromProviders(@NotNull Editor editor,
int offset,
PsiFile file) {
PsiElement elementAt = file.findElementAt(TargetElementUtilBase.adjustOffset(file, editor.getDocument(), offset));
for (GotoDeclarationHandler handler : GotoDeclarationHandler.EP_NAME.getExtensionList()) {
PsiElement[] result = handler.getGotoDeclarationTargets(elementAt, offset, editor);
if (result != null && result.length > 0) {
return assertNotNullElements(result, handler.getClass()) ? result : null;
}
}
return PsiElement.EMPTY_ARRAY;
}
private static boolean assertNotNullElements(@NotNull PsiElement[] result, Class<?> clazz) {
for (PsiElement element : result) {
if (element == null) {
PluginException.logPluginError(LOG,
"Null target element is returned by 'getGotoDeclarationTargets' in " + clazz.getName(), null, clazz
);
return false;
}
}
return true;
}
}
@@ -8,7 +8,6 @@ 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.lang.LanguageExtension;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.components.ServiceManager;
@@ -27,7 +26,6 @@ import com.intellij.psi.*;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.SearchScope;
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;
@@ -110,7 +108,7 @@ public class TargetElementUtil {
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
PsiReference ref = file.findReferenceAt(adjustOffset(file, document, offset));
PsiReference ref = file.findReferenceAt(TargetElementUtilBase.adjustOffset(file, document, offset));
if (ref == null) return null;
int elementOffset = ref.getElement().getTextRange().getStartOffset();
@@ -123,45 +121,8 @@ public class TargetElementUtil {
return null;
}
/**
* 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
* identifiers around, or the {@code offset} is already in one.
*
* @param file language source for the {@link #isIdentifierPart(com.intellij.psi.PsiFile, java.lang.CharSequence, int)}
* @see PsiTreeUtilKt#elementsAroundOffsetUp(PsiFile, int)
*/
public static int adjustOffset(@Nullable PsiFile file, Document document, final int offset) {
CharSequence text = document.getCharsSequence();
int correctedOffset = offset;
int textLength = document.getTextLength();
if (offset >= textLength) {
correctedOffset = textLength - 1;
}
else if (!isIdentifierPart(file, text, offset)) {
correctedOffset--;
}
if (correctedOffset >= 0) {
char charAt = text.charAt(correctedOffset);
if (charAt == '\'' || charAt == '"' || charAt == ')' || charAt == ']' ||
isIdentifierPart(file, text, correctedOffset)) {
return correctedOffset;
}
}
return offset;
}
/**
* @return true iff character at the offset may be a part of an identifier.
* @see Character#isJavaIdentifierPart(char)
* @see TargetElementEvaluatorEx#isIdentifierPart(com.intellij.psi.PsiFile, java.lang.CharSequence, int)
*/
private static boolean isIdentifierPart(@Nullable PsiFile file, CharSequence text, int offset) {
if (file != null) {
TargetElementEvaluatorEx evaluator = getElementEvaluatorsEx(file.getLanguage());
if (evaluator != null && evaluator.isIdentifierPart(file, text, offset)) return true;
}
return Character.isJavaIdentifierPart(text.charAt(offset));
return TargetElementUtilBase.adjustOffset(file, document, offset);
}
public static boolean inVirtualSpace(@NotNull Editor editor, int offset) {
@@ -225,7 +186,7 @@ public class TargetElementUtil {
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
int adjusted = adjustOffset(file, document, offset);
int adjusted = TargetElementUtilBase.adjustOffset(file, document, offset);
PsiElement element = file.findElementAt(adjusted);
if (BitUtil.isSet(flags, REFERENCED_ELEMENT_ACCEPTED)) {
@@ -372,7 +333,7 @@ public class TargetElementUtil {
if (ref == null) return null;
final Language language = ref.getElement().getLanguage();
TargetElementEvaluator evaluator = TARGET_ELEMENT_EVALUATOR.forLanguage(language);
TargetElementEvaluator evaluator = TargetElementUtilBase.TARGET_ELEMENT_EVALUATOR.forLanguage(language);
if (evaluator != null) {
final PsiElement element = evaluator.getElementByReference(ref, flags);
if (element != null) return element;
@@ -426,7 +387,7 @@ public class TargetElementUtil {
}
public boolean includeSelfInGotoImplementation(@NotNull final PsiElement element) {
TargetElementEvaluator evaluator = TARGET_ELEMENT_EVALUATOR.forLanguage(element.getLanguage());
TargetElementEvaluator evaluator = TargetElementUtilBase.TARGET_ELEMENT_EVALUATOR.forLanguage(element.getLanguage());
return evaluator == null || evaluator.includeSelfInGotoImplementation(element);
}
@@ -445,16 +406,9 @@ public class TargetElementUtil {
return PsiSearchHelper.getInstance(element.getProject()).getUseScope(file != null ? file : element);
}
private static final LanguageExtension<TargetElementEvaluator> TARGET_ELEMENT_EVALUATOR =
new LanguageExtension<>("com.intellij.targetElementEvaluator");
@Nullable
private static TargetElementEvaluatorEx getElementEvaluatorsEx(@NotNull Language language) {
TargetElementEvaluator result = TARGET_ELEMENT_EVALUATOR.forLanguage(language);
return result instanceof TargetElementEvaluatorEx ? (TargetElementEvaluatorEx)result : null;
}
@Nullable
private static TargetElementEvaluatorEx2 getElementEvaluatorsEx2(@NotNull Language language) {
TargetElementEvaluator result = TARGET_ELEMENT_EVALUATOR.forLanguage(language);
TargetElementEvaluator result = TargetElementUtilBase.TARGET_ELEMENT_EVALUATOR.forLanguage(language);
return result instanceof TargetElementEvaluatorEx2 ? (TargetElementEvaluatorEx2)result : null;
}
}
@@ -8,7 +8,7 @@ import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.actions.BaseCodeInsightAction;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.diagnostic.PluginException;
import com.intellij.codeInsight.navigation.action.GotoDeclarationUtil;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.find.actions.ShowUsagesAction;
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
@@ -241,7 +241,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
else {
final TextRange range = reference.getRangeInElement();
final String elementText = reference.getElement().getText();
LOG.assertTrue(range.getStartOffset() >= 0 && range.getEndOffset() <= elementText.length(), Arrays.toString(elements) + ";" + reference);
LOG.assertTrue(range.getStartOffset() >= 0 && range.getEndOffset() <= elementText.length(),
Arrays.toString(elements) + ";" + reference);
final String refText = range.substring(elementText);
title = MessageFormat.format(titlePattern, refText);
}
@@ -302,15 +303,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (file == null) return null;
PsiElement elementAt = file.findElementAt(TargetElementUtil.adjustOffset(file, document, offset));
for (GotoDeclarationHandler handler : GotoDeclarationHandler.EP_NAME.getExtensionList()) {
PsiElement[] result = handler.getGotoDeclarationTargets(elementAt, offset, editor);
if (result != null && result.length > 0) {
return assertNotNullElements(result, handler.getClass()) ? result : null;
}
}
return PsiElement.EMPTY_ARRAY;
return GotoDeclarationUtil.findTargetElementsFromProviders(editor, offset, file);
}
@Nullable
@@ -374,15 +367,4 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
return namesValidator.isKeyword(elementAtCaret.getText(), project);
}
private static boolean assertNotNullElements(@NotNull PsiElement[] result, Class<?> clazz) {
for (PsiElement element : result) {
if (element == null) {
PluginException.logPluginError(LOG,
"Null target element is returned by 'getGotoDeclarationTargets' in " + clazz.getName(), null, clazz
);
return false;
}
}
return true;
}
}