AnnotateCapitalizationIntention

This commit is contained in:
Dmitry Avdeev
2015-01-21 15:13:45 +03:00
parent 5918a2bd4f
commit fd3a79474c
16 changed files with 166 additions and 16 deletions
@@ -23,17 +23,18 @@ import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class AddAnnotationFix extends AddAnnotationPsiFix implements IntentionAction {
public AddAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner modifierListOwner, @NotNull String... annotationsToRemove) {
public AddAnnotationFix(@NotNull String fqn, @Nullable PsiModifierListOwner modifierListOwner, @NotNull String... annotationsToRemove) {
this(fqn, modifierListOwner, PsiNameValuePair.EMPTY_ARRAY, annotationsToRemove);
}
public AddAnnotationFix(@NotNull String fqn,
@NotNull PsiModifierListOwner modifierListOwner,
@Nullable PsiModifierListOwner modifierListOwner,
@NotNull PsiNameValuePair[] values,
@NotNull String... annotationsToRemove) {
super(fqn, modifierListOwner, values, annotationsToRemove);
@@ -37,10 +37,10 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
protected final String myAnnotation;
protected final String[] myAnnotationsToRemove;
protected final PsiNameValuePair[] myPairs; // not used when registering local quick fix
protected final String myText;
protected String myText;
public AddAnnotationPsiFix(@NotNull String fqn,
@NotNull PsiModifierListOwner modifierListOwner,
@Nullable PsiModifierListOwner modifierListOwner,
@NotNull PsiNameValuePair[] values,
@NotNull String... annotationsToRemove) {
super(modifierListOwner);
@@ -117,26 +117,29 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement;
final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
invoke(project, file, (PsiModifierListOwner)startElement, myPairs);
}
protected void invoke(@NotNull Project project, @NotNull PsiFile file, PsiModifierListOwner myModifierListOwner, PsiNameValuePair[] pairs) {
final PsiModifierList modifierList = myModifierListOwner.getModifierList();
LOG.assertTrue(modifierList != null);
if (modifierList.findAnnotation(myAnnotation) != null) return;
final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner);
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return;
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) {
for (String fqn : myAnnotationsToRemove) {
annotationsManager.deannotate(myModifierListOwner, fqn);
}
annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs);
annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, pairs);
}
else {
final PsiFile containingFile = myModifierListOwner.getContainingFile();
if (!FileModificationService.getInstance().preparePsiElementForWrite(containingFile)) return;
removePhysicalAnnotations(myModifierListOwner, myAnnotationsToRemove);
PsiAnnotation inserted = addPhysicalAnnotation(myAnnotation, myPairs, modifierList);
PsiAnnotation inserted = addPhysicalAnnotation(myAnnotation, pairs, modifierList);
JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted);
if (containingFile != file) {
UndoUtil.markPsiFileForUndo(file);
@@ -257,10 +257,6 @@ class Foo {
assert 'Bar' in myFixture.lookupElementStrings
}
private Editor getEditor() {
return myFixture.getEditor();
}
private void checkResult() {
checkResultByFile(getTestName(false) + "-out.java");
}
@@ -16,6 +16,7 @@
package com.intellij.testFramework.fixtures;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -154,6 +155,8 @@ public abstract class LightCodeInsightFixtureTestCase extends UsefulTestCase{
protected PsiFile getFile() { return myFixture.getFile(); }
protected Editor getEditor() { return myFixture.getEditor(); }
protected PsiManager getPsiManager() {
return PsiManager.getInstance(getProject());
}
@@ -22,13 +22,14 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class LocalQuickFixOnPsiElement implements LocalQuickFix {
protected static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.LocalQuickFixAndIntentionAction");
protected final SmartPsiElementPointer<PsiElement> myStartElement;
protected final SmartPsiElementPointer<PsiElement> myEndElement;
protected LocalQuickFixOnPsiElement(@NotNull PsiElement element) {
protected LocalQuickFixOnPsiElement(@Nullable PsiElement element) {
this(element, element);
}
@@ -32,7 +32,7 @@ public class BaseListPopupStep<T> extends BaseStep<T> implements ListPopupStep<T
private List<Icon> myIcons;
private int myDefaultOptionIndex = -1;
public BaseListPopupStep(@Nullable String title, T[] values) {
public BaseListPopupStep(@Nullable String title, T... values) {
this(title, values, new Icon[]{});
}
@@ -19,6 +19,8 @@ import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeEventQueue;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
@@ -579,4 +581,13 @@ public class ListPopupImpl extends WizardPopup implements ListPopup {
return true;
}
@Override
public void showInBestPositionFor(@NotNull Editor editor) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
handleSelect(true);
}
else {
super.showInBestPositionFor(editor);
}
}
}
@@ -75,7 +75,10 @@ public class CodeInsightTestUtil {
@TestOnly
public static void doIntentionTest(CodeInsightTestFixture fixture, @NonNls String file, @NonNls String actionText) {
doIntentionTest(fixture, actionText, file + ".xml", file + "_after.xml");
String extension = FileUtilRt.getExtension(file);
file = FileUtil.getNameWithoutExtension(file);
if (extension.isEmpty()) extension = "xml";
doIntentionTest(fixture, actionText, file + "." + extension, file + "_after." + extension);
}
@TestOnly
@@ -136,6 +136,11 @@
groupKey="inspections.group.name" enabledByDefault="true" level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.internal.UnsafeReturnStatementVisitorInspection" />
<intentionAction>
<className>org.jetbrains.idea.devkit.inspections.AnnotateCapitalizationIntention</className>
<category>I18N</category>
</intentionAction>
<moduleConfigurationEditorProvider implementation="org.jetbrains.idea.devkit.module.PluginModuleEditorsProvider"/>
<implicitUsageProvider implementation="org.jetbrains.idea.devkit.inspections.DevKitImplicitUsageProvider"/>
<psi.referenceContributor implementation="org.jetbrains.idea.devkit.dom.impl.I18nReferenceContributor"/>
@@ -0,0 +1,2 @@
void setTitle(@Nls(capitalization = Nls.Capitalization.Title) String title) {
}
@@ -0,0 +1,2 @@
void setTitle(String title) {
}
@@ -0,0 +1,5 @@
<html>
<body>
Annotate with capitalization type.
</body>
</html>
@@ -0,0 +1,99 @@
/*
* Copyright 2000-2015 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.idea.devkit.inspections;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Avdeev
*/
public class AnnotateCapitalizationIntention extends AddAnnotationFix {
public AnnotateCapitalizationIntention() {
super(Nls.class.getName(), null);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
PsiModifierListOwner element = getElement(editor, file);
if (element == null ||
(!ApplicationManager.getApplication().isUnitTestMode() && element.getManager().isInProject(element)) ||
AnnotationUtil.findAnnotation(element, Nls.class.getName()) != null) return false;
myText = "Annotate capitalization type";
return true;
}
@NotNull
@Override
public String getFamilyName() {
return "Annotate capitalization type";
}
@Override
public void invoke(@NotNull final Project project, Editor editor, final PsiFile file) throws IncorrectOperationException {
final PsiModifierListOwner modifierListOwner = getElement(editor, file);
if (modifierListOwner == null) throw new IncorrectOperationException();
BaseListPopupStep<Nls.Capitalization> step =
new BaseListPopupStep<Nls.Capitalization>(null, Nls.Capitalization.Title, Nls.Capitalization.Sentence) {
@Override
public PopupStep onChosen(final Nls.Capitalization selectedValue, boolean finalChoice) {
new WriteCommandAction.Simple(project) {
@Override
protected void run() throws Throwable {
String nls = Nls.class.getName();
PsiAnnotation annotation = JavaPsiFacade.getInstance(project).getElementFactory()
.createAnnotationFromText("@" + nls + "(capitalization = " +
nls + ".Capitalization." + selectedValue.toString() + ")", modifierListOwner);
invoke(project, file, modifierListOwner, annotation.getParameterList().getAttributes());
}
}.execute();
return FINAL_CHOICE;
}
};
JBPopupFactory.getInstance().createListPopup(step).showInBestPositionFor(editor);
}
@Override
public boolean startInWriteAction() {
return false;
}
@Nullable
private static PsiModifierListOwner getElement(Editor editor, PsiFile file) {
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
if (parameter == null) return null;
PsiMethod method = PsiTreeUtil.getParentOfType(parameter, PsiMethod.class);
if (method == null) return null;
PsiType type = parameter.getType();
return type.equalsToText(CommonClassNames.JAVA_LANG_STRING) ? parameter : null;
}
}
@@ -0,0 +1,4 @@
class Intention {
void setTitle(String ti<caret>tle) {
}
}
@@ -0,0 +1,6 @@
import org.jetbrains.annotations.Nls;
class Intention {
void setTitle(@Nls(capitalization = Nls.Capitalization.Title) String title) {
}
}
@@ -46,7 +46,16 @@ public class CapitalizationInspectionTest extends LightCodeInsightFixtureTestCas
assertEmpty(myFixture.filterAvailableIntentions("Properly capitalize"));
}
public void doTest(boolean fix) {
public void testIntention() throws Exception {
myFixture.configureByFile("Intention.java");
AnnotateCapitalizationIntention intention = new AnnotateCapitalizationIntention();
assertTrue(intention.isAvailable(getProject(), getEditor(), getFile()));
intention.invoke(getProject(), getEditor(), getFile());
myFixture.checkResultByFile("Intention_after.java");
assertFalse(intention.isAvailable(getProject(), getEditor(), getFile()));
}
private void doTest(boolean fix) {
myFixture.testHighlighting(getTestName(false) + ".java");
if (!fix) return;