diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaCharsetReferenceContributor.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaCharsetReferenceContributor.java new file mode 100644 index 000000000000..db1a385d5137 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaCharsetReferenceContributor.java @@ -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.psi.impl.source.resolve.reference.impl; + +import com.intellij.codeInsight.daemon.impl.analysis.encoding.EncodingReference; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.reference.impl.manipulators.StringLiteralManipulator; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import java.nio.charset.Charset; + +import static com.intellij.patterns.PsiJavaPatterns.literalExpression; +import static com.intellij.patterns.PsiJavaPatterns.psiMethod; +import static com.intellij.patterns.StandardPatterns.string; + +/** + * @author peter + */ +public class JavaCharsetReferenceContributor extends PsiReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( + literalExpression().methodCallParameter( + 0, psiMethod().withName(string().oneOf("forName", "isSupported")).inClass(Charset.class.getName())), + new PsiReferenceProvider() { + @NotNull + @Override + public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { + PsiLiteralExpression literal = (PsiLiteralExpression)element; + Object value = literal.getValue(); + if (value instanceof String) { + return new PsiReference[]{new EncodingReference(element, (String)value, StringLiteralManipulator.getValueRange(literal))}; + } + return PsiReference.EMPTY_ARRAY; + } + }); + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/CharsetName.java b/java/java-tests/testData/codeInsight/completion/normal/CharsetName.java new file mode 100644 index 000000000000..c932c81751d6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/CharsetName.java @@ -0,0 +1,7 @@ +import java.nio.charset.Charset; + +public final class FileAttributes { + { + Charset.forName("utf") + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 16132567de64..79a94aaa8148 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1216,6 +1216,12 @@ class XInternalError {} public void testConstantInAnno() { doTest() } + public void testCharsetName() { + myFixture.addClass("package java.nio.charset; public class Charset { public static Charset forName(String s) {} }") + configureByTestName() + assert myFixture.lookupElementStrings.contains('UTF-8') + } + public void testInnerClassInExtendsGenerics() { def text = "package bar; class Foo extends List> { public static class Inner {} }" myFixture.configureFromExistingVirtualFile(myFixture.addClass(text).containingFile.virtualFile) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReference.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReference.java new file mode 100644 index 000000000000..d3f0da5e5d0f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReference.java @@ -0,0 +1,103 @@ +/* + * 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.daemon.impl.analysis.encoding; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * @author peter + */ +public class EncodingReference implements PsiReference { + private final PsiElement myElement; + + private final String myCharsetName; + private final TextRange myRangeInElement; + + public EncodingReference(PsiElement element, final String charsetName, final TextRange rangeInElement) { + myElement = element; + myCharsetName = charsetName; + myRangeInElement = rangeInElement; + } + + @Override + public PsiElement getElement() { + return myElement; + } + + @Override + public TextRange getRangeInElement() { + return myRangeInElement; + } + + @Override + @Nullable + public PsiElement resolve() { + return CharsetToolkit.forName(myCharsetName) == null ? null : myElement; + //if (ApplicationManager.getApplication().isUnitTestMode()) return myValue; // tests do not have full JDK + //String fqn = charset.getClass().getName(); + //return myValue.getManager().findClass(fqn, GlobalSearchScope.allScope(myValue.getProject())); + } + + @Override + @NotNull + public String getCanonicalText() { + return myCharsetName; + } + + @Override + public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { + return null; + } + + @Override + public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { + return null; + } + + @Override + public boolean isReferenceTo(PsiElement element) { + return false; + } + + @Override + @NotNull + public Object[] getVariants() { + Charset[] charsets = CharsetToolkit.getAvailableCharsets(); + List suggestions = new ArrayList(charsets.length); + for (Charset charset : charsets) { + suggestions.add(LookupElementBuilder.create(charset.name()).withCaseSensitivity(false)); + } + return suggestions.toArray(new LookupElement[suggestions.size()]); + } + + @Override + public boolean isSoft() { + return false; + } + +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java index a83d51b7867a..3ad8cb12c2ec 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CopyReferenceAction.java @@ -36,15 +36,14 @@ import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.StatusBarEx; import com.intellij.psi.*; -import com.intellij.util.ArrayUtilRt; -import com.intellij.util.LogicalRoot; -import com.intellij.util.LogicalRootsManager; -import com.intellij.util.ObjectUtils; +import com.intellij.util.*; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,6 +52,8 @@ import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; +import java.util.Arrays; +import java.util.List; /** * @author Alexey @@ -68,10 +69,20 @@ public class CopyReferenceAction extends DumbAwareAction { @Override public void update(AnActionEvent e) { + boolean plural = false; + boolean enabled; + DataContext dataContext = e.getDataContext(); Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - boolean enabled = (editor != null && FileDocumentManager.getInstance().getFile(editor.getDocument()) != null) || - getElementToCopy(editor, dataContext) != null; + if (editor != null && FileDocumentManager.getInstance().getFile(editor.getDocument()) != null) { + enabled = true; + } + else { + List elements = getElementsToCopy(editor, dataContext); + enabled = !elements.isEmpty(); + plural = elements.size() > 1; + } + e.getPresentation().setEnabled(enabled); if (ActionPlaces.isPopupPlace(e.getPlace())) { e.getPresentation().setVisible(enabled); @@ -79,6 +90,7 @@ public class CopyReferenceAction extends DumbAwareAction { else { e.getPresentation().setVisible(true); } + e.getPresentation().setText(plural ? "Cop&y References" : "Cop&y Reference"); } @Override @@ -86,9 +98,9 @@ public class CopyReferenceAction extends DumbAwareAction { DataContext dataContext = e.getDataContext(); Editor editor = CommonDataKeys.EDITOR.getData(dataContext); Project project = CommonDataKeys.PROJECT.getData(dataContext); - PsiElement element = getElementToCopy(editor, dataContext); + List elements = getElementsToCopy(editor, dataContext); - if (!doCopy(element, project, editor) && editor != null && project != null) { + if (!doCopy(elements, project, editor) && editor != null && project != null) { Document document = editor.getDocument(); PsiFile file = PsiDocumentManager.getInstance(project).getCachedPsiFile(document); if (file != null) { @@ -102,45 +114,54 @@ public class CopyReferenceAction extends DumbAwareAction { HighlightManager highlightManager = HighlightManager.getInstance(project); EditorColorsManager manager = EditorColorsManager.getInstance(); TextAttributes attributes = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - if (element != null && editor != null && project != null) { - PsiElement nameIdentifier = IdentifierUtil.getNameIdentifier(element); + if (elements.size() == 1 && editor != null && project != null) { + PsiElement nameIdentifier = IdentifierUtil.getNameIdentifier(elements.get(0)); if (nameIdentifier != null) { highlightManager.addOccurrenceHighlights(editor, new PsiElement[]{nameIdentifier}, attributes, true, null); } else { PsiReference reference = TargetElementUtilBase.findReference(editor, editor.getCaretModel().getOffset()); if (reference != null) { highlightManager.addOccurrenceHighlights(editor, new PsiReference[]{reference}, attributes, true, null); - } else if (element != PsiDocumentManager.getInstance(project).getCachedPsiFile(editor.getDocument())) { - highlightManager.addOccurrenceHighlights(editor, new PsiElement[]{element}, attributes, true, null); + } else if (elements != PsiDocumentManager.getInstance(project).getCachedPsiFile(editor.getDocument())) { + highlightManager.addOccurrenceHighlights(editor, new PsiElement[]{elements.get(0)}, attributes, true, null); } } } } - @Nullable - private static PsiElement getElementToCopy(@Nullable final Editor editor, final DataContext dataContext) { - PsiElement element = null; + @NotNull + private static List getElementsToCopy(@Nullable final Editor editor, final DataContext dataContext) { + List elements = ContainerUtil.newArrayList(); if (editor != null) { PsiReference reference = TargetElementUtilBase.findReference(editor); if (reference != null) { - element = reference.getElement(); + ContainerUtil.addIfNotNull(elements, reference.getElement()); } } - if (element == null) { - element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); - } - if (element == null && editor == null) { - VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (virtualFile != null && project != null) { - element = PsiManager.getInstance(project).findFile(virtualFile); - } - } - if (element instanceof PsiFile && !((PsiFile)element).getViewProvider().isPhysical()) { - return null; + if (elements.isEmpty()) { + ContainerUtil.addIfNotNull(elements, CommonDataKeys.PSI_ELEMENT.getData(dataContext)); } + if (elements.isEmpty() && editor == null) { + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); + if (project != null && files != null) { + for (VirtualFile file : files) { + ContainerUtil.addIfNotNull(elements, PsiManager.getInstance(project).findFile(file)); + } + } + } + + return ContainerUtil.mapNotNull(elements, new Function() { + @Override + public PsiElement fun(PsiElement element) { + return element instanceof PsiFile && !((PsiFile)element).getViewProvider().isPhysical() ? null : adjustElement(element); + } + }); + } + + private static PsiElement adjustElement(PsiElement element) { for (QualifiedNameProvider provider : Extensions.getExtensions(QualifiedNameProvider.EP_NAME)) { PsiElement adjustedElement = provider.adjustElementToCopy(element); if (adjustedElement != null) return adjustedElement; @@ -149,16 +170,25 @@ public class CopyReferenceAction extends DumbAwareAction { } public static boolean doCopy(final PsiElement element, final Project project) { - return doCopy(element, project, null); + return doCopy(Arrays.asList(element), project, null); } - private static boolean doCopy(final PsiElement element, @Nullable final Project project, @Nullable Editor editor) { - String fqn = elementToFqn(element, editor); - if (fqn == null) return false; + private static boolean doCopy(List elements, @Nullable final Project project, @Nullable Editor editor) { + if (elements.isEmpty()) return false; - CopyPasteManager.getInstance().setContents(new MyTransferable(fqn)); + List fqns = ContainerUtil.newArrayList(); + for (PsiElement element : elements) { + String fqn = elementToFqn(element, editor); + if (fqn == null) return false; - setStatusBarText(project, IdeBundle.message("message.reference.to.fqn.has.been.copied", fqn)); + fqns.add(fqn); + } + + String toCopy = StringUtil.join(fqns, "\n"); + + CopyPasteManager.getInstance().setContents(new MyTransferable(toCopy)); + + setStatusBarText(project, IdeBundle.message("message.reference.to.fqn.has.been.copied", toCopy)); return true; } @@ -199,12 +229,12 @@ public class CopyReferenceAction extends DumbAwareAction { } @Nullable - public static String elementToFqn(final PsiElement element) { + public static String elementToFqn(@Nullable final PsiElement element) { return elementToFqn(element, null); } @Nullable - public static String elementToFqn(final PsiElement element, @Nullable Editor editor) { + private static String elementToFqn(@Nullable final PsiElement element, @Nullable Editor editor) { String result = getQualifiedNameFromProviders(element); if (result != null) return result; diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 4c8b217d526d..329fc3def69f 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1471,6 +1471,7 @@ implementationClass="com.intellij.psi.impl.JavaRegExpHost"/> + diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 6ac3516a8b37..71cb555d1838 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -57,6 +57,7 @@ cdata cglib changelist charset +charsets checkbox checkboxes checksum diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java index d6ab939090fe..3515297f31de 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java @@ -17,57 +17,21 @@ package com.intellij.codeInsight.daemon.impl.analysis.encoding; import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider; import com.intellij.codeInsight.daemon.XmlErrorMessages; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; import com.intellij.psi.xml.XmlAttributeValue; -import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; /** * @author cdr */ -public class XmlEncodingReference implements PsiReference, EmptyResolveMessageProvider, Comparable { - private final XmlAttributeValue myValue; - - private final String myCharsetName; - private final TextRange myRangeInElement; +public class XmlEncodingReference extends EncodingReference implements EmptyResolveMessageProvider, Comparable { private final int myPriority; public XmlEncodingReference(XmlAttributeValue value, final String charsetName, final TextRange rangeInElement, int priority) { - myValue = value; - myCharsetName = charsetName; - myRangeInElement = rangeInElement; + super(value, charsetName, rangeInElement); myPriority = priority; } - @Override - public PsiElement getElement() { - return myValue; - } - - @Override - public TextRange getRangeInElement() { - return myRangeInElement; - } - - @Override - @Nullable - public PsiElement resolve() { - return CharsetToolkit.forName(myCharsetName) == null ? null : myValue; - //if (ApplicationManager.getApplication().isUnitTestMode()) return myValue; // tests do not have full JDK - //String fqn = charset.getClass().getName(); - //return myValue.getManager().findClass(fqn, GlobalSearchScope.allScope(myValue.getProject())); - } - @Override @NotNull public String getUnresolvedMessagePattern() { @@ -75,43 +39,6 @@ public class XmlEncodingReference implements PsiReference, EmptyResolveMessagePr return XmlErrorMessages.message("unknown.encoding.0"); } - @Override - @NotNull - public String getCanonicalText() { - return myCharsetName; - } - - @Override - public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { - return null; - } - - @Override - public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { - return null; - } - - @Override - public boolean isReferenceTo(PsiElement element) { - return false; - } - - @Override - @NotNull - public Object[] getVariants() { - Charset[] charsets = CharsetToolkit.getAvailableCharsets(); - List suggestions = new ArrayList(charsets.length); - for (Charset charset : charsets) { - suggestions.add(LookupElementBuilder.create(charset.name()).withCaseSensitivity(false)); - } - return suggestions.toArray(new LookupElement[suggestions.size()]); - } - - @Override - public boolean isSoft() { - return false; - } - @Override public int compareTo(@NotNull XmlEncodingReference ref) { return myPriority - ref.myPriority;