mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-13 15:52:01 +07:00
Capitalization annotation support
This commit is contained in:
Binary file not shown.
@@ -30,4 +30,15 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE, ElementType.PACKAGE})
|
||||
public @interface Nls {
|
||||
|
||||
enum Capitalization {
|
||||
|
||||
NotSpecified,
|
||||
/** e.g. This Is a Title */
|
||||
Title,
|
||||
/** e.g. This is a sentence */
|
||||
Sentence
|
||||
}
|
||||
|
||||
Capitalization capitalization() default Capitalization.NotSpecified;
|
||||
}
|
||||
|
||||
@@ -423,24 +423,30 @@ public class StringUtil extends StringUtilRt {
|
||||
@NotNull
|
||||
@Contract(pure = true)
|
||||
public static String wordsToBeginFromUpperCase(@NotNull String s) {
|
||||
return toTitleCase(s, ourPrepositions);
|
||||
return fixCapitalization(s, ourPrepositions, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract(pure = true)
|
||||
public static String wordsToBeginFromLowerCase(@NotNull String s) {
|
||||
return fixCapitalization(s, ourPrepositions, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract(pure = true)
|
||||
public static String toTitleCase(@NotNull String s) {
|
||||
return toTitleCase(s, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
return fixCapitalization(s, ArrayUtil.EMPTY_STRING_ARRAY, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String toTitleCase(@NotNull String s, @NotNull String[] prepositions) {
|
||||
private static String fixCapitalization(@NotNull String s, @NotNull String[] prepositions, boolean title) {
|
||||
StringBuilder buffer = null;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char prevChar = i == 0 ? ' ' : s.charAt(i - 1);
|
||||
char currChar = s.charAt(i);
|
||||
if (!Character.isLetterOrDigit(prevChar) && prevChar != '\'') {
|
||||
if (Character.isLetterOrDigit(currChar)) {
|
||||
if (!Character.isUpperCase(currChar)) {
|
||||
if (title || Character.isUpperCase(currChar)) {
|
||||
int j = i;
|
||||
for (; j < s.length(); j++) {
|
||||
if (!Character.isLetterOrDigit(s.charAt(j))) {
|
||||
@@ -451,7 +457,7 @@ public class StringUtil extends StringUtilRt {
|
||||
if (buffer == null) {
|
||||
buffer = new StringBuilder(s);
|
||||
}
|
||||
buffer.setCharAt(i, toUpperCase(currChar));
|
||||
buffer.setCharAt(i, title ? toUpperCase(currChar) : toLowerCase(currChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,10 @@ public class StringUtilTest extends TestCase {
|
||||
assertEquals("Couldn't Connect to Debugger", StringUtil.wordsToBeginFromUpperCase("Couldn't connect to debugger"));
|
||||
}
|
||||
|
||||
public void testSentenceCapitalization() {
|
||||
assertEquals("couldn't connect to debugger", StringUtil.wordsToBeginFromLowerCase("Couldn't Connect to Debugger"));
|
||||
}
|
||||
|
||||
public void testEscapeStringCharacters() {
|
||||
assertEquals("\\\"\\n", StringUtil.escapeStringCharacters(3, "\\\"\n", "\"", false, new StringBuilder()).toString());
|
||||
assertEquals("\\\"\\n", StringUtil.escapeStringCharacters(2, "\"\n", "\"", false, new StringBuilder()).toString());
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.idea.devkit.inspections;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.lang.properties.psi.Property;
|
||||
import com.intellij.lang.properties.references.PropertyReference;
|
||||
@@ -28,12 +29,15 @@ import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PropertyUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -67,6 +71,19 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
PsiType type = method.getReturnType();
|
||||
if (!(type instanceof PsiClassType) || !"String".equals(((PsiClassType)type).getClassName())) return;
|
||||
PsiReturnStatement returnStatement = PsiTreeUtil.findChildOfType(method, PsiReturnStatement.class);
|
||||
if (returnStatement == null) return;
|
||||
PsiExpression expression = returnStatement.getReturnValue();
|
||||
String value = getTitleValue(expression);
|
||||
if (value == null) return;
|
||||
Nls.Capitalization capitalization = getCapitalizationFromAnno(method);
|
||||
checkCapitalization(expression, holder, capitalization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
@@ -78,11 +95,7 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
if (args.length == 0) {
|
||||
return;
|
||||
}
|
||||
String titleValue = getTitleValue(args [0]);
|
||||
if (!hasTitleCapitalization(titleValue)) {
|
||||
holder.registerProblem(args [0], "Dialog title '" + titleValue + "' is not properly capitalized. It should have title capitalization",
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new TitleCapitalizationFix(titleValue));
|
||||
}
|
||||
checkCapitalization(args[0], holder, Nls.Capitalization.Title);
|
||||
}
|
||||
else if (calledName.startsWith("show") && (calledName.endsWith("Dialog") || calledName.endsWith("Message"))) {
|
||||
if (!isMethodOfClass(expression, Messages.class.getName())) return;
|
||||
@@ -93,11 +106,7 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) {
|
||||
PsiParameter parameter = parameters[i];
|
||||
if ("title".equals(parameter.getName()) && i < args.length) {
|
||||
String titleValue = getTitleValue(args [i]);
|
||||
if (!hasTitleCapitalization(titleValue)) {
|
||||
holder.registerProblem(args [i], "Message title '" + titleValue + "' is not properly capitalized. It should have title capitalization",
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new TitleCapitalizationFix(titleValue));
|
||||
}
|
||||
checkCapitalization(args[i], holder, Nls.Capitalization.Title);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -106,6 +115,23 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
};
|
||||
}
|
||||
|
||||
public Nls.Capitalization getCapitalizationFromAnno(PsiMethod method) {
|
||||
PsiAnnotation nls = AnnotationUtil.findAnnotationInHierarchy(method, Collections.singleton(Nls.class.getName()));
|
||||
if (nls == null) return Nls.Capitalization.NotSpecified;
|
||||
PsiAnnotationMemberValue capitalization = nls.findAttributeValue("capitalization");
|
||||
Object cap = JavaPsiFacade.getInstance(method.getProject()).getConstantEvaluationHelper().computeConstantExpression(capitalization);
|
||||
return cap instanceof Nls.Capitalization ? (Nls.Capitalization)cap : Nls.Capitalization.NotSpecified;
|
||||
}
|
||||
|
||||
private static void checkCapitalization(PsiExpression element, @NotNull ProblemsHolder holder, Nls.Capitalization capitalization) {
|
||||
String titleValue = getTitleValue(element);
|
||||
if (!checkCapitalization(titleValue, capitalization)) {
|
||||
holder.registerProblem(element, "String '" + titleValue + "' is not properly capitalized. It should have " +
|
||||
StringUtil.toLowerCase(capitalization.toString()) + " capitalization",
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new TitleCapitalizationFix(titleValue, capitalization));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMethodOfClass(PsiMethodCallExpression expression, String... classNames) {
|
||||
PsiMethod psiMethod = expression.resolveMethod();
|
||||
if (psiMethod == null) {
|
||||
@@ -120,7 +146,7 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getTitleValue(PsiExpression arg) {
|
||||
private static String getTitleValue(@Nullable PsiExpression arg) {
|
||||
if (arg instanceof PsiLiteralExpression) {
|
||||
Object value = ((PsiLiteralExpression)arg).getValue();
|
||||
if (value instanceof String) {
|
||||
@@ -167,20 +193,35 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean hasTitleCapitalization(String value) {
|
||||
if (value == null) {
|
||||
private static boolean checkCapitalization(String value, Nls.Capitalization capitalization) {
|
||||
if (value == null || capitalization == Nls.Capitalization.NotSpecified) {
|
||||
return true;
|
||||
}
|
||||
value = value.replace("&", "");
|
||||
return StringUtil.wordsToBeginFromUpperCase(value).equals(value);
|
||||
return capitalization == Nls.Capitalization.Title
|
||||
? StringUtil.wordsToBeginFromUpperCase(value).equals(value)
|
||||
: checkSentenceCapitalization(value);
|
||||
}
|
||||
|
||||
private static boolean checkSentenceCapitalization(@NotNull String value) {
|
||||
String[] words = value.split(" ");
|
||||
if (words.length == 0) return true;
|
||||
if (!StringUtil.isCapitalized(words[0])) return false;
|
||||
for (int i = 1; i < words.length; i++) {
|
||||
String word = words[i];
|
||||
if (StringUtil.isCapitalized(word)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class TitleCapitalizationFix implements LocalQuickFix {
|
||||
|
||||
private final String myTitleValue;
|
||||
private final Nls.Capitalization myCapitalization;
|
||||
|
||||
public TitleCapitalizationFix(String titleValue) {
|
||||
public TitleCapitalizationFix(String titleValue, Nls.Capitalization capitalization) {
|
||||
myTitleValue = titleValue;
|
||||
myCapitalization = capitalization;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -217,10 +258,10 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
}
|
||||
final String string = (String)value;
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
final PsiExpression
|
||||
newExpression = factory.createExpressionFromText('"' + StringUtil.wordsToBeginFromUpperCase(string) + '"', element);
|
||||
final PsiExpression newExpression = factory.createExpressionFromText('"' + fixValue(string) + '"', element);
|
||||
literalExpression.replace(newExpression);
|
||||
}else if (element instanceof PsiMethodCallExpression) {
|
||||
}
|
||||
else if (element instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
|
||||
final PsiMethod method = methodCallExpression.resolveMethod();
|
||||
final PsiExpression returnValue = PropertyUtil.getGetterReturnExpression(method);
|
||||
@@ -235,9 +276,9 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
final String capitalizedString = StringUtil.wordsToBeginFromUpperCase(value);
|
||||
property.setValue(capitalizedString);
|
||||
} else if (element instanceof PsiReferenceExpression) {
|
||||
property.setValue(fixValue(value));
|
||||
}
|
||||
else if (element instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element;
|
||||
final PsiElement target = referenceExpression.resolve();
|
||||
if (!(target instanceof PsiVariable)) {
|
||||
@@ -250,6 +291,13 @@ public class TitleCapitalizationInspection extends BaseJavaLocalInspectionTool {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String fixValue(String string) {
|
||||
return myCapitalization == Nls.Capitalization.Title
|
||||
? StringUtil.wordsToBeginFromUpperCase(string)
|
||||
: StringUtil.capitalize(StringUtil.wordsToBeginFromLowerCase(string));
|
||||
}
|
||||
|
||||
protected static boolean isQuickFixOnReadOnlyFile(PsiElement problemElement) {
|
||||
final PsiFile containingPsiFile = problemElement.getContainingFile();
|
||||
if (containingPsiFile == null) {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import org.jetbrains.annotations.Nls;
|
||||
|
||||
class SentenceCapitalization {
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
public String getName1() {
|
||||
return <warning descr="String 'Foo Bar' is not properly capitalized. It should have sentence capitalization">"Foo B<caret>ar"</warning>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import org.jetbrains.annotations.Nls;
|
||||
|
||||
class SentenceCapitalization {
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
public String getName1() {
|
||||
return "Foo bar";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.jetbrains.annotations.Nls;
|
||||
|
||||
class TitleCapitalization {
|
||||
@Nls(capitalization = Nls.Capitalization.Title)
|
||||
public String getName() {
|
||||
return <warning descr="String 'Foo bar' is not properly capitalized. It should have title capitalization">"Foo b<caret>ar"</warning>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.jetbrains.annotations.Nls;
|
||||
|
||||
class TitleCapitalization {
|
||||
@Nls(capitalization = Nls.Capitalization.Title)
|
||||
public String getName() {
|
||||
return "Foo Bar";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 org.jetbrains.idea.devkit.inspections;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.application.PluginPathManager;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
public class CapitalizationInspectionTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
public void testTitleCapitalization() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSentenceCapitalization() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void doTest() {
|
||||
myFixture.testHighlighting(getTestName(false) + ".java");
|
||||
final IntentionAction action = myFixture.filterAvailableIntentions("Properly capitalize").get(0);
|
||||
new WriteCommandAction.Simple(getProject()) {
|
||||
@Override
|
||||
protected void run() throws Throwable {
|
||||
action.invoke(getProject(), myFixture.getEditor(), getFile());
|
||||
}
|
||||
}.execute();
|
||||
myFixture.checkResultByFile(getTestName(false) + "_after.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.addClass("package com.intellij.codeInspection; public class CommonProblemDescriptor {}");
|
||||
myFixture.addClass("package com.intellij.codeInspection; public class QuickFix {}");
|
||||
myFixture.enableInspections(TitleCapitalizationInspection.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return PluginPathManager.getPluginHomePathRelative("devkit") + "/testData/inspections/capitalization";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user