IDEA-122946 final modifier not inserted when completing a sequence of parameters from an inner method

IDEA-123493 Smart completion makes completed variable final
This commit is contained in:
peter
2014-04-18 22:37:31 +02:00
parent 019a68bcc8
commit 0fd86dea1f
4 changed files with 36 additions and 18 deletions
@@ -716,7 +716,7 @@ public class HighlightControlFlowUtil {
}
@Nullable
public static PsiClass getInnerClassVariableReferencedFrom(PsiVariable variable, PsiElement context) {
public static PsiClass getInnerClassVariableReferencedFrom(@NotNull PsiVariable variable, @NotNull PsiElement context) {
final PsiElement[] scope;
if (variable instanceof PsiResourceVariable) {
scope = ((PsiResourceVariable)variable).getDeclarationScope();
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.codeInsight.lookup.VariableLookupItem;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
@@ -72,8 +73,8 @@ class SameSignatureCallParametersProvider extends CompletionProvider<CompletionP
}
}
private static LookupElement createParametersLookupElement(PsiMethod takeParametersFrom, PsiElement call, PsiMethod invoked) {
PsiParameter[] parameters = takeParametersFrom.getParameterList().getParameters();
private static LookupElement createParametersLookupElement(final PsiMethod takeParametersFrom, PsiElement call, PsiMethod invoked) {
final PsiParameter[] parameters = takeParametersFrom.getParameterList().getParameters();
final String lookupString = StringUtil.join(parameters, new Function<PsiParameter, String>() {
@Override
public String fun(PsiParameter psiParameter) {
@@ -86,7 +87,18 @@ class SameSignatureCallParametersProvider extends CompletionProvider<CompletionP
icon.setIcon(PlatformIcons.PARAMETER_ICON, 0, 2*w/5, 0);
icon.setIcon(PlatformIcons.PARAMETER_ICON, 1);
final LookupElement element = LookupElementBuilder.create(lookupString).withIcon(icon);
LookupElementBuilder element = LookupElementBuilder.create(lookupString).withIcon(icon);
if (PsiTreeUtil.isAncestor(takeParametersFrom, call, true)) {
element = element.withInsertHandler(new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
context.commitDocument();
for (PsiParameter parameter : CompletionUtil.getOriginalOrSelf(takeParametersFrom).getParameterList().getParameters()) {
VariableLookupItem.makeFinalIfNeeded(context, parameter);
}
}
});
}
element.putUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS, Boolean.TRUE);
return TailTypeDecorator.withTail(element, ExpectedTypesProvider.getFinalCallParameterTailType(call, invoked.getReturnType(), invoked));
@@ -123,7 +123,10 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
}
ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false);
makeVariableFinalIfNeeded(context, ref);
PsiElement target = ref == null ? null : ref.resolve();
if (target instanceof PsiLocalVariable || target instanceof PsiParameter) {
makeFinalIfNeeded(context, (PsiVariable)target);
}
final char completionChar = context.getCompletionChar();
if (completionChar == '=') {
@@ -151,22 +154,16 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed
}
}
private static void makeVariableFinalIfNeeded(InsertionContext context, @Nullable PsiReferenceExpression ref) {
public static void makeFinalIfNeeded(@NotNull InsertionContext context, @NotNull PsiVariable variable) {
PsiElement place = context.getFile().findElementAt(context.getTailOffset() - 1);
if (!Registry.is("java.completion.make.outer.variables.final") ||
ref == null || PsiUtil.isLanguageLevel8OrHigher(ref) || JspPsiUtil.isInJspFile(ref)) {
place == null || PsiUtil.isLanguageLevel8OrHigher(place) || JspPsiUtil.isInJspFile(place)) {
return;
}
PsiElement target = ref.resolve();
if (target instanceof PsiLocalVariable || target instanceof PsiParameter) {
PsiClass placeClass = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getTailOffset() - 1, PsiClass.class, false);
if (placeClass != null && !PsiTreeUtil.isAncestor(placeClass, target, true) &&
!HighlightControlFlowUtil.isReassigned((PsiVariable)target, new HashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>())) {
PsiModifierList modifierList = ((PsiVariable)target).getModifierList();
if (modifierList != null) {
modifierList.setModifierProperty(PsiModifier.FINAL, true);
}
}
if (HighlightControlFlowUtil.getInnerClassVariableReferencedFrom(variable, place) != null &&
!HighlightControlFlowUtil.isReassigned(variable, new HashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>())) {
PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true);
}
}
@@ -1283,9 +1283,18 @@ class XInternalError {}
lookup.currentItem = lookup.items[1]
type '\n'
checkResult()
}
public void testMakeMultipleArgumentsFinalWhenInInner() {
configure()
def item = lookup.items.find { 'a, b' == it.lookupString }
assert item
lookup.currentItem = item
type '\n'
checkResult()
}
public void testNoFinalInAnonymousConstructor() { doTest() }
public void testListArrayListCast() { doTest('\n') }
public void testInterfaceImplementationNoCast() { doTest() }
public void testStaticallyImportedMethodsBeforeExpression() { doTest() }