Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2014-11-03 22:43:44 +01:00
20 changed files with 164 additions and 43 deletions
@@ -17,10 +17,11 @@ package com.intellij.codeInsight;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -37,15 +38,11 @@ public class FunctionalInterfaceSuggester {
return Collections.emptyList();
}
final Set<PsiType> types = new LinkedHashSet<PsiType>();
final String uniqueExprName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName("l", expression, true);
AnnotatedMembersSearch.search(functionalInterfaceClass, expression.getResolveScope()).forEach(new Processor<PsiMember>() {
@Override
public boolean process(PsiMember member) {
if (member instanceof PsiClass) {
final PsiType type = getAcceptableType((PsiClass)member, expression, uniqueExprName);
if (type != null) {
types.add(type);
}
ContainerUtil.addIfNotNull(types, composeAcceptableType((PsiClass)member, expression));
}
return true;
}
@@ -53,26 +50,60 @@ public class FunctionalInterfaceSuggester {
return types;
}
private static PsiType getAcceptableType(PsiClass interface2Consider, PsiFunctionalExpression expression, String uniqueExprName) {
private static PsiType composeAcceptableType(@NotNull PsiClass interface2Consider, @NotNull PsiFunctionalExpression expression) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(interface2Consider.getProject());
//todo try to infer type
final PsiDeclarationStatement exprDeclaration = (PsiDeclarationStatement)elementFactory
.createStatementFromText(interface2Consider.getQualifiedName() + " " + uniqueExprName + " = " + expression.getText() + ";", expression);
final PsiLocalVariable var = (PsiLocalVariable)exprDeclaration.getDeclaredElements()[0];
final PsiExpression exprAsInitializer = var.getInitializer();
if (exprAsInitializer instanceof PsiFunctionalExpression) {
if (!((PsiFunctionalExpression)exprAsInitializer).isAcceptable(var.getType())) {
return null;
}
final PsiType type = ((PsiFunctionalExpression)exprAsInitializer).getFunctionalInterfaceType();
if (type instanceof PsiLambdaExpressionType || type instanceof PsiLambdaParameterType || type instanceof PsiMethodReferenceType) {
return null;
}
final PsiType type = elementFactory.createType(interface2Consider, PsiSubstitutor.EMPTY);
if (expression.isAcceptable(type)) {
return type;
}
return composeAcceptableType(interface2Consider, expression, elementFactory);
}
private static PsiType composeAcceptableType(final PsiClass interface2Consider,
final PsiFunctionalExpression expression,
final PsiElementFactory elementFactory) {
if (interface2Consider.hasTypeParameters()) {
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(interface2Consider);
if (interfaceMethod != null) {
final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
final PsiParameter[] functionalExprParameters;
if (expression instanceof PsiLambdaExpression && ((PsiLambdaExpression)expression).hasFormalParameterTypes()) {
functionalExprParameters = ((PsiLambdaExpression)expression).getParameterList().getParameters();
}
else if (expression instanceof PsiMethodReferenceExpression && ((PsiMethodReferenceExpression)expression).isExact()) {
final PsiElement exactMethod = ((PsiMethodReferenceExpression)expression).resolve();
if (!(exactMethod instanceof PsiMethod)) {
return null;
}
functionalExprParameters = ((PsiMethod)exactMethod).getParameterList().getParameters();
} else {
return null;
}
if (parameters.length != functionalExprParameters.length) {
return null;
}
final PsiType[] left = new PsiType[parameters.length];
final PsiType[] right = new PsiType[parameters.length];
for (int i = 0; i < parameters.length; i++) {
left[i] = parameters[i].getType();
right[i] = functionalExprParameters[i].getType();
}
final PsiSubstitutor substitutor = PsiResolveHelper.SERVICE.getInstance(interface2Consider.getProject())
.inferTypeArguments(interface2Consider.getTypeParameters(), left, right, PsiUtil.getLanguageLevel(expression));
PsiType type = elementFactory.createType(interface2Consider, substitutor);
if (expression.isAcceptable(type)) {
return type;
}
}
}
return null;
}
}
@@ -135,7 +135,7 @@ public class InplaceIntroduceConstantPopup extends AbstractInplaceIntroduceField
public PsiField compute() {
PsiField field = elementFactory.createFieldFromText(
psiType.getCanonicalText() + " " + (getInputName() != null ? getInputName() : names[0]) + " = " + myInitializerText + ";",
psiType.getCanonicalText() + " " + (chooseName(names, myParentClass.getLanguage())) + " = " + myInitializerText + ";",
myParentClass);
PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true);
PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true);
@@ -86,7 +86,7 @@ public class InplaceIntroduceFieldPopup extends AbstractInplaceIntroduceFieldPop
return ApplicationManager.getApplication().runWriteAction(new Computable<PsiField>() {
@Override
public PsiField compute() {
PsiField field = elementFactory.createField(getInputName() != null ? getInputName() : names[0], defaultType);
PsiField field = elementFactory.createField(chooseName(names, myParentClass.getLanguage()), defaultType);
field = (PsiField)myParentClass.add(field);
if (myExprText != null) {
updateInitializer(elementFactory, field);
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.template.Expression;
import com.intellij.codeInsight.template.ExpressionContext;
import com.intellij.codeInsight.template.Result;
import com.intellij.codeInsight.template.TextResult;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
@@ -49,7 +50,6 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro
@Override
protected String[] suggestNames(boolean replaceAll, PsiVariable variable) {
myTypeSelectorManager.setAllOccurrences(replaceAll);
final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType();
final String propertyName = variable != null
? JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(variable.getName(), VariableKind.LOCAL_VARIABLE)
@@ -204,4 +204,11 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro
};
}
protected String chooseName(String[] names, Language language) {
String inputName = getInputName();
if (inputName != null && !isIdentifier(inputName, language)) {
inputName = null;
}
return inputName != null ? inputName : names[0];
}
}
@@ -116,10 +116,9 @@ public class InplaceIntroduceParameterPopup extends AbstractJavaInplaceIntroduce
return ApplicationManager.getApplication().runWriteAction(new Computable<PsiParameter>() {
@Override
public PsiParameter compute() {
final String name = getInputName() != null ? getInputName() : names[0];
final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod);
final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList()
.addAfter(elementFactory.createParameter(name, defaultType), anchor);
.addAfter(elementFactory.createParameter(chooseName(names, myMethod.getLanguage()), defaultType), anchor);
PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, myPanel.hasFinalModifier());
myParameterIndex = myMethod.getParameterList().getParameterIndex(psiParameter);
return psiParameter;
@@ -185,7 +185,6 @@ public abstract class IntroduceParameterSettingsUI {
box.setSelected(myCbReplaceAllOccurences.isSelected());
}
}
getTypeSelectionManager().setAllOccurrences(myCbReplaceAllOccurences.isSelected());
if (myCbReplaceAllOccurences.isSelected()) {
if (myCbDeleteLocalVariable != null) {
myCbDeleteLocalVariable.makeSelectable();
@@ -197,9 +196,6 @@ public abstract class IntroduceParameterSettingsUI {
}
}
}
else {
getTypeSelectionManager().setAllOccurrences(myIsInvokedOnDeclaration);
}
}
protected abstract TypeSelectorManager getTypeSelectionManager();
@@ -0,0 +1,10 @@
public class Derr {
public static void main(String[] args) {
String value;
value = "1";
value = "1";
value = "<caret>1";
}
}
@@ -0,0 +1,12 @@
public class Derr {
public static final String STRING = "1";
public static void main(String[] args) {
String value;
value = STRING;
value = STRING;
value = STRING;
}
}
@@ -0,0 +1,9 @@
public class Derr {
public static void main(String[] args) {
long value;
value = new Long(1);
value = new L<caret>ong(1);
}
}
@@ -0,0 +1,9 @@
public class Derr {
public static void main(String[] args, Long aLong) {
long value;
value = aLong;
value = aLong;
}
}
@@ -0,0 +1,7 @@
import java.util.function.Consumer;
class Foo {
void test() {
Consumer<Integer> l = System::exit;
}
}
@@ -0,0 +1,5 @@
class Foo {
void test() {
<selection>System::exit</selection>;
}
}
@@ -78,6 +78,16 @@ public class InplaceIntroduceConstantTest extends AbstractJavaInplaceIntroduceTe
}
});
}
public void testReplaceAllWithBrokenIdentifier() throws Exception {
doTest(new Pass<AbstractInplaceIntroducer>() {
@Override
public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) {
type("A B");
inplaceIntroduceFieldPopup.setReplaceAllOccurrences(true);
}
});
}
public void testReplaceAllFromSecondOccurrence() throws Exception {
@@ -60,6 +60,16 @@ public class InplaceIntroduceParameterTest extends AbstractJavaInplaceIntroduceT
});
}
public void testReplaceAllBrokenIdentifier() throws Exception {
doTest(new Pass<AbstractInplaceIntroducer>() {
@Override
public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) {
type("ONE TWO");
inplaceIntroduceFieldPopup.setReplaceAllOccurrences(true);
}
});
}
public void testReplaceAll2() throws Exception {
doTest(new Pass<AbstractInplaceIntroducer>() {
@Override
@@ -437,7 +437,11 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
}
public void testMethodRefNotInContext() {
doTest(new MockIntroduceVariableHandler("l", false, false, false, "java.util.function.IntConsumer"));
doTest(new MockIntroduceVariableHandler("l", false, false, false, "java.util.function.IntConsumer", true));
}
public void testMethodRefNotInContextInferred() {
doTest(new MockIntroduceVariableHandler("l", false, false, false, "java.util.function.Consumer<java.lang.Integer>", true));
}
public void testOneLineLambdaVoidCompatible() {
@@ -51,6 +51,7 @@ import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
@@ -198,7 +199,7 @@ public class SurroundWithHandler implements CodeInsightActionHandler {
editor.getCaretModel().moveToLogicalPosition(pos);
}
TextRange range = surrounder.surroundElements(project, editor, elements);
if (TemplateManager.getInstance(project).getActiveTemplate(editor) == null) {
if (TemplateManager.getInstance(project).getActiveTemplate(editor) == null && InplaceRefactoring.getActiveInplaceRenamer(editor) == null) {
LogicalPosition pos1 = new LogicalPosition(line, col);
editor.getCaretModel().moveToLogicalPosition(pos1);
}
@@ -318,14 +318,19 @@ public abstract class AbstractInplaceIntroducer<V extends PsiNameIdentifierOwner
myEditor.putUserData(INTRODUCE_RESTART, true);
try {
final TextRange range = templateState.getCurrentVariableRange();
if (range != null && range.isEmpty()) {
final String[] names = suggestNames(isReplaceAllOccurrences(), getLocalVariable());
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
myEditor.getDocument().insertString(myEditor.getCaretModel().getOffset(), names[0]);
}
});
if (range != null) {
final TextResult inputText = templateState.getVariableValue(PRIMARY_VARIABLE_NAME);
final String inputName = inputText != null ? inputText.getText() : null;
final V variable = getVariable();
if (inputName == null || variable == null || !isIdentifier(inputName, variable.getLanguage())) {
final String[] names = suggestNames(isReplaceAllOccurrences(), getLocalVariable());
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
myEditor.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), names[0]);
}
});
}
}
templateState.gotoEnd(true);
try {
@@ -43,7 +43,7 @@ public class ChangeSet {
public ChangeSet(long id, long timestamp) {
myId = id;
myTimestamp = timestamp;
myChanges = ContainerUtil.createLockFreeCopyOnWriteList();
myChanges = new ArrayList<Change>();
}
public ChangeSet(DataInput in) throws IOException {
@@ -54,7 +54,7 @@ public class ClassWithOnlyPrivateConstructorsInspectionBase extends BaseInspecti
@Override
public void visitClass(PsiClass aClass) {
super.visitClass(aClass);
if (aClass.isEnum()) {
if (aClass.isEnum() || aClass.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
final PsiMethod[] constructors = aClass.getConstructors();
@@ -41,6 +41,12 @@ public class ClassWithOnlyPrivateConstructorsInspectionTest extends LightInspect
doTest("class X {}");
}
public void testNoWarnOnFinalClass() {
doTest("final class X {" +
" private X() {}" +
"}");
}
public void testEnum() {
doTest("enum Currencies {\n" +
" EURO, DOLLAR;\n" +