diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java
index f06162932d0e..01d6988cb998 100644
--- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java
+++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddOnDemandStaticImportAction.java
@@ -31,6 +31,7 @@ import com.intellij.util.IncorrectOperationException;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* @author ven
@@ -43,41 +44,63 @@ public class AddOnDemandStaticImportAction extends PsiElementBaseIntentionAction
return CodeInsightBundle.message("intention.add.on.demand.static.import.family");
}
- public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
- if (!PsiUtil.isLanguageLevel5OrHigher(element)) return false;
+ /**
+ * Allows to check if static import may be performed for the given element.
+ *
+ * @param element element to check
+ * @return target class that may be statically imported if any; null otherwise
+ */
+ @Nullable
+ public static PsiClass getClassToPerformStaticImport(@NotNull PsiElement element) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(element)) return null;
if (!(element instanceof PsiIdentifier) || !(element.getParent() instanceof PsiReferenceExpression)) {
- return false;
+ return null;
}
PsiReferenceExpression refExpr = (PsiReferenceExpression)element.getParent();
if (refExpr.getParent() instanceof PsiReferenceExpression &&
- isParameterizedReference((PsiReferenceExpression)refExpr.getParent())) return false;
+ isParameterizedReference((PsiReferenceExpression)refExpr.getParent())) return null;
PsiElement resolved = refExpr.resolve();
if (!(resolved instanceof PsiClass)) {
- return false;
+ return null;
}
PsiClass psiClass = (PsiClass)resolved;
PsiFile file = refExpr.getContainingFile();
- if (!(file instanceof PsiJavaFile)) return false;
+ if (!(file instanceof PsiJavaFile)) return null;
PsiImportList importList = ((PsiJavaFile)file).getImportList();
- if (importList == null) return false;
+ if (importList == null) return null;
for (PsiImportStaticStatement statement : importList.getImportStaticStatements()) {
PsiClass staticResolve = statement.resolveTargetClass();
- if (psiClass == staticResolve) return false; //already imported
+ if (psiClass == staticResolve) return null; //already imported
}
- String text = CodeInsightBundle.message("intention.add.on.demand.static.import.text", psiClass.getQualifiedName());
- setText(text);
- return true;
+
+ return psiClass;
+ }
+
+ public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
+ PsiClass classToImport = getClassToPerformStaticImport(element);
+ if (classToImport != null) {
+ String text = CodeInsightBundle.message("intention.add.on.demand.static.import.text", classToImport.getQualifiedName());
+ setText(text);
+ }
+ return classToImport != null;
}
- public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
+ public static void invoke(final Project project, PsiFile file, final Editor editor, PsiElement element) {
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
- PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
+
final PsiReferenceExpression refExpr = (PsiReferenceExpression)element.getParent();
final PsiClass aClass = (PsiClass)refExpr.resolve();
+ if (aClass == null) {
+ return;
+ }
PsiImportStaticStatement importStaticStatement =
JavaPsiFacade.getInstance(file.getProject()).getElementFactory().createImportStaticStatement(aClass, "*");
- ((PsiJavaFile)file).getImportList().add(importStaticStatement);
+ PsiImportList importList = ((PsiJavaFile)file).getImportList();
+ if (importList == null) {
+ return;
+ }
+ importList.add(importStaticStatement);
PsiFile[] roots = file.getPsiRoots();
for (final PsiFile root : roots) {
@@ -113,6 +136,9 @@ public class AddOnDemandStaticImportAction extends PsiElementBaseIntentionAction
expressionToDequalifyOffsets.forEachDescending(new TIntProcedure() {
public boolean execute(int offset) {
PsiReferenceExpression expression = PsiTreeUtil.findElementOfClassAtOffset(root, offset, PsiReferenceExpression.class, false);
+ if (expression == null) {
+ return false;
+ }
PsiExpression qualifierExpression = expression.getQualifierExpression();
if (qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).isReferenceTo(aClass)) {
qualifierExpression.delete();
@@ -127,8 +153,17 @@ public class AddOnDemandStaticImportAction extends PsiElementBaseIntentionAction
});
}
}
+
+ public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
+ PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
+ invoke(project, file, editor, element);
+ }
private static boolean isParameterizedReference(final PsiReferenceExpression expression) {
- return expression.getParameterList() != null && expression.getParameterList().getFirstChild() != null;
+ if (expression.getParameterList() == null) {
+ return false;
+ }
+ PsiReferenceParameterList parameterList = expression.getParameterList();
+ return parameterList != null && parameterList.getFirstChild() != null;
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddSingleMemberStaticImportAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddSingleMemberStaticImportAction.java
index 74c8049add86..a76233a34c64 100644
--- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddSingleMemberStaticImportAction.java
+++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddSingleMemberStaticImportAction.java
@@ -32,6 +32,7 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAction {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.AddSingleMemberStaticImportAction");
@@ -42,26 +43,32 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
return CodeInsightBundle.message("intention.add.single.member.static.import.family");
}
- public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
- if (!PsiUtil.isLanguageLevel5OrHigher(element)) return false;
+ /**
+ * Allows to check if it's possible to perform static import for the target element.
+ *
+ * @param element target element that is static import candidate
+ * @return not-null qualified name of the class which method may be statically imported if any; null otherwise
+ */
+ @Nullable
+ public static String getStaticImportClass(@NotNull PsiElement element) {
+ if (!PsiUtil.isLanguageLevel5OrHigher(element)) return null;
PsiFile file = element.getContainingFile();
if (element instanceof PsiIdentifier && element.getParent() instanceof PsiReferenceExpression &&
((PsiReferenceExpression)element.getParent()).getQualifierExpression() != null) {
PsiReferenceExpression refExpr = (PsiReferenceExpression)element.getParent();
- if (refExpr.getParameterList() != null &&
- refExpr.getParameterList().getFirstChild() != null) return false;
+ PsiReferenceParameterList parameterList = refExpr.getParameterList();
+ if (parameterList != null && parameterList.getFirstChild() != null) return null;
PsiElement resolved = refExpr.resolve();
- if (resolved instanceof PsiMember &&
- ((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) {
+ if (resolved instanceof PsiMember && ((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) {
PsiClass aClass = ((PsiMember)resolved).getContainingClass();
if (aClass != null && !PsiTreeUtil.isAncestor(aClass, element, true)) {
String qName = aClass.getQualifiedName();
if (qName != null) {
qName = qName + "." +refExpr.getReferenceName();
if (file instanceof PsiJavaFile) {
- if (((PsiJavaFile)file).getImportList().findSingleImportStatement(refExpr.getReferenceName()) == null) {
- setText(CodeInsightBundle.message("intention.add.single.member.static.import.text", qName));
- return true;
+ PsiImportList importList = ((PsiJavaFile)file).getImportList();
+ if (importList != null && importList.findSingleImportStatement(refExpr.getReferenceName()) == null) {
+ return qName;
}
}
}
@@ -69,20 +76,28 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
}
}
- return false;
+ return null;
+ }
+
+ public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
+ String classQName = getStaticImportClass(element);
+ if (classQName != null) {
+ setText(CodeInsightBundle.message("intention.add.single.member.static.import.text", classQName));
+ }
+ return classQName != null;
}
-
- public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
+ public static void invoke(PsiFile file, PsiElement element) {
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
- PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
+
final PsiReferenceExpression refExpr = (PsiReferenceExpression)element.getParent();
final PsiElement resolved = refExpr.resolve();
file.accept(new JavaRecursiveElementWalkingVisitor() {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
- if (refExpr.getReferenceName().equals(expression.getReferenceName())) {
+ String referenceName = refExpr.getReferenceName();
+ if (referenceName != null && referenceName.equals(expression.getReferenceName())) {
PsiElement resolved = expression.resolve();
if (resolved != null) {
expression.putUserData(TEMP_REFERENT_USER_DATA, resolved);
@@ -91,7 +106,11 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
}
});
- RefactoringUtil.bindToElementViaStaticImport(((PsiMember)resolved).getContainingClass(), ((PsiNamedElement)resolved).getName(), ((PsiJavaFile)file).getImportList());
+ if (resolved != null) {
+ RefactoringUtil.bindToElementViaStaticImport(
+ ((PsiMember)resolved).getContainingClass(), ((PsiNamedElement)resolved).getName(), ((PsiJavaFile)file).getImportList()
+ );
+ }
file.accept(new JavaRecursiveElementVisitor() {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
@@ -133,5 +152,11 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
super.visitReferenceExpression(expression);
}
});
+
+ }
+
+ public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
+ PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
+ invoke(file, element);
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java b/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java
new file mode 100644
index 000000000000..20050e3b1c01
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/template/impl/ShortenToStaticImportProcessor.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2011 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.impl;
+
+import com.intellij.codeInsight.CodeInsightBundle;
+import com.intellij.codeInsight.intention.impl.AddOnDemandStaticImportAction;
+import com.intellij.codeInsight.intention.impl.AddSingleMemberStaticImportAction;
+import com.intellij.codeInsight.template.Template;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.RangeMarker;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiUtilBase;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+
+/**
+ * @author Denis Zhdanov
+ * @since 4/27/11 3:07 PM
+ */
+public class ShortenToStaticImportProcessor implements TemplateOptionalProcessor {
+
+ private static final List IMPORTERS = asList(new SingleMemberStaticImporter(), new OnDemandStaticImporter());
+
+ @Override
+ public void processText(Project project, Template template, Document document, RangeMarker templateRange, Editor editor) {
+ if (!template.getValue(Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE)) {
+ return;
+ }
+
+ PsiDocumentManager.getInstance(project).commitDocument(document);
+ final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, project);
+ if (file == null) {
+ return;
+ }
+
+ List> staticImportTargets = new ArrayList>();
+ for (
+ PsiElement element = PsiUtilBase.getElementAtOffset(file, templateRange.getStartOffset());
+ element != null && element.getTextRange().getStartOffset() < templateRange.getEndOffset();
+ element = getNext(element))
+ {
+ for (StaticImporter importer : IMPORTERS) {
+ if (importer.canPerform(element)) {
+ staticImportTargets.add(new Pair(element, importer));
+ break;
+ }
+ }
+ }
+
+ for (Pair pair : staticImportTargets) {
+ if (pair.first.isValid()) {
+ pair.second.perform(project, file, editor, pair.first);
+ }
+ }
+ }
+
+ @Nullable
+ private static PsiElement getNext(@NotNull PsiElement element) {
+ PsiElement result = element.getNextSibling();
+ for (PsiElement current = element; current != null && result == null; current = current.getParent()) {
+ result = current.getNextSibling();
+ }
+ return result;
+ }
+
+ @Nls
+ @Override
+ public String getOptionName() {
+ return CodeInsightBundle.message("dialog.edit.template.checkbox.use.static.import");
+ }
+
+ @Override
+ public boolean isEnabled(Template template) {
+ return template.getValue(Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE);
+ }
+
+ @Override
+ public void setEnabled(Template template, boolean value) {
+ template.setValue(Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE, value);
+ }
+
+ @Override
+ public boolean isVisible(Template template) {
+ return true;
+ }
+
+ private interface StaticImporter {
+ boolean canPerform(@NotNull PsiElement element);
+ void perform(Project project, PsiFile file, Editor editor, PsiElement element);
+ }
+
+ private static class SingleMemberStaticImporter implements StaticImporter {
+ @Override
+ public boolean canPerform(@NotNull PsiElement element) {
+ return AddSingleMemberStaticImportAction.getStaticImportClass(element) != null;
+ }
+
+ @Override
+ public void perform(Project project, PsiFile file, Editor editor, PsiElement element) {
+ AddSingleMemberStaticImportAction.invoke(file, element);
+ }
+ }
+
+ private static class OnDemandStaticImporter implements StaticImporter {
+ @Override
+ public boolean canPerform(@NotNull PsiElement element) {
+ return AddOnDemandStaticImportAction.getClassToPerformStaticImport(element) != null;
+ }
+
+ @Override
+ public void perform(Project project, PsiFile file, Editor editor, PsiElement element) {
+ AddOnDemandStaticImportAction.invoke(project, file, editor, element);
+ }
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java b/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java
index 43dba460aa10..9b61f20fabe3 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/Template.java
@@ -21,7 +21,21 @@ import com.intellij.openapi.editor.RangeMarker;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import java.util.EnumMap;
+import java.util.Map;
+
public abstract class Template {
+
+ public enum Property {
+ USE_STATIC_IMPORT_IF_POSSIBLE
+ }
+ private static final Map DEFAULT_PROPERTIES = new EnumMap(Property.class);
+ static {
+ DEFAULT_PROPERTIES.put(Property.USE_STATIC_IMPORT_IF_POSSIBLE, false);
+ }
+
+ private final Map myProperties = new EnumMap(Property.class);
+
public abstract void addTextSegment(@NotNull String text);
public abstract void addVariableSegment(@NonNls String name);
@@ -66,4 +80,18 @@ public abstract class Template {
public abstract boolean isToShortenLongNames();
public abstract void setToShortenLongNames(boolean toShortenLongNames);
+
+ public boolean getValue(@NotNull Property key) {
+ Boolean result = myProperties.get(key);
+ return result == null ? getDefaultValue(key) : result;
+ }
+
+ public void setValue(@NotNull Property key, boolean value) {
+ myProperties.put(key, value);
+ }
+
+ public static boolean getDefaultValue(@NotNull Property key) {
+ Boolean result = DEFAULT_PROPERTIES.get(key);
+ return result == null ? false : result;
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java
index ce7303c93d7d..91a516fea300 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java
@@ -27,6 +27,7 @@ import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import javax.xml.bind.annotation.XmlElement;
import java.util.*;
/**
@@ -183,6 +184,12 @@ public class TemplateImpl extends Template implements SchemeElement {
template.myIsInline = myIsInline;
template.myTemplateContext = myTemplateContext.createCopy();
template.isDeactivated = isDeactivated;
+ for (Property property : Property.values()) {
+ boolean value = getValue(property);
+ if (value != Template.getDefaultValue(property)) {
+ template.setValue(property, value);
+ }
+ }
for (Variable variable : myVariables) {
template.addVariable(variable.getName(), variable.getExpressionString(), variable.getDefaultValueString(), variable.isAlwaysStopAt());
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java
index 7e7d2c7dbda4..a5b40e8b27f5 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java
@@ -86,6 +86,7 @@ public class TemplateSettings implements PersistentStateComponent, Expo
private static final @NonNls String CONTEXT = "context";
private static final @NonNls String TO_REFORMAT = "toReformat";
private static final @NonNls String TO_SHORTEN_FQ_NAMES = "toShortenFQNames";
+ private static final @NonNls String USE_STATIC_IMPORT = "useStaticImport";
private static final @NonNls String DEFAULT_SHORTCUT = "defaultShortcut";
private static final @NonNls String DEACTIVATED = "deactivated";
@@ -589,6 +590,10 @@ public class TemplateSettings implements PersistentStateComponent, Expo
template.setToShortenLongNames(Boolean.parseBoolean(element.getAttributeValue(TO_SHORTEN_FQ_NAMES)));
template.setDeactivated(Boolean.parseBoolean(element.getAttributeValue(DEACTIVATED)));
+ String useStaticImport = element.getAttributeValue(USE_STATIC_IMPORT);
+ if (useStaticImport != null) {
+ template.setValue(TemplateImpl.Property.USE_STATIC_IMPORT_IF_POSSIBLE, Boolean.parseBoolean(useStaticImport));
+ }
for (final Object o : element.getChildren(VARIABLE)) {
Element e = (Element)o;
@@ -627,6 +632,11 @@ public class TemplateSettings implements PersistentStateComponent, Expo
}
element.setAttribute(TO_REFORMAT, Boolean.toString(template.isToReformat()));
element.setAttribute(TO_SHORTEN_FQ_NAMES, Boolean.toString(template.isToShortenLongNames()));
+ if (template.getValue(Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE)
+ != Template.getDefaultValue(Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE))
+ {
+ element.setAttribute(USE_STATIC_IMPORT, Boolean.toString(template.getValue(Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE)));
+ }
if (template.isDeactivated()) {
element.setAttribute(DEACTIVATED, Boolean.toString(true));
}
diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties
index 80b26d17b51e..ba4040d332c1 100644
--- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties
+++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties
@@ -295,6 +295,7 @@ dialog.edit.template.options.title=Options
dialog.edit.template.label.expand.with=Expand with
dialog.edit.template.checkbox.reformat.according.to.style=&Reformat according to style
dialog.edit.template.checkbox.shorten.fq.names=Shorten &FQ names
+dialog.edit.template.checkbox.use.static.import=Use static import if possible
dialog.edit.template.context.title=Context
dialog.edit.template.checkbox.java.code=&Java code
dialog.edit.template.checkbox.html=&HTML
diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml
index 58ab2328b8f3..391f7863f211 100644
--- a/resources/src/META-INF/IdeaPlugin.xml
+++ b/resources/src/META-INF/IdeaPlugin.xml
@@ -947,6 +947,7 @@
+