diff --git a/plugins/java-i18n/testData/findUsages/Conditional.java b/plugins/java-i18n/testData/findUsages/Conditional.java new file mode 100644 index 000000000000..0c43ae67cf31 --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/Conditional.java @@ -0,0 +1,7 @@ +class Test { + void m() { + String xxx = "qwe.asd.zxc"; + String yyy = 1 == 1 ? "qwe.asd.zxc" : ""; + String zzz = (1 == 1 ? "qwe.asd.zxc" : "") + "qwe"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/X.java b/plugins/java-i18n/testData/findUsages/X.java new file mode 100644 index 000000000000..f12c3d1d5ca4 --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/X.java @@ -0,0 +1,3 @@ +class X { + String f = "x.y"; +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/Y.java b/plugins/java-i18n/testData/findUsages/Y.java new file mode 100644 index 000000000000..bdc5dad943cc --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/Y.java @@ -0,0 +1,2 @@ +class Y { +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/conditional.properties b/plugins/java-i18n/testData/findUsages/conditional.properties new file mode 100644 index 000000000000..743617f72032 --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/conditional.properties @@ -0,0 +1 @@ +qwe.asd.zxc=1234567890 \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/fmt.tld b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/fmt.tld new file mode 100644 index 000000000000..d7e1aca9f169 --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/fmt.tld @@ -0,0 +1,442 @@ + + + + 1.0 + 1.2 + fmt + http://java.sun.com/jstl/fmt + JSTL fmt + JSTL 1.0 i18n-capable formatting library + + + + org.apache.taglibs.standard.tlv.JstlFmtTLV + + + expressionAttributes + + requestEncoding:value + setLocale:value + setLocale:variant + timeZone:value + setTimeZone:value + bundle:basename + bundle:prefix + setBundle:basename + message:key + message:bundle + param:value + formatNumber:value + formatNumber:pattern + formatNumber:currencyCode + formatNumber:currencySymbol + formatNumber:groupingUsed + formatNumber:maxIntegerDigits + formatNumber:minIntegerDigits + formatNumber:maxFractionDigits + formatNumber:minFractionDigits + parseNumber:value + parseNumber:pattern + parseNumber:parseLocale + parseNumber:integerOnly + formatDate:value + formatDate:pattern + formatDate:timeZone + parseDate:value + parseDate:pattern + parseDate:timeZone + parseDate:parseLocale + + + Whitespace-separated list of colon-separated token pairs + describing tag:attribute combinations that accept expressions. + The validator uses this information to determine which + attributes need their syntax validated. + + + + + + requestEncoding + org.apache.taglibs.standard.tag.el.fmt.RequestEncodingTag + empty + + Sets the request character encoding + + + value + false + false + + + + + setLocale + org.apache.taglibs.standard.tag.el.fmt.SetLocaleTag + empty + + Stores the given locale in the locale configuration variable + + + value + true + false + + + variant + false + false + + + scope + false + false + + + + + timeZone + org.apache.taglibs.standard.tag.el.fmt.TimeZoneTag + JSP + + Specifies the time zone for any time formatting or parsing actions + nested in its body + + + value + true + false + + + + + setTimeZone + org.apache.taglibs.standard.tag.el.fmt.SetTimeZoneTag + empty + + Stores the given time zone in the time zone configuration variable + + + value + true + false + + + var + false + false + + + scope + false + false + + + + + bundle + org.apache.taglibs.standard.tag.el.fmt.BundleTag + JSP + + Loads a resource bundle to be used by its tag body + + + basename + true + false + + + prefix + false + false + + + + + setBundle + org.apache.taglibs.standard.tag.el.fmt.SetBundleTag + empty + + Loads a resource bundle and stores it in the named scoped variable or + the bundle configuration variable + + + basename + true + false + + + var + false + false + + + scope + false + false + + + + + message + org.apache.taglibs.standard.tag.el.fmt.MessageTag + JSP + + Maps key to localized message and performs parametric replacement + + + key + false + false + + + bundle + false + false + + + var + false + false + + + scope + false + false + + + + + param + org.apache.taglibs.standard.tag.el.fmt.ParamTag + JSP + + Supplies an argument for parametric replacement to a containing + <message> tag + + + value + false + false + + + + + formatNumber + org.apache.taglibs.standard.tag.el.fmt.FormatNumberTag + JSP + + Formats a numeric value as a number, currency, or percentage + + + value + false + false + + + type + false + false + + + pattern + false + false + + + currencyCode + false + false + + + currencySymbol + false + false + + + groupingUsed + false + false + + + maxIntegerDigits + false + false + + + minIntegerDigits + false + false + + + maxFractionDigits + false + false + + + minFractionDigits + false + false + + + var + false + false + + + scope + false + false + + + + + parseNumber + org.apache.taglibs.standard.tag.el.fmt.ParseNumberTag + JSP + + Parses the string representation of a number, currency, or percentage + + + value + false + false + + + type + false + false + + + pattern + false + false + + + parseLocale + false + false + + + integerOnly + false + false + + + var + false + false + + + scope + false + false + + + + + formatDate + org.apache.taglibs.standard.tag.el.fmt.FormatDateTag + empty + + Formats a date and/or time using the supplied styles and pattern + + + value + true + false + + + type + false + false + + + dateStyle + false + false + + + timeStyle + false + false + + + pattern + false + false + + + timeZone + false + false + + + var + false + false + + + scope + false + false + + + + + parseDate + org.apache.taglibs.standard.tag.el.fmt.ParseDateTag + JSP + + Parses the string representation of a date and/or time + + + value + false + false + + + type + false + false + + + dateStyle + false + false + + + timeStyle + false + false + + + pattern + false + false + + + timeZone + false + false + + + parseLocale + false + false + + + var + false + false + + + scope + false + false + + + + diff --git a/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/test.jsp b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/test.jsp new file mode 100644 index 000000000000..fa24e41ca34a --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/test.jsp @@ -0,0 +1,4 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib uri="/tags/fmt" prefix="fmt" %> + + \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/web.xml b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/web.xml new file mode 100644 index 000000000000..aa3fd5003258 --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/WEB-INF/web.xml @@ -0,0 +1,11 @@ + + + + + + /tags/fmt + /WEB-INF/fmt.tld + + \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/prop-bug.iml b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/prop-bug.iml new file mode 100644 index 000000000000..b278b66c183b --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/prop-bug.iml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/prop-bug.ipr b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/prop-bug.ipr new file mode 100644 index 000000000000..69e646ae3fab --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/prop-bug.ipr @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/resources/some.properties b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/resources/some.properties new file mode 100644 index 000000000000..ed5291ffdefe --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/findUsagesFromJsp/resources/some.properties @@ -0,0 +1 @@ +find.this.property=Duplicate Results \ No newline at end of file diff --git a/plugins/java-i18n/testData/findUsages/xx.properties b/plugins/java-i18n/testData/findUsages/xx.properties new file mode 100644 index 000000000000..fb897208b088 --- /dev/null +++ b/plugins/java-i18n/testData/findUsages/xx.properties @@ -0,0 +1 @@ +x.y=Y \ No newline at end of file diff --git a/plugins/java-i18n/testData/highlighting/Duplicate.properties b/plugins/java-i18n/testData/highlighting/Duplicate.properties new file mode 100644 index 000000000000..212949ca4c91 --- /dev/null +++ b/plugins/java-i18n/testData/highlighting/Duplicate.properties @@ -0,0 +1,2 @@ +xxx=aaa +xxx=bbb diff --git a/plugins/java-i18n/testData/highlighting/InvalidEscape.properties b/plugins/java-i18n/testData/highlighting/InvalidEscape.properties new file mode 100644 index 000000000000..180cbcba6ae7 --- /dev/null +++ b/plugins/java-i18n/testData/highlighting/InvalidEscape.properties @@ -0,0 +1,5 @@ +\ a\ b\ =x\x +a\n\r\b2 = x\\\n\r v +spaceinthemiddle=a\ b +ii\dnnvalidkey +framingSpaces = \ xxx\ \ \ \ No newline at end of file diff --git a/plugins/java-i18n/testData/highlighting/Ok.properties b/plugins/java-i18n/testData/highlighting/Ok.properties new file mode 100644 index 000000000000..a887e108aa5b --- /dev/null +++ b/plugins/java-i18n/testData/highlighting/Ok.properties @@ -0,0 +1,3 @@ + +ddd=ss +eee=ff \ No newline at end of file diff --git a/plugins/java-i18n/testData/highlighting/Unused.properties b/plugins/java-i18n/testData/highlighting/Unused.properties new file mode 100644 index 000000000000..501822c7f561 --- /dev/null +++ b/plugins/java-i18n/testData/highlighting/Unused.properties @@ -0,0 +1,2 @@ +abcd.esadfdsaf=ddd +used.prop=xcxcd \ No newline at end of file diff --git a/plugins/java-i18n/testSrc/com/intellij/lang/properties/PropertiesFindUsagesTest.java b/plugins/java-i18n/testSrc/com/intellij/lang/properties/PropertiesFindUsagesTest.java new file mode 100644 index 000000000000..910052f8c929 --- /dev/null +++ b/plugins/java-i18n/testSrc/com/intellij/lang/properties/PropertiesFindUsagesTest.java @@ -0,0 +1,103 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.lang.properties; + +import com.intellij.codeInsight.CodeInsightTestCase; +import com.intellij.find.FindManager; +import com.intellij.find.findUsages.FindUsagesHandler; +import com.intellij.find.findUsages.FindUsagesManager; +import com.intellij.find.findUsages.FindUsagesOptions; +import com.intellij.find.findUsages.JavaClassFindUsagesOptions; +import com.intellij.find.impl.FindManagerImpl; +import com.intellij.ide.startup.impl.StartupManagerImpl; +import com.intellij.lang.findUsages.FindUsagesProvider; +import com.intellij.lang.findUsages.LanguageFindUsages; +import com.intellij.lang.properties.psi.Property; +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.startup.StartupManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.usageView.UsageInfo; +import com.intellij.util.CommonProcessors; +import com.intellij.util.Processor; + +/** + * @author Maxim.Mossienko + */ +public class PropertiesFindUsagesTest extends CodeInsightTestCase { + private static final String BASE_PATH = "testData/findUsages/"; + @Override + protected String getTestDataPath() { + return PluginPathManager.getPluginHomePath("java-i18n") + "/"; + } + + private void initProperties() { + ((StartupManagerImpl)StartupManager.getInstance(myProject)).runPostStartupActivities(); + } + public void testFindUsages() throws Exception { + configureByFile(BASE_PATH+"xx.properties", BASE_PATH); + initProperties(); + + PsiReference[] references = findReferences(); + assertEquals(1, references.length); + assertEquals("X.java", references[0].getElement().getContainingFile().getName()); + } + public void testFindUsagesInPropValue() throws Exception { + configureByFile(BASE_PATH+"Y.java", BASE_PATH); + initProperties(); + + UsageInfo[] usages = findUsages(); + assertEquals(1, usages.length); + PsiElement element = usages[0].getElement(); + assertEquals("xx.properties", element.getContainingFile().getName()); + } + + public void testFindUsagesInConditionalExpression() { + configureByFiles(BASE_PATH, BASE_PATH + "conditional.properties", BASE_PATH + "Conditional.java"); + initProperties(); + + PsiElement element = myFile.findElementAt(myEditor.getCaretModel().getOffset()); + Property prop = PsiTreeUtil.getNonStrictParentOfType(element, Property.class); + PsiReference[] usages = ReferencesSearch.search(prop).toArray(PsiReference.EMPTY_ARRAY); + assertEquals(2, usages.length); + } + + private static void processUsages(final PsiElement element, + final FindUsagesOptions options, + final Processor processor) { + FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(element.getProject())).getFindUsagesManager(); + FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, false); + assertNotNull(handler); + handler.processElementUsages(element, processor, options); + } + + private PsiReference[] findReferences() { + PsiNamedElement namedElement = getElementAtCaret(); + + GlobalSearchScope searchScope = GlobalSearchScope.allScope(myProject); + + return ReferencesSearch.search(namedElement, searchScope, false).toArray(PsiReference.EMPTY_ARRAY); + } + + private UsageInfo[] findUsages() { + PsiNamedElement namedElement = getElementAtCaret(); + JavaClassFindUsagesOptions options = new JavaClassFindUsagesOptions(getProject()); + options.isFieldsUsages=true; + options.isMethodsUsages=true; + options.isUsages=true; + CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor<>(); + processUsages(namedElement, options, processor); + return processor.toArray(UsageInfo.EMPTY_ARRAY); + } + + private PsiNamedElement getElementAtCaret() { + PsiElement element = myFile.findElementAt(myEditor.getCaretModel().getOffset()); + PsiNamedElement namedElement = PsiTreeUtil.getParentOfType(element, PsiNamedElement.class); + FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(namedElement.getLanguage()); + assertTrue("Cannot find element in caret",provider.canFindUsagesFor(namedElement)); + return namedElement; + } +} diff --git a/plugins/java-i18n/testSrc/com/intellij/lang/properties/PropertiesHighlightingTest.java b/plugins/java-i18n/testSrc/com/intellij/lang/properties/PropertiesHighlightingTest.java new file mode 100644 index 000000000000..1e12b3841c4e --- /dev/null +++ b/plugins/java-i18n/testSrc/com/intellij/lang/properties/PropertiesHighlightingTest.java @@ -0,0 +1,76 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.lang.properties; + +import com.intellij.codeInspection.unused.UnusedPropertyInspection; +import com.intellij.lang.FileASTNode; +import com.intellij.lang.properties.psi.PropertiesFile; +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiReference; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; + +import java.io.IOException; +import java.util.Collection; + +/** + * @author max + */ +public class PropertiesHighlightingTest extends JavaCodeInsightFixtureTestCase { + + @Override + protected String getTestDataPath() { + return PluginPathManager.getPluginHomePath("java-i18n") + "/testData/highlighting"; + } + + private void doTest(boolean checkWarnings, boolean checkInfos) { + myFixture.configureByFile(getTestName(false) + ".properties"); + ((CodeInsightTestFixtureImpl)myFixture).setVirtualFileFilter(VirtualFileFilter.NONE); + myFixture.checkHighlighting(checkWarnings, checkInfos, false); + } + + public void testDuplicate() { doTest(false, false); } + + public void testUnused() { + myFixture.enableInspections(new UnusedPropertyInspection()); + myFixture.addClass("class C { String s = \"used.prop\"; }"); + doTest(true, false); + } + + public void testPropertyUsedInLibrary() throws IOException { + myFixture.enableInspections(new UnusedPropertyInspection()); + + PsiTestUtil.removeAllRoots(myModule, ModuleRootManager.getInstance(myModule).getSdk()); + String libDir = myFixture.getTempDirFixture().findOrCreateDir("lib").getPath(); + PsiTestUtil.addLibrary(myModule, "someLib", libDir, new String[]{""}, new String[]{""}); + PsiTestUtil.addSourceContentToRoots(myModule, myFixture.getTempDirFixture().findOrCreateDir("src")); + + VirtualFile usage = myFixture.addFileToProject("lib/C.java", "class C { String s = \"used.prop\"; }").getVirtualFile(); + myFixture.addFileToProject("lib/original.properties", "used.prop=xxx"); + + ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(getProject()); + assertTrue(index.isInLibrarySource(usage)); + assertTrue(index.isInLibraryClasses(usage)); + assertFalse(index.isInSourceContent(usage)); + + //noinspection UnusedDeclaration,ConstantConditions + FileASTNode node = PsiManager.getInstance(getProject()).findFile(usage).getNode(); // load tree before assertions are enabled + + myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("Unused.properties", "src/a.properties")); + myFixture.checkHighlighting(true, false, false); + + IProperty property = ((PropertiesFile)myFixture.getFile()).getProperties().get(1); + assertEquals("used.prop", property.getName()); + Collection references = ReferencesSearch.search(property.getPsiElement()).findAll(); + assertEquals(usage, assertOneElement(references).getElement().getContainingFile().getVirtualFile()); + } + + public void testOk() { doTest(false, false); } + public void testInvalidEscape() { doTest(true, false); } +}