IDEA-80399 @Language in Groovy files

This commit is contained in:
Max Medvedev
2013-06-10 11:55:53 +04:00
parent dac30636f2
commit 87a8f24126
4 changed files with 150 additions and 16 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -23,7 +23,7 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
@@ -197,21 +197,26 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
else if (parent instanceof PsiVariable) {
if (doAddLanguageAnnotation(project, (PsiModifierListOwner)parent, languageId)) return true;
}
else if (target instanceof PsiVariable) {
if (doAddLanguageAnnotation(project, (PsiModifierListOwner)target, languageId)) return true;
}
return false;
}
static boolean doAddLanguageAnnotation(final Project project, final PsiModifierListOwner modifierListOwner,
final String languageId) {
public static boolean doAddLanguageAnnotation(final Project project, final PsiModifierListOwner modifierListOwner, final String languageId) {
if (!Configuration.getProjectInstance(project).getAdvancedConfiguration().isSourceModificationAllowed()) return false;
if (modifierListOwner.getModifierList() == null || !PsiUtil.isLanguageLevel5OrHigher(modifierListOwner)) return false;
if (!OrderEntryFix.isAnnotationsJarInPath(ModuleUtil.findModuleForPsiElement(modifierListOwner))) {
if (!OrderEntryFix.isAnnotationsJarInPath(ModuleUtilCore.findModuleForPsiElement(modifierListOwner))) {
// todo add languageId comment
return false;
}
new WriteCommandAction(project, modifierListOwner.getContainingFile()) {
protected void run(final Result result) throws Throwable {
final PsiAnnotation annotation = JavaPsiFacade.getInstance(project).getElementFactory()
.createAnnotationFromText("@" + AnnotationUtil.LANGUAGE + "(\"" + languageId + "\")", modifierListOwner);
JVMElementFactory factory = JVMElementFactories.getFactory(modifierListOwner.getLanguage(), modifierListOwner.getProject());
if (factory == null) {
factory = JavaPsiFacade.getElementFactory(modifierListOwner.getProject());
}
final PsiAnnotation annotation = factory.createAnnotationFromText("@" + AnnotationUtil.LANGUAGE + "(\"" + languageId + "\")", modifierListOwner);
final PsiModifierList list = modifierListOwner.getModifierList();
assert list != null;
final PsiAnnotation existingAnnotation = list.findAnnotation(AnnotationUtil.LANGUAGE);
@@ -227,8 +232,10 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
return true;
}
private static boolean doInjectInJavaMethod(final Project project, final PsiMethod psiMethod, final int parameterIndex,
final String languageId) {
public static boolean doInjectInJavaMethod(@NotNull final Project project,
@Nullable final PsiMethod psiMethod,
final int parameterIndex,
@NotNull final String languageId) {
if (psiMethod == null) return false;
if (parameterIndex < -1) return false;
if (parameterIndex >= psiMethod.getParameterList().getParametersCount()) return false;
+1 -1
View File
@@ -27,7 +27,7 @@
<orderEntry type="module" module-name="ant" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
<orderEntry type="module" module-name="IntelliLang-java" scope="TEST" />
<orderEntry type="module" module-name="IntelliLang-java" />
<orderEntry type="module" module-name="IntelliLang-xml" scope="TEST" />
<orderEntry type="module" module-name="jps-builders" />
<orderEntry type="module" module-name="spellchecker" />
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -16,13 +16,36 @@
package org.intellij.plugins.intelliLang.inject.groovy;
import com.intellij.psi.PsiElement;
import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.tree.IElementType;
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport;
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyPatterns;
import java.util.Map;
/**
* @author Gregory.Shrago
*/
@@ -47,4 +70,104 @@ public class GroovyLanguageInjectionSupport extends AbstractLanguageInjectionSup
public String getHelpId() {
return "reference.settings.language.injection.groovy";
}
@Override
public boolean addInjectionInPlace(Language language, PsiLanguageInjectionHost psiElement) {
if (!isStringLiteral(psiElement)) return false;
return doInject(language.getID(), psiElement);
}
private static boolean doInject(String languageId, PsiElement host) {
final PsiElement target = getTopLevelInjectionTarget(host);
final PsiElement parent = target.getParent();
final Project project = host.getProject();
if (parent instanceof GrReturnStatement) {
final GrControlFlowOwner owner = ControlFlowUtils.findControlFlowOwner(parent);
if (owner instanceof GrOpenBlock && owner.getParent() instanceof GrMethod) {
return JavaLanguageInjectionSupport.doInjectInJavaMethod(project, (PsiMethod)owner.getParent(), -1, languageId);
}
}
else if (parent instanceof GrMethod) {
return JavaLanguageInjectionSupport.doInjectInJavaMethod(project, (GrMethod)parent, -1, languageId);
}
else if (parent instanceof GrAnnotationNameValuePair) {
final PsiReference ref = parent.getReference();
if (ref != null) {
final PsiElement resolved = ref.resolve();
if (resolved instanceof PsiMethod) {
return JavaLanguageInjectionSupport.doInjectInJavaMethod(project, (PsiMethod)resolved, -1, languageId);
}
}
}
else if (parent instanceof GrArgumentList && parent.getParent() instanceof GrMethodCall) {
final PsiMethod method = ((GrMethodCall)parent.getParent()).resolveMethod();
if (method != null) {
final int index = findParameterIndex(target, ((GrMethodCall)parent.getParent()));
if (index >= 0) {
return JavaLanguageInjectionSupport.doInjectInJavaMethod(project, method, index, languageId);
}
}
}
else if (parent instanceof GrAssignmentExpression) {
final GrExpression expr = ((GrAssignmentExpression)parent).getLValue();
if (expr instanceof GrReferenceExpression) {
final PsiElement element = ((GrReferenceExpression)expr).resolve();
if (element != null) {
return doInject(languageId, element);
}
}
}
else {
if (parent instanceof PsiVariable) {
if (JavaLanguageInjectionSupport.doAddLanguageAnnotation(project, (PsiModifierListOwner)parent, languageId)) return true;
}
else if (target instanceof PsiVariable && !(target instanceof LightElement)) {
if (JavaLanguageInjectionSupport.doAddLanguageAnnotation(project, (PsiModifierListOwner)target, languageId)) return true;
}
}
return false;
}
private static int findParameterIndex(PsiElement arg, GrMethodCall call) {
final GroovyResolveResult result = call.advancedResolve();
assert result.getElement() instanceof PsiMethod;
final Map<GrExpression, Pair<PsiParameter, PsiType>> map = GrClosureSignatureUtil
.mapArgumentsToParameters(result, call, false, false, call.getNamedArguments(), call.getExpressionArguments(),
call.getClosureArguments());
if (map == null) return -1;
final PsiMethod method = (PsiMethod)result.getElement();
final PsiParameter parameter = map.get(arg).first;
if (parameter == null) return -1;
return method.getParameterList().getParameterIndex(parameter);
}
private static boolean isStringLiteral(PsiLanguageInjectionHost element) {
if (element instanceof GrLiteral) {
final IElementType type = GrLiteralImpl.getLiteralType((GrLiteral)element);
return TokenSets.STRING_LITERALS.contains(type);
}
return false;
}
@NotNull
public static PsiElement getTopLevelInjectionTarget(@NotNull final PsiElement host) {
PsiElement target = host;
PsiElement parent = target.getParent();
for (; parent != null; target = parent, parent = target.getParent()) {
if (parent instanceof GrBinaryExpression) continue;
if (parent instanceof GrParenthesizedExpression) continue;
if (parent instanceof GrConditionalExpression && ((GrConditionalExpression)parent).getCondition() != target) continue;
if (parent instanceof GrAnnotationArrayInitializer) continue;
if (parent instanceof GrListOrMap) {
parent = parent.getParent(); continue;
}
break;
}
return target;
}
}
@@ -125,14 +125,18 @@ public abstract class TokenSets {
public static final TokenSet STRING_LITERALS = TokenSet.create(
mSTRING_LITERAL,
mREGEX_CONTENT,
mDOLLAR_SLASH_REGEX_CONTENT,
mGSTRING_LITERAL,
mGSTRING_CONTENT,
mGSTRING_BEGIN,
mGSTRING_CONTENT,
mGSTRING_END,
mREGEX_LITERAL,
mDOLLAR_SLASH_REGEX_LITERAL
mREGEX_BEGIN,
mREGEX_CONTENT,
mREGEX_END,
mDOLLAR_SLASH_REGEX_LITERAL,
mDOLLAR_SLASH_REGEX_BEGIN,
mDOLLAR_SLASH_REGEX_CONTENT,
mDOLLAR_SLASH_REGEX_END
);
public static final TokenSet FOR_IN_DELIMITERS = TokenSet.create(kIN, mCOLON);