mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
kotlin support
GitOrigin-RevId: 2c7a580713b05e4bf885cc9d5dd229b35c6f589d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5dc2eefe89
commit
d9498601b2
+25
@@ -0,0 +1,25 @@
|
||||
package ru.adelf.idea.dotenv.java;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JavaEnvironmentClasses {
|
||||
public static boolean isDirectMethodCall(String methodName) {
|
||||
return methodName.equals("getenv") || methodName.equals("getEnv");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<String> getClassNames(String methodName) {
|
||||
switch (methodName) {
|
||||
case "get":
|
||||
return Arrays.asList("Dotenv", "DotEnv");
|
||||
case "getProperty":
|
||||
return Collections.singletonList("System");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+2
-70
@@ -1,18 +1,10 @@
|
||||
package ru.adelf.idea.dotenv.java;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.jetbrains.php.lang.psi.elements.ArrayAccessExpression;
|
||||
import com.jetbrains.php.lang.psi.elements.PhpPsiElement;
|
||||
import com.jetbrains.php.lang.psi.elements.Variable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class JavaPsiHelper {
|
||||
public static final List<String> ARRAY_NAMES = Arrays.asList("_ENV", "_SERVER");
|
||||
|
||||
/**
|
||||
* Checks that this element environment string
|
||||
*
|
||||
@@ -52,11 +44,11 @@ class JavaPsiHelper {
|
||||
|
||||
String methodName = nameElement.getText();
|
||||
|
||||
if (isDirectMethodCall(methodName)) {
|
||||
if (JavaEnvironmentClasses.isDirectMethodCall(methodName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<String> classNames = getClassNames(methodName);
|
||||
List<String> classNames = JavaEnvironmentClasses.getClassNames(methodName);
|
||||
|
||||
if (classNames == null) {
|
||||
return false;
|
||||
@@ -74,64 +66,4 @@ class JavaPsiHelper {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isDirectMethodCall(String methodName) {
|
||||
return methodName.equals("getenv") || methodName.equals("getEnv");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<String> getClassNames(String methodName) {
|
||||
switch (methodName) {
|
||||
case "get":
|
||||
return Arrays.asList("Dotenv", "DotEnv");
|
||||
case "getProperty":
|
||||
return Collections.singletonList("System");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this array access is environment call
|
||||
*
|
||||
* @param arrayAccess Checking array
|
||||
* @return true if condition filled
|
||||
*/
|
||||
static boolean isEnvArrayCall(ArrayAccessExpression arrayAccess) {
|
||||
PhpPsiElement variable = arrayAccess.getValue();
|
||||
|
||||
if (!(variable instanceof Variable)) return false;
|
||||
|
||||
return (variable.getName() != null && ARRAY_NAMES.contains(variable.getName()));
|
||||
}
|
||||
|
||||
/* @SuppressWarnings("SameParameterValue")
|
||||
private static boolean isFunctionParameter(PsiElement psiElement, int parameterIndex, List<String> functions) {
|
||||
PsiElement variableContext = psiElement.getContext();
|
||||
if(!(variableContext instanceof ParameterList)) {
|
||||
return false;
|
||||
} else {
|
||||
ParameterList parameterList = (ParameterList) variableContext;
|
||||
PsiElement context = parameterList.getContext();
|
||||
if(!(context instanceof FunctionReference)) {
|
||||
return false;
|
||||
} else {
|
||||
FunctionReference methodReference = (FunctionReference) context;
|
||||
String name = methodReference.getName();
|
||||
|
||||
return (name != null && functions.contains(name) && getParameterIndex(parameterList, psiElement) == parameterIndex);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/* private static int getParameterIndex(ParameterList parameterList, PsiElement parameter) {
|
||||
PsiElement[] parameters = parameterList.getParameters();
|
||||
for(int i = 0; i < parameters.length; i = i + 1) {
|
||||
if(parameters[i].equals(parameter)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}*/
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package ru.adelf.idea.dotenv.kotlin;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionConfidence;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.ThreeState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
|
||||
|
||||
public class KotlinCompletionConfidence extends CompletionConfidence {
|
||||
@NotNull
|
||||
@Override
|
||||
public ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) {
|
||||
PsiElement literal = contextElement.getContext();
|
||||
if (!(literal instanceof KtLiteralStringTemplateEntry)) {
|
||||
return ThreeState.UNSURE;
|
||||
}
|
||||
|
||||
if (KotlinPsiHelper.isEnvStringLiteral((KtLiteralStringTemplateEntry) literal)) {
|
||||
return ThreeState.NO;
|
||||
}
|
||||
|
||||
return ThreeState.UNSURE;
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package ru.adelf.idea.dotenv.kotlin;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionParameters;
|
||||
import com.intellij.codeInsight.completion.CompletionProvider;
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.patterns.PlatformPatterns;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry;
|
||||
import ru.adelf.idea.dotenv.api.EnvironmentVariablesApi;
|
||||
import ru.adelf.idea.dotenv.common.BaseEnvCompletionProvider;
|
||||
|
||||
public class KotlinEnvCompletionContributor extends BaseEnvCompletionProvider implements GotoDeclarationHandler {
|
||||
public KotlinEnvCompletionContributor() {
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement().withParent(KtLiteralStringTemplateEntry.class), new CompletionProvider<CompletionParameters>() {
|
||||
@Override
|
||||
protected void addCompletions(@NotNull CompletionParameters completionParameters, @NotNull ProcessingContext processingContext, @NotNull CompletionResultSet completionResultSet) {
|
||||
PsiElement psiElement = completionParameters.getOriginalPosition();
|
||||
if (psiElement == null || getStringLiteral(psiElement) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
fillCompletionResultSet(completionResultSet, psiElement.getProject());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement psiElement, int i, Editor editor) {
|
||||
if (psiElement == null) {
|
||||
return PsiElement.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
KtLiteralStringTemplateEntry stringLiteral = getStringLiteral(psiElement);
|
||||
|
||||
if (stringLiteral == null) {
|
||||
return PsiElement.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
return EnvironmentVariablesApi.getKeyDeclarations(psiElement.getProject(), stringLiteral.getText());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KtLiteralStringTemplateEntry getStringLiteral(@NotNull PsiElement psiElement) {
|
||||
PsiElement parent = psiElement.getParent();
|
||||
|
||||
if (!(parent instanceof KtLiteralStringTemplateEntry)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!KotlinPsiHelper.isEnvStringLiteral((KtLiteralStringTemplateEntry) parent)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (KtLiteralStringTemplateEntry) parent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getActionText(@NotNull DataContext dataContext) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package ru.adelf.idea.dotenv.kotlin;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression;
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression;
|
||||
import org.jetbrains.kotlin.psi.KtTreeVisitor;
|
||||
import ru.adelf.idea.dotenv.models.KeyUsagePsiElement;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
class KotlinEnvironmentCallsVisitor extends KtTreeVisitor<Set<KeyUsagePsiElement>> {
|
||||
@Override
|
||||
public Void visitCallExpression(@NotNull KtCallExpression expression, Set<KeyUsagePsiElement> data) {
|
||||
KeyUsagePsiElement keyUsage = KotlinPsiHelper.getKeyUsageFromCall(expression);
|
||||
|
||||
if (keyUsage != null) {
|
||||
data.add(keyUsage);
|
||||
}
|
||||
|
||||
return super.visitCallExpression(expression, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression, Set<KeyUsagePsiElement> data) {
|
||||
KeyUsagePsiElement keyUsage = KotlinPsiHelper.getKeyUsageFromArrayAccess(expression);
|
||||
|
||||
if (keyUsage != null) {
|
||||
data.add(keyUsage);
|
||||
}
|
||||
|
||||
return super.visitArrayAccessExpression(expression, data);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ru.adelf.idea.dotenv.kotlin;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import ru.adelf.idea.dotenv.api.EnvironmentVariablesUsagesProvider;
|
||||
import ru.adelf.idea.dotenv.models.KeyUsagePsiElement;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class KotlinEnvironmentVariablesUsagesProvider implements EnvironmentVariablesUsagesProvider {
|
||||
@Override
|
||||
public boolean acceptFile(VirtualFile file) {
|
||||
return file.getFileType().equals(KotlinFileType.INSTANCE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<KeyUsagePsiElement> getUsages(PsiFile psiFile) {
|
||||
if (psiFile instanceof KtFile) {
|
||||
Set<KeyUsagePsiElement> result = new HashSet<>();
|
||||
|
||||
KotlinEnvironmentCallsVisitor visitor = new KotlinEnvironmentCallsVisitor();
|
||||
((KtFile) psiFile).acceptChildren(visitor, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
package ru.adelf.idea.dotenv.kotlin;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import ru.adelf.idea.dotenv.java.JavaEnvironmentClasses;
|
||||
import ru.adelf.idea.dotenv.models.KeyUsagePsiElement;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class KotlinPsiHelper {
|
||||
/**
|
||||
* Checks that this element environment string
|
||||
*
|
||||
* @param literal Checking psi element
|
||||
*/
|
||||
static boolean isEnvStringLiteral(KtLiteralStringTemplateEntry literal) {
|
||||
if (!(literal.getParent() instanceof KtStringTemplateExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiElement parent = literal.getParent().getParent();
|
||||
if (parent instanceof KtValueArgument) {
|
||||
return isMethodCallLiteral((KtValueArgument) parent);
|
||||
}
|
||||
|
||||
if (parent instanceof KtContainerNode) {
|
||||
return isArrayAccessLiteral((KtContainerNode) parent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isMethodCallLiteral(KtValueArgument valueArgument) {
|
||||
PsiElement valueArgumentList = valueArgument.getParent();
|
||||
|
||||
if (!(valueArgumentList instanceof KtValueArgumentList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((KtValueArgumentList) valueArgumentList).getArguments().get(0) != valueArgument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiElement methodCall = valueArgumentList.getParent();
|
||||
|
||||
if (!(methodCall instanceof KtCallExpression)) return false;
|
||||
|
||||
return isEnvMethodCall((KtCallExpression) methodCall);
|
||||
}
|
||||
|
||||
private static boolean isArrayAccessLiteral(KtContainerNode containerNode) {
|
||||
if (!(containerNode.getParent() instanceof KtArrayAccessExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isEnvArrayAccess((KtArrayAccessExpression) containerNode.getParent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this function reference is reference for env functions, like env or getenv
|
||||
*
|
||||
* @param methodCallExpression Checking reference
|
||||
* @return true if condition filled
|
||||
*/
|
||||
static boolean isEnvMethodCall(KtCallExpression methodCallExpression) {
|
||||
PsiElement nameElement = methodCallExpression.getCalleeExpression();
|
||||
|
||||
if (!(nameElement instanceof KtNameReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String methodName = ((KtNameReferenceExpression) nameElement).getReferencedName();
|
||||
|
||||
if (JavaEnvironmentClasses.isDirectMethodCall(methodName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<String> classNames = JavaEnvironmentClasses.getClassNames(methodName);
|
||||
|
||||
if (classNames == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkReferences(methodCallExpression.getCalleeExpression(), classNames);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static KeyUsagePsiElement getKeyUsageFromCall(@NotNull KtCallExpression expression) {
|
||||
if (!isEnvMethodCall(expression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
KtValueArgumentList valueArgumentList = expression.getValueArgumentList();
|
||||
|
||||
if (valueArgumentList == null || valueArgumentList.getArguments().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
KtValueArgument valueArgument = valueArgumentList.getArguments().get(0);
|
||||
|
||||
if (valueArgument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getKeyUsageFromStringTemplate(valueArgument.getFirstChild());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this array access is environment call
|
||||
*
|
||||
* @param arrayAccess Checking array
|
||||
* @return true if condition filled
|
||||
*/
|
||||
static boolean isEnvArrayAccess(KtArrayAccessExpression arrayAccess) {
|
||||
List<String> classNames = JavaEnvironmentClasses.getClassNames("get");
|
||||
|
||||
if (classNames == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkReferences(arrayAccess, classNames);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static KeyUsagePsiElement getKeyUsageFromArrayAccess(@NotNull KtArrayAccessExpression expression) {
|
||||
if (!isEnvArrayAccess(expression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<KtExpression> indexExpressions = expression.getIndexExpressions();
|
||||
|
||||
if (indexExpressions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getKeyUsageFromStringTemplate(indexExpressions.get(0));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static KeyUsagePsiElement getKeyUsageFromStringTemplate(PsiElement element) {
|
||||
if (!(element instanceof KtStringTemplateExpression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
KtLiteralStringTemplateEntry literal = PsiTreeUtil.findChildOfType(element, KtLiteralStringTemplateEntry.class);
|
||||
|
||||
if (literal == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new KeyUsagePsiElement(literal.getText(), literal);
|
||||
}
|
||||
|
||||
private static boolean checkReferences(PsiElement element, List<String> classNames) {
|
||||
return Arrays.stream(element.getReferences()).anyMatch(psiReference -> {
|
||||
PsiElement method = psiReference.resolve();
|
||||
|
||||
if (method instanceof KtNamedFunction) {
|
||||
KtClass ktClass = PsiTreeUtil.getParentOfType(method, KtClass.class);
|
||||
|
||||
return ktClass != null && classNames.contains(ktClass.getName());
|
||||
} else if (method instanceof PsiMethod) {
|
||||
// Maybe it's a Java reference?
|
||||
PsiClass psiClass = ((PsiMethod) method).getContainingClass();
|
||||
|
||||
return psiClass != null && classNames.contains(psiClass.getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<completion.contributor language="kotlin" implementationClass="ru.adelf.idea.dotenv.kotlin.KotlinEnvCompletionContributor"/>
|
||||
<gotoDeclarationHandler implementation="ru.adelf.idea.dotenv.kotlin.KotlinEnvCompletionContributor"/>
|
||||
<completion.confidence language="kotlin" implementationClass="ru.adelf.idea.dotenv.kotlin.KotlinCompletionConfidence"
|
||||
id="envStringCompletionConfidence" order="first"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="ru.adelf.idea.dotenv">
|
||||
<environmentVariablesUsagesProvider implementation="ru.adelf.idea.dotenv.kotlin.KotlinEnvironmentVariablesUsagesProvider"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -66,6 +66,7 @@
|
||||
<depends>com.intellij.modules.platform</depends>
|
||||
|
||||
<depends optional="true" config-file="java.xml">com.intellij.java</depends>
|
||||
<depends optional="true" config-file="kotlin.xml">org.jetbrains.kotlin</depends>
|
||||
<depends optional="true" config-file="php.xml">com.jetbrains.php</depends>
|
||||
<depends optional="true" config-file="ruby.xml">com.intellij.modules.ruby</depends>
|
||||
<depends optional="true" config-file="python.xml">com.intellij.modules.python</depends>
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package ru.adelf.idea.dotenv.tests.usages;
|
||||
|
||||
public class KotlinUsagesTest extends BaseUsagesTest {
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.copyDirectoryToProject("kotlin", "src/kotlin");
|
||||
}
|
||||
|
||||
public void testGetEnvUsages() {
|
||||
assertUsagesContains("KOTLIN_GET_ENV", "KOTLIN_GET_ENV2");
|
||||
}
|
||||
|
||||
public void testDotEnvGetUsages() {
|
||||
assertUsagesContains("KOTLIN_DOTENV_GET", "KOTLIN_DOTENV_GET2");
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package ru.adelf.idea.dotenv.tests.usages.fixtures.kotlin
|
||||
|
||||
import java.lang.System.getenv
|
||||
|
||||
class KotlinUsages {
|
||||
fun getEnv() {
|
||||
getenv("KOTLIN_GET_ENV")
|
||||
|
||||
System.getenv("KOTLIN_GET_ENV2")
|
||||
}
|
||||
|
||||
fun getDotenvGet() {
|
||||
Dotenv().get("KOTLIN_DOTENV_GET")
|
||||
|
||||
val d = Dotenv()
|
||||
|
||||
d["KOTLIN_DOTENV_GET2"]
|
||||
}
|
||||
}
|
||||
|
||||
class Dotenv {
|
||||
operator fun get(key: String): String {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user