Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir Orlov
2014-07-01 00:04:33 +04:00
8 changed files with 238 additions and 111 deletions
@@ -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;
}
});
}
}
@@ -0,0 +1,7 @@
import java.nio.charset.Charset;
public final class FileAttributes {
{
Charset.forName("utf<caret>")
}
}
@@ -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<Inne<caret>> { public static class Inner {} }"
myFixture.configureFromExistingVirtualFile(myFixture.addClass(text).containingFile.virtualFile)
@@ -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<LookupElement> suggestions = new ArrayList<LookupElement>(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;
}
}
@@ -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<PsiElement> 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<PsiElement> 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<PsiElement> getElementsToCopy(@Nullable final Editor editor, final DataContext dataContext) {
List<PsiElement> 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<PsiElement, PsiElement>() {
@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<PsiElement> elements, @Nullable final Project project, @Nullable Editor editor) {
if (elements.isEmpty()) return false;
CopyPasteManager.getInstance().setContents(new MyTransferable(fqn));
List<String> 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;
+1
View File
@@ -1471,6 +1471,7 @@
implementationClass="com.intellij.psi.impl.JavaRegExpHost"/>
<psi.referenceContributor language="JAVA" implementation="com.intellij.psi.impl.source.resolve.reference.impl.JavaReflectionReferenceContributor"/>
<psi.referenceContributor language="JAVA" implementation="com.intellij.psi.impl.source.resolve.reference.impl.JavaCharsetReferenceContributor"/>
<writingAccessProvider implementation="com.intellij.refactoring.util.ClsElementWritingAccessProvider"/>
@@ -57,6 +57,7 @@ cdata
cglib
changelist
charset
charsets
checkbox
checkboxes
checksum
@@ -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<XmlEncodingReference> {
private final XmlAttributeValue myValue;
private final String myCharsetName;
private final TextRange myRangeInElement;
public class XmlEncodingReference extends EncodingReference implements EmptyResolveMessageProvider, Comparable<XmlEncodingReference> {
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<LookupElement> suggestions = new ArrayList<LookupElement>(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;