| /* |
| * 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. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.jetbrains.plugins.groovy.refactoring; |
| |
| import com.intellij.openapi.util.Key; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; |
| import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; |
| import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; |
| import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; |
| import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; |
| import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; |
| import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; |
| |
| /** |
| * @author Maxim.Medvedev |
| */ |
| public class GroovyChangeContextUtil { |
| private static final Key<PsiClass> QUALIFIER_CLASS_KEY = Key.create("QUALIFIER_CLASS_KEY"); |
| private static final Key<PsiClass> REF_TO_CLASS = Key.create("REF_TO_CLASS"); |
| private static final Key<PsiMember> REF_TO_MEMBER = Key.create("REF_TO_MEMBER"); |
| private static final Key<Object> KEY_ENCODED = Key.create("KEY_ENCODED"); |
| |
| private GroovyChangeContextUtil() { |
| } |
| |
| public static void encodeContextInfo(PsiElement element) { |
| encodeContextInfo(element, element); |
| } |
| |
| public static void encodeContextInfo(PsiElement element, PsiElement scope) { |
| if (!(element instanceof GroovyPsiElement)) return; |
| if (PsiUtil.isThisReference(element)) { |
| GrReferenceExpression thisExpr = (GrReferenceExpression)element; |
| final PsiClass containingClass = PsiTreeUtil.getParentOfType(thisExpr, PsiClass.class); |
| element.putCopyableUserData(KEY_ENCODED, KEY_ENCODED); |
| thisExpr.putCopyableUserData(QUALIFIER_CLASS_KEY, containingClass); |
| } |
| else if (element instanceof GrReferenceExpression) { |
| GrReferenceExpression refExpr = (GrReferenceExpression)element; |
| final GrExpression qualifier = refExpr.getQualifierExpression(); |
| if (qualifier == null) { |
| PsiElement refElement = refExpr.resolve(); |
| element.putCopyableUserData(KEY_ENCODED, KEY_ENCODED); |
| if (refElement != null && !PsiTreeUtil.isContextAncestor(scope, refElement, false)) { |
| if (refElement instanceof GrAccessorMethod) refElement = ((GrAccessorMethod)refElement).getProperty(); |
| if (refElement instanceof PsiClass) { |
| refExpr.putCopyableUserData(REF_TO_CLASS, (PsiClass)refElement); |
| } |
| else if (refElement instanceof PsiMember) { |
| refExpr.putCopyableUserData(REF_TO_MEMBER, (PsiMember)refElement); |
| } |
| } |
| } |
| } |
| else if (element instanceof GrCodeReferenceElement) { |
| final PsiElement resolvedElement = ((GrCodeReferenceElement)element).resolve(); |
| element.putCopyableUserData(KEY_ENCODED, KEY_ENCODED); |
| if (resolvedElement instanceof PsiClass && !PsiTreeUtil.isContextAncestor(scope, resolvedElement, false)) { |
| element.putCopyableUserData(REF_TO_CLASS, (PsiClass)resolvedElement); |
| } |
| } |
| |
| for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { |
| encodeContextInfo(child, scope); |
| } |
| |
| } |
| |
| public static void decodeContextInfo(PsiElement element, @Nullable PsiClass thisClass, @Nullable GrExpression thisAccessExpr) { |
| if (!(element instanceof GroovyPsiElement)) return; |
| for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { |
| decodeContextInfo(child, thisClass, thisAccessExpr); |
| } |
| if (element.getCopyableUserData(KEY_ENCODED) != null) { |
| element.putCopyableUserData(KEY_ENCODED, null); |
| final PsiManager manager = element.getManager(); |
| if (PsiUtil.isThisReference(element)) { |
| final PsiClass thisQualClass = element.getCopyableUserData(QUALIFIER_CLASS_KEY); |
| element.putCopyableUserData(QUALIFIER_CLASS_KEY, null); |
| if (thisAccessExpr != null && !manager.areElementsEquivalent(thisClass, thisQualClass)) { |
| element.replace(thisAccessExpr); |
| return; |
| } |
| } |
| |
| else if (element instanceof GrReferenceExpression) { |
| final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(element.getProject()); |
| final GrReferenceExpression refExpr = (GrReferenceExpression)element; |
| final PsiElement resolvedElement = refExpr.resolve(); |
| final PsiMember memberRef = refExpr.getCopyableUserData(REF_TO_MEMBER); |
| refExpr.putCopyableUserData(REF_TO_MEMBER, null); |
| if (memberRef != null && memberRef.isValid()) { |
| final PsiClass memberClass = memberRef.getContainingClass(); |
| if (memberClass != null) { |
| if (memberRef.hasModifierProperty(PsiModifier.STATIC)) { |
| if (!manager.areElementsEquivalent(memberRef, resolvedElement)) { |
| final PsiElement qualifier = refExpr.getQualifier(); |
| if (!(qualifier instanceof GrReferenceExpression)) { |
| refExpr.setQualifier(factory.createReferenceExpressionFromText(memberClass.getQualifiedName())); |
| JavaCodeStyleManager.getInstance(manager.getProject()).shortenClassReferences(refExpr.getQualifier()); |
| return; |
| } |
| } |
| } |
| else if (thisAccessExpr instanceof GrReferenceExpression) { |
| final PsiElement qualifier = refExpr.getQualifier(); |
| if (!(qualifier instanceof GrReferenceExpression)) { |
| refExpr.setQualifier(thisAccessExpr); |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| PsiClass refClass = element.getCopyableUserData(REF_TO_CLASS); |
| element.putCopyableUserData(REF_TO_CLASS, null); |
| |
| if (refClass != null && refClass.isValid()) { |
| final PsiReference ref = element.getReference(); |
| if (ref != null) { |
| ref.bindToElement(refClass); |
| } |
| } |
| } |
| } |
| |
| public static void clearContextInfo(PsiElement scope) { |
| scope.putCopyableUserData(QUALIFIER_CLASS_KEY, null); |
| scope.putCopyableUserData(REF_TO_CLASS, null); |
| scope.putCopyableUserData(REF_TO_MEMBER, null); |
| for (PsiElement child = scope.getFirstChild(); child != null; child = child.getNextSibling()) { |
| clearContextInfo(child); |
| } |
| } |
| } |