diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java index c38cf6e026d6..70843dbd4763 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java @@ -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; diff --git a/plugins/groovy/jetgroovy.iml b/plugins/groovy/jetgroovy.iml index bb64ecbe2d34..38452af447cc 100644 --- a/plugins/groovy/jetgroovy.iml +++ b/plugins/groovy/jetgroovy.iml @@ -27,7 +27,7 @@ - + diff --git a/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/GroovyLanguageInjectionSupport.java b/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/GroovyLanguageInjectionSupport.java index f19c1bf888f7..ea384086f3fb 100644 --- a/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/GroovyLanguageInjectionSupport.java +++ b/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/GroovyLanguageInjectionSupport.java @@ -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> 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; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java index f2dcba80117e..45c51b40dee0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java @@ -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);