Add "try-with-resources" live postfix template

This commit is contained in:
Andrey Starovoyt
2014-04-17 17:57:50 +04:00
parent cfec5b058e
commit 5d908867e0
14 changed files with 324 additions and 4 deletions
@@ -0,0 +1,109 @@
/*
* Copyright 2000-2014 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.template.postfix.templates;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.intention.impl.TypeExpression;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.codeInsight.template.impl.MacroCallNode;
import com.intellij.codeInsight.template.impl.TextExpression;
import com.intellij.codeInsight.template.macro.SuggestVariableNameMacro;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
public class TryWithResourcesPostfixTemplate extends PostfixTemplate {
protected TryWithResourcesPostfixTemplate() {
super("twr", "Description", "Example");
}
@Override
public boolean isApplicable(@NotNull PsiElement element, @NotNull Document copyDocument, int newOffset) {
if (!PsiUtil.isLanguageLevel7OrHigher(element)) return false;
PsiExpression initializer = getTopmostExpression(element);
if (initializer == null) return false;
final PsiType type = initializer.getType();
if (!(type instanceof PsiClassType)) return false;
final PsiClass aClass = ((PsiClassType)type).resolve();
Project project = element.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiClass autoCloseable = facade.findClass(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, ProjectScope.getLibrariesScope(project));
if (!InheritanceUtil.isInheritorOrSelf(aClass, autoCloseable, true)) return false;
return true;
}
@Override
public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
PsiExpression expression = getTopmostExpression(context);
assert expression != null;
Project project = context.getProject();
editor.getDocument().deleteString(expression.getTextRange().getStartOffset(), expression.getTextRange().getEndOffset());
TemplateManager manager = TemplateManager.getInstance(project);
Template template = manager.createTemplate("", "");
template.setToReformat(true);
template.addTextSegment("try (");
MacroCallNode name = new MacroCallNode(new SuggestVariableNameMacro());
template.addVariable("type", new TypeExpression(project, new PsiType[]{expression.getType()}), false);
template.addTextSegment(" ");
template.addVariable("name", name, name, true);
template.addTextSegment(" = ");
template.addVariable("variable", new TextExpression(expression.getText()), false);
template.addTextSegment(") {\n");
template.addEndVariable();
template.addTextSegment("\n}");
Collection<PsiClassType> unhandled = getUnhandled(expression);
for (PsiClassType exception : unhandled) {
MacroCallNode variable = new MacroCallNode(new SuggestVariableNameMacro());
template.addTextSegment("catch(");
template.addVariable("type " + exception.getClassName(), new TypeExpression(project, new PsiType[]{exception}), false);
template.addTextSegment(" ");
template.addVariable("name " + exception.getClassName(), variable, variable, false);
template.addTextSegment(") {}");
}
manager.startTemplate(editor, template);
}
@NotNull
private static Collection<PsiClassType> getUnhandled(@NotNull PsiExpression expression) {
assert expression.getType() != null;
PsiMethod methodCloser = PsiUtil.getResourceCloserMethodForType((PsiClassType)expression.getType(), expression.getProject());
PsiSubstitutor substitutor = PsiUtil.resolveGenericsClassInType(expression.getType()).getSubstitutor();
return methodCloser != null
? ExceptionUtil.getUnhandledExceptions(methodCloser, expression, null, substitutor)
: Collections.<PsiClassType>emptyList();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -998,10 +998,14 @@ public final class PsiUtil extends PsiUtilCore {
public static PsiMethod getResourceCloserMethod(@NotNull final PsiResourceVariable resource) {
final PsiType resourceType = resource.getType();
if (!(resourceType instanceof PsiClassType)) return null;
final PsiClass resourceClass = ((PsiClassType)resourceType).resolve();
return getResourceCloserMethodForType((PsiClassType)resourceType, resource.getProject());
}
@Nullable
public static PsiMethod getResourceCloserMethodForType(@NotNull final PsiClassType resourceType, Project project) {
final PsiClass resourceClass = resourceType.resolve();
if (resourceClass == null) return null;
final Project project = resource.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiClass autoCloseable = facade.findClass(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, ProjectScope.getLibrariesScope(project));
if (autoCloseable == null) return null;
@@ -537,7 +537,7 @@ public class ExceptionUtil {
}
@NotNull
private static List<PsiClassType> getUnhandledExceptions(@Nullable PsiMethod method,
public static List<PsiClassType> getUnhandledExceptions(@Nullable PsiMethod method,
PsiElement element,
PsiElement topElement,
@NotNull PsiSubstitutor substitutor) {
@@ -0,0 +1,12 @@
import java.lang.AutoCloseable
public class Foo {
void m() {
getStream().twr<caret>
}
AutoCloseable getStream()
{
return null;
}
}
@@ -0,0 +1,12 @@
import java.lang.AutoCloseable
public class Foo {
void m() {
getStream().twr<caret>
}
Object getStream()
{
return null;
}
}
@@ -0,0 +1,12 @@
import java.lang.AutoCloseable
public class Foo {
void m() {
getStream().twr <caret>
}
Object getStream()
{
return null;
}
}
@@ -0,0 +1,17 @@
import java.lang.AutoCloseable
public class Foo {
void m() {
getStream().twr<caret>
}
AutoCloseable getStream()
{
return null;
}
private class Exception extends java.lang.Exception
{
}
}
@@ -0,0 +1,20 @@
import java.lang.AutoCloseable
public class Foo {
void m() {
try (AutoCloseable stream = getStream()) {
<caret>
} catch (java.lang.Exception e) {
}
}
AutoCloseable getStream()
{
return null;
}
private class Exception extends java.lang.Exception
{
}
}
@@ -0,0 +1,23 @@
import java.lang.AutoCloseable
import java.lang.Exception;
public class Foo {
void m() {
getStream().twr<caret>
}
MyStream getStream()
{
return null;
}
private class MyStream implements AutoCloseable
{
public void close() throws MyException {}
}
private class MyException extends Exception
{
}
}
@@ -0,0 +1,26 @@
import java.lang.AutoCloseable
import java.lang.Exception;
public class Foo {
void m() {
try (MyStream stream = getStream()) {
<caret>
} catch (MyException e) {
}
}
MyStream getStream()
{
return null;
}
private class MyStream implements AutoCloseable
{
public void close() throws MyException {}
}
private class MyException extends Exception
{
}
}
@@ -0,0 +1,15 @@
import java.lang.AutoCloseable
public class Foo {
void m() {
try (AutoCloseable stream = getStream()) {
<caret>
} catch (Exception e) {
}
}
AutoCloseable getStream()
{
return null;
}
}
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2014 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.template.postfix.templates;
import com.intellij.JavaTestUtil;
@@ -37,5 +52,7 @@ abstract public class PostfixTemplateTestCase extends LightCodeInsightFixtureTes
myFixture.addClass("package java.util;\n" +
"public class ArrayList<E> extends AbstractList<E>\n" +
" implements List<E>, Iterable<E>, RandomAccess, Cloneable, java.io.Serializable {}");
myFixture.addClass("package java.lang;\n" +
"public interface AutoCloseable {}");
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2000-2014 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.template.postfix.templates;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import org.jetbrains.annotations.NotNull;
public class TryWithResourcesPostfixTemplateTest extends PostfixTemplateTestCase {
@NotNull
@Override
protected String getSuffix() {
return "twr";
}
@Override
protected void setUp() throws Exception {
super.setUp();
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
}
public void testSimple() {
doTest();
}
public void testSimpleWithMyException() {
doTest();
}
public void testSimpleWithConflict() {
doTest();
}
public void testSimpleNotAutoCloseable() {
doTest();
}
}
@@ -26,6 +26,7 @@
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.SoutPostfixTemplate"/>
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.FormatPostfixTemplate"/>
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.TryStatementPostfixTemplate"/>
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.TryWithResourcesPostfixTemplate"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">