| |
| /* |
| * Copyright 2000-2009 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 com.intellij.codeInsight.generation.surroundWith; |
| |
| import com.intellij.codeInsight.CodeInsightBundle; |
| import com.intellij.openapi.editor.Editor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.TextRange; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.CodeStyleManager; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.search.LocalSearchScope; |
| import com.intellij.psi.search.searches.ReferencesSearch; |
| import com.intellij.psi.util.PsiUtil; |
| import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; |
| import com.intellij.util.IncorrectOperationException; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.Collection; |
| |
| public class JavaWithRunnableSurrounder extends JavaStatementsSurrounder{ |
| @Override |
| public String getTemplateDescription() { |
| return CodeInsightBundle.message("surround.with.runnable.template"); |
| } |
| |
| @Override |
| public TextRange surroundStatements(Project project, final Editor editor, PsiElement container, PsiElement[] statements) throws IncorrectOperationException{ |
| PsiManager manager = container.getManager(); |
| PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); |
| CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); |
| final String baseName = "runnable"; |
| final String uniqueName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName(baseName, container, false); |
| |
| @NonNls String text = "Runnable runnable = new Runnable(){\npublic void run(){\n}};"; |
| PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)factory.createStatementFromText(text, null); |
| declarationStatement = (PsiDeclarationStatement)codeStyleManager.reformat(declarationStatement); |
| |
| declarationStatement = (PsiDeclarationStatement)container.addAfter(declarationStatement, statements[statements.length - 1]); |
| |
| final PsiVariable variable = (PsiVariable)declarationStatement.getDeclaredElements()[0]; |
| |
| if (!Comparing.strEqual(uniqueName, baseName)) { |
| variable.setName(uniqueName); |
| } |
| |
| PsiNewExpression newExpression = (PsiNewExpression)variable.getInitializer(); |
| PsiElement[] children = newExpression.getChildren(); |
| PsiAnonymousClass anonymousClass = (PsiAnonymousClass)children[children.length - 1]; |
| PsiMethod method = anonymousClass.getMethods()[0]; |
| PsiCodeBlock body = method.getBody(); |
| body.addRange(statements[0], statements[statements.length - 1]); |
| container.deleteChildRange(statements[0], statements[statements.length - 1]); |
| |
| makeVariablesFinal(body, body); |
| |
| final int textOffset = variable.getNameIdentifier().getTextOffset(); |
| PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); |
| editor.getCaretModel().moveToOffset(textOffset); |
| editor.getSelectionModel().removeSelection(); |
| new VariableInplaceRenamer(variable, editor){ |
| @Override |
| protected boolean shouldSelectAll() { |
| return true; |
| } |
| |
| @Override |
| protected void moveOffsetAfter(boolean success) { |
| super.moveOffsetAfter(success); |
| if (success) { |
| final PsiNamedElement renamedVariable = getVariable(); |
| if (renamedVariable != null) { |
| editor.getCaretModel().moveToOffset(renamedVariable.getTextRange().getEndOffset()); |
| } |
| } |
| } |
| }.performInplaceRename(); |
| return null; |
| } |
| |
| private static void makeVariablesFinal(PsiElement scope, PsiCodeBlock body) throws IncorrectOperationException{ |
| //Q : check if variable may not be final (assigned twice)? |
| PsiElement[] children = scope.getChildren(); |
| |
| for (PsiElement child : children) { |
| makeVariablesFinal(child, body); |
| |
| if (child instanceof PsiReferenceExpression) { |
| if (child.getParent() instanceof PsiMethodCallExpression) continue; |
| if (PsiUtil.isAccessedForWriting((PsiReferenceExpression) child)) { |
| continue; |
| } |
| |
| PsiElement refElement = ((PsiReferenceExpression)child).resolve(); |
| if (refElement instanceof PsiLocalVariable || refElement instanceof PsiParameter) { |
| PsiVariable variable = (PsiVariable) refElement; |
| final PsiModifierList modifierList = variable.getModifierList(); |
| if ((modifierList != null) && (modifierList.hasModifierProperty(PsiModifier.FINAL))) { |
| continue; |
| } |
| |
| PsiElement parent = variable.getParent(); |
| PsiMethod enclosingMethod = null; |
| |
| while (parent != null) { |
| if (parent.equals(body)) break; |
| if (parent instanceof PsiMethod) { |
| enclosingMethod = (PsiMethod) parent; |
| } |
| parent = parent.getParent(); |
| } |
| if ((parent == null) && canBeDeclaredFinal(variable, enclosingMethod)) { |
| PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true); |
| } |
| } |
| } |
| } |
| } |
| |
| private static boolean canBeDeclaredFinal(@NotNull final PsiVariable variable, @Nullable final PsiElement scope) { |
| if (scope == null) { |
| return false; |
| } |
| final Collection<PsiReference> references = ReferencesSearch.search(variable, new LocalSearchScope(scope)).findAll(); |
| boolean foundOnce = (variable instanceof PsiParameter) || (variable.getInitializer() != null); |
| for (PsiReference reference : references) { |
| if (reference instanceof PsiReferenceExpression) { |
| if (PsiUtil.isAccessedForWriting((PsiReferenceExpression) reference)) { |
| if (foundOnce) { |
| return false; |
| } |
| foundOnce = true; |
| } |
| } |
| } |
| return true; |
| } |
| } |