diff --git a/build.txt b/build.txt index 94551a39261d..2b466995ac79 100644 --- a/build.txt +++ b/build.txt @@ -1 +1 @@ -118.SNAPSHOT +120.SNAPSHOT diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java index f084d975b7a0..71b3176e7a29 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/DefaultQuickFixProvider.java @@ -17,13 +17,20 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.QuickFixActionRegistrar; import com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper; import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; +import java.util.HashMap; +import java.util.Map; + public class DefaultQuickFixProvider extends UnresolvedReferenceQuickFixProvider { @Override public void registerFixes(PsiJavaCodeReferenceElement ref, QuickFixActionRegistrar registrar) { @@ -37,15 +44,13 @@ public class DefaultQuickFixProvider extends UnresolvedReferenceQuickFixProvider PsiReferenceExpression refExpr = (PsiReferenceExpression)ref; registrar.register(fixRange, new CreateEnumConstantFromUsageFix(refExpr), null); - registrar.register(fixRange, new CreateConstantFieldFromUsageFix(refExpr), null); - registrar.register(fixRange, new CreateFieldFromUsageFix(refExpr), null); registrar.register(new RenameWrongRefFix(refExpr)); if (!ref.isQualified()) { registrar.register(fixRange, new BringVariableIntoScopeFix(refExpr), null); - registrar.register(fixRange, new CreateLocalFromUsageFix(refExpr), null); - registrar.register(fixRange, new CreateParameterFromUsageFix(refExpr), null); } + + registerPriorityActions(registrar,fixRange,refExpr); } registrar.register(new CreateClassFromUsageFix(ref, CreateClassKind.INTERFACE)); @@ -65,6 +70,57 @@ public class DefaultQuickFixProvider extends UnresolvedReferenceQuickFixProvider } } + private static void registerPriorityActions(@NotNull final QuickFixActionRegistrar registrar, + @NotNull final TextRange fixRange, + @NotNull final PsiReferenceExpression refExpr) { + final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(refExpr.getProject()); + + final Map map = new HashMap() { + { + put(VariableKind.FIELD, new CreateFieldFromUsageFix(refExpr)); + put(VariableKind.STATIC_FINAL_FIELD, new CreateConstantFieldFromUsageFix(refExpr)); + if (!refExpr.isQualified()) { + put(VariableKind.LOCAL_VARIABLE, new CreateLocalFromUsageFix(refExpr)); + put(VariableKind.PARAMETER, new CreateParameterFromUsageFix(refExpr)); + } + } + }; + + final VariableKind kind = getKind(styleManager, refExpr); + if (map.containsKey(kind)){ + map.put(kind, PriorityIntentionActionWrapper.highPriority(map.get(kind))); + } + + for (IntentionAction action : map.values()){ + registrar.register(fixRange, action, null); + } + } + + @NotNull + private static VariableKind getKind(@NotNull JavaCodeStyleManager styleManager, + @NotNull PsiReferenceExpression refExpr) { + final String reference = refExpr.getText(); + + if (reference.toUpperCase().equals(reference)){ + return VariableKind.STATIC_FINAL_FIELD; + } + + for (VariableKind kind : VariableKind.values()) { + final String prefix = styleManager.getPrefixByVariableKind(kind); + final String suffix = styleManager.getSuffixByVariableKind(kind); + + if (prefix.isEmpty() && suffix.isEmpty()) { + continue; + } + + if (reference.startsWith(prefix) && reference.endsWith(suffix)) { + return kind; + } + } + + return VariableKind.LOCAL_VARIABLE; + } + @Override @NotNull public Class getReferenceClass() { diff --git a/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java b/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java index f9f5756581ba..08325f5c32cc 100644 --- a/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/internal/FileEqualsUsageInspection.java @@ -55,7 +55,7 @@ public class FileEqualsUsageInspection extends InternalInspection { if (clazz == null) return; String methodName = method.getName(); - if ("java.io.File".equals(clazz.getQualifiedName()) + if (CommonClassNames.JAVA_IO_FILE.equals(clazz.getQualifiedName()) && ("equals".equals(methodName) || "compareTo".equals(methodName) || "hashCode".equals(methodName))) { holder.registerProblem(methodExpression, "Do not use File.equals/hashCode/compareTo as they don't honor case-sensitivity on MacOS. Use FileUtil.filesEquals/fileHashCode/compareFiles instead", diff --git a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java index 95d78fafed51..9a7c93449210 100644 --- a/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java +++ b/java/java-psi-api/src/com/intellij/psi/CommonClassNames.java @@ -87,4 +87,5 @@ public interface CommonClassNames { @NonNls String JAVA_LANG_INVOKE_MH_POLYMORPHIC = "java.lang.invoke.MethodHandle.PolymorphicSignature"; String TARGET_ANNOTATION_FQ_NAME = "java.lang.annotation.Target"; @NonNls String JAVA_LANG_RUNNABLE = "java.lang.Runnable"; + @NonNls String JAVA_IO_FILE = "java.io.File"; } diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java b/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java new file mode 100644 index 000000000000..7867e3415883 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/UnderscoresDontMakeMatchMiddle.java @@ -0,0 +1,5 @@ +class FooBar { + void foo(FooBar _fooBar) { + fb + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 4cbd44f021da..3f7afec4da67 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -1272,4 +1272,22 @@ class Foo { myFixture.checkResult 'class Foo {{ boolean }}' } + @Override + protected void tearDown() { + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER + super.tearDown() + } + + public void testBackspaceShouldShowPreviousVariants() { + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE + myFixture.addClass("class OuterX { static class TrueLine {} }") + myFixture.configureByText 'a.java', 'class Foo{ void foo(int truex) { return tr }}' + type 'ue' + assert myFixture.lookupElementStrings == ['true', 'truex'] + type 'l' + assert myFixture.lookupElementStrings == ['TrueLine'] + type '\b' + assert myFixture.lookupElementStrings == ['true', 'truex'] + } + } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy index 0f73a23f289f..771413f86736 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -378,4 +378,9 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { assertPreferredItems(0, 'fooy', 'foox', 'fooAClass', 'fooBar'); } + public void testUnderscoresDontMakeMatchMiddle() { + CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE; + checkPreferredItems(0, '_fooBar', 'FooBar') + } + } diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java index 1591b3818546..714408dcf566 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java @@ -63,7 +63,7 @@ public abstract class CompletionTestCase extends DaemonAnalyzerTestCase { } protected void complete(final int time) { - new CodeCompletionHandlerBase(myType).invokeCompletion(myProject, myEditor, time, false); + new CodeCompletionHandlerBase(myType).invokeCompletion(myProject, myEditor, time); LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); myItems = lookup == null ? null : lookup.getItems().toArray(new LookupElement[lookup.getItems().size()]); diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java index d7a89a49a4eb..025efe43b958 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java @@ -57,7 +57,7 @@ public abstract class LightCompletionTestCase extends LightCodeInsightTestCase { } protected void complete(final int time) { - new CodeCompletionHandlerBase(myType).invokeCompletion(getProject(), getEditor(), time, false); + new CodeCompletionHandlerBase(myType).invokeCompletion(getProject(), getEditor(), time); LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor); myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java new file mode 100644 index 000000000000..4c6aa7cbb62d --- /dev/null +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityIntentionActionWrapper.java @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2012 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.intention.impl; + +import com.intellij.codeInsight.intention.HighPriorityAction; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; + +/** + * @author Danila Ponomarenko + */ +public abstract class PriorityIntentionActionWrapper implements IntentionAction { + private IntentionAction action; + + private PriorityIntentionActionWrapper(@NotNull IntentionAction action) { + this.action = action; + } + + @NotNull + @Override + public String getText() { + return action.getText(); + } + + @NotNull + @Override + public String getFamilyName() { + return action.getFamilyName(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return action.isAvailable(project, editor, file); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + action.invoke(project, editor, file); + } + + @Override + public boolean startInWriteAction() { + return action.startInWriteAction(); + } + + private static class HighPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper implements HighPriorityAction { + protected HighPriorityIntentionActionWrapper(@NotNull IntentionAction action) { + super(action); + } + } + + private static class NormalPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper { + protected NormalPriorityIntentionActionWrapper(@NotNull IntentionAction action) { + super(action); + } + } + + private static class LowPriorityIntentionActionWrapper extends PriorityIntentionActionWrapper implements LowPriorityAction { + protected LowPriorityIntentionActionWrapper(@NotNull IntentionAction action) { + super(action); + } + } + + @NotNull + public static IntentionAction highPriority(@NotNull IntentionAction action) { + return new HighPriorityIntentionActionWrapper(action); + } + + @NotNull + public static IntentionAction normalPriority(@NotNull IntentionAction action) { + return new NormalPriorityIntentionActionWrapper(action); + } + + @NotNull + public static IntentionAction lowPriority(@NotNull IntentionAction action) { + return new LowPriorityIntentionActionWrapper(action); + } +} diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java new file mode 100644 index 000000000000..ba83bc5b324c --- /dev/null +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/PriorityLocalQuickFixWrapper.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2012 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.intention.impl; + +import com.intellij.codeInsight.intention.HighPriorityAction; +import com.intellij.codeInsight.intention.LowPriorityAction; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Danila Ponomarenko + */ +public abstract class PriorityLocalQuickFixWrapper implements LocalQuickFix { + private LocalQuickFix fix; + + private PriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + this.fix = fix; + } + + @NotNull + @Override + public String getName() { + return fix.getName(); + } + + @NotNull + @Override + public String getFamilyName() { + return fix.getFamilyName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + fix.applyFix(project, descriptor); + } + + private static class HighPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper implements HighPriorityAction { + protected HighPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + super(fix); + } + } + + private static class NormalPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper { + protected NormalPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + super(fix); + } + } + + + private static class LowPriorityLocalQuickFixWrapper extends PriorityLocalQuickFixWrapper implements LowPriorityAction { + protected LowPriorityLocalQuickFixWrapper(@NotNull LocalQuickFix fix) { + super(fix); + } + } + + @NotNull + public static LocalQuickFix highPriority(@NotNull LocalQuickFix fix) { + return new HighPriorityLocalQuickFixWrapper(fix); + } + + @NotNull + public static LocalQuickFix normalPriority(@NotNull LocalQuickFix fix) { + return new NormalPriorityLocalQuickFixWrapper(fix); + } + + @NotNull + public static LocalQuickFix lowPriority(@NotNull LocalQuickFix fix) { + return new LowPriorityLocalQuickFixWrapper(fix); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java index 673baa207249..01e7a3181b72 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java @@ -121,7 +121,7 @@ public class AutoPopupController implements Disposable { PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument()); if (file != null && condition != null && !condition.value(file)) return; - CompletionAutoPopupHandler.invokeCompletion(CompletionType.BASIC, true, myProject, editor, 0); + CompletionAutoPopupHandler.invokeCompletion(CompletionType.BASIC, true, myProject, editor, 0, false); } }); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 977262faa634..913a89aa2bd3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -100,14 +100,18 @@ public class CodeCompletionHandlerBase { public final void invokeCompletion(final Project project, final Editor editor) { try { - invokeCompletion(project, editor, 1, false); + invokeCompletion(project, editor, 1); } catch (IndexNotReadyException e) { DumbService.getInstance(project).showDumbModeNotification("Code completion is not available here while indices are being built"); } } - public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers) { + public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time) { + invokeCompletion(project, editor, time, false, false); + } + + public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted) { final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument()); @@ -210,22 +214,8 @@ public class CodeCompletionHandlerBase { }; if (autopopup) { CommandProcessor.getInstance().runUndoTransparentAction(initCmd); - - int offset = editor.getCaretModel().getOffset(); - int psiOffset = Math.max(0, offset - 1); - - PsiElement elementAt = InjectedLanguageUtil.findInjectedElementNoCommit(psiFile, psiOffset); - if (elementAt == null) { - elementAt = psiFile.findElementAt(psiOffset); - } - if (elementAt == null) return; - - Language language = PsiUtilBase.findLanguageFromElement(elementAt); - - for (CompletionConfidence confidence : CompletionConfidenceEP.forLanguage(language)) { - final ThreeState result = confidence.shouldSkipAutopopup(elementAt, psiFile, offset); - if (result == ThreeState.YES) return; - if (result == ThreeState.NO) break; + if (!restarted && shouldSkipAutoPopup(editor, psiFile)) { + return; } } else { CommandProcessor.getInstance().executeCommand(project, initCmd, null, null); @@ -234,6 +224,30 @@ public class CodeCompletionHandlerBase { insertDummyIdentifier(initializationContext[0], hasModifiers, time); } + private static boolean shouldSkipAutoPopup(Editor editor, PsiFile psiFile) { + int offset = editor.getCaretModel().getOffset(); + int psiOffset = Math.max(0, offset - 1); + + PsiElement elementAt = InjectedLanguageUtil.findInjectedElementNoCommit(psiFile, psiOffset); + if (elementAt == null) { + elementAt = psiFile.findElementAt(psiOffset); + } + if (elementAt == null) return true; + + Language language = PsiUtilBase.findLanguageFromElement(elementAt); + + for (CompletionConfidence confidence : CompletionConfidenceEP.forLanguage(language)) { + final ThreeState result = confidence.shouldSkipAutopopup(elementAt, psiFile, offset); + if (result == ThreeState.YES) { + return true; + } + if (result == ThreeState.NO) { + return false; + } + } + return false; + } + @NotNull private LookupImpl obtainLookup(Editor editor) { LookupImpl existing = (LookupImpl)LookupManager.getActiveLookup(editor); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index b0f57ae05d52..84c980d1ae26 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -658,7 +658,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement if (phase.checkExpired()) return; CompletionAutoPopupHandler.invokeCompletion(myParameters.getCompletionType(), - isAutopopupCompletion(), project, myEditor, myParameters.getInvocationCount()); + isAutopopupCompletion(), project, myEditor, myParameters.getInvocationCount(), true); } }); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java index 3a0a67655362..dc92fd0d8dc6 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/actions/BaseCodeCompletionAction.java @@ -47,7 +47,7 @@ public abstract class BaseCodeCompletionAction extends AnAction implements HintM assert project != null; assert editor != null; InputEvent inputEvent = e.getInputEvent(); - new CodeCompletionHandlerBase(type).invokeCompletion(project, editor, time, inputEvent != null && inputEvent.getModifiers() != 0); + new CodeCompletionHandlerBase(type).invokeCompletion(project, editor, time, inputEvent != null && inputEvent.getModifiers() != 0, false); } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java index fb274985ebf9..30e16e9a7a3a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java @@ -59,25 +59,22 @@ public class CamelHumpMatcher extends PrefixMatcher { String prefix = applyMiddleMatching(myPrefix); if (!caseSensitive) { - return NameUtil.buildCompletionMatcher(prefix, 0, true, true); + return NameUtil.buildMatcher(prefix, NameUtil.MatchingCaseSensitivity.NONE); } switch (CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE) { case CodeInsightSettings.NONE: - return NameUtil.buildCompletionMatcher(prefix, 0, true, true); + return NameUtil.buildMatcher(prefix, NameUtil.MatchingCaseSensitivity.NONE); case CodeInsightSettings.FIRST_LETTER: - int exactPrefixLen = prefix.startsWith("*") ? 0 : 1; - return NameUtil.buildCompletionMatcher(prefix, exactPrefixLen, true, true); - case CodeInsightSettings.ALL: - return NameUtil.buildCompletionMatcher(prefix, 1, false, false); + return NameUtil.buildMatcher(prefix, NameUtil.MatchingCaseSensitivity.FIRST_LETTER); default: - return NameUtil.buildCompletionMatcher(prefix, 0, true, false); + return NameUtil.buildMatcher(prefix, NameUtil.MatchingCaseSensitivity.ALL); } } public static String applyMiddleMatching(String prefix) { if (Registry.is("ide.completion.middle.matching") && !prefix.isEmpty() && !ApplicationManager.getApplication().isUnitTestMode()) { - return " " + StringUtil.replace(prefix, ".", ". ").trim(); + return "*" + StringUtil.replace(prefix, ".", ". ").trim(); } return prefix; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java index ba7543e680da..63f738b5b147 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CompletionServiceImpl.java @@ -147,10 +147,7 @@ public class CompletionServiceImpl extends CompletionService{ Iterable fragments = matcher.matchingFragments(ls); if (fragments != null) { Iterator iterator = fragments.iterator(); - if (!ls.isEmpty() && prefix.charAt(0) == ls.charAt(0)) { - return false; - } - if (iterator.hasNext() && iterator.next().contains(0)) { + if (!iterator.hasNext() || MinusculeMatcher.isStartMatch(ls, iterator.next().getStartOffset())) { return false; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java index d0a8ae4db1c3..86ea6e97d1f3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -79,7 +79,7 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { public static void invokeCompletion(CompletionType completionType, boolean autopopup, - Project project, Editor editor, int time) { + Project project, Editor editor, int time, boolean restart) { if (editor.isDisposed()) return; // retrieve the injected file from scratch since our typing might have destroyed the old one completely @@ -94,7 +94,7 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { } Editor newEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(topLevelEditor, topLevelFile); try { - new CodeCompletionHandlerBase(completionType, false, autopopup, false).invokeCompletion(project, newEditor, time, false); + new CodeCompletionHandlerBase(completionType, false, autopopup, false).invokeCompletion(project, newEditor, time, false, restart); } catch (IndexNotReadyException ignored) { } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java index 9476402c0c0a..1382508ea8b5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java @@ -12,6 +12,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.util.text.CharArrayUtil; @@ -20,6 +21,7 @@ import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; +import java.util.List; /** * @author yole @@ -40,9 +42,9 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor= document.getLineStartOffset(selStartLine); offset--) { if (!Character.isWhitespace(document.getCharsSequence().charAt(offset))) { @@ -132,20 +134,29 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor strings = StringUtil.split(pastedText, "\n"); + //if (strings.get(strings.size() - 1)) + + if (strings.get(0).trim().startsWith("def") || + strings.get(0).trim().startsWith("class")) endLine -=1; + for (int i = startLine+1; i <= endLine; i++) { - EditorActionUtil.indentLine(project, editor, i, caretColumn - value.getIndent()); + EditorActionUtil.indentLine(project, editor, i, value.getIndent()); } indented.set(Boolean.TRUE); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index 70bd5d7e91cd..0083f5c5d888 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -1396,14 +1396,15 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable myScrollBarIncreaseButton.setPreferredSize(buttonSize); myScrollBarIncreaseButton.setMinimumSize(buttonSize); myScrollBarIncreaseButton.setMaximumSize(buttonSize); - myScrollPane.getVerticalScrollBar().revalidate(); - myScrollPane.getVerticalScrollBar().repaint(); + JScrollBar scrollBar = myScrollPane.getVerticalScrollBar(); + scrollBar.revalidate(); + scrollBar.repaint(); final Dimension iconSize = myProcessIcon.getPreferredSize(); - myIconPanel.setBounds(getWidth() - iconSize.width, 0, iconSize.width, iconSize.height); + myIconPanel.setBounds(getWidth() - iconSize.width - (scrollBar.isVisible() ? scrollBar.getWidth() : 0), 0, iconSize.width, iconSize.height); final Dimension sortSize = mySortingLabel.getPreferredSize(); - final Point sbLocation = SwingUtilities.convertPoint(myScrollPane.getVerticalScrollBar(), 0, 0, myLayeredPane); + final Point sbLocation = SwingUtilities.convertPoint(scrollBar, 0, 0, myLayeredPane); final int sortHeight = Math.max(adHeight, mySortingLabel.getPreferredSize().height); mySortingLabel.setBounds(sbLocation.x, getHeight() - sortHeight, sortSize.width, sortHeight); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java index 6ee5256bbdc5..d5796ffcc4ff 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/ClassNameCompleteMacro.java @@ -27,6 +27,6 @@ public class ClassNameCompleteMacro extends BaseCompleteMacro { } protected void invokeCompletionHandler(Project project, Editor editor) { - new CodeCompletionHandlerBase(CompletionType.BASIC, false, false, true).invokeCompletion(project, editor, 2, false); + new CodeCompletionHandlerBase(CompletionType.BASIC, false, false, true).invokeCompletion(project, editor, 2); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java index 8276aefc966c..020de5d3aae9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteMacro.java @@ -29,6 +29,6 @@ public class CompleteMacro extends BaseCompleteMacro { protected void invokeCompletionHandler(Project project, Editor editor) { new CodeCompletionHandlerBase(CompletionType.BASIC, ApplicationManager.getApplication().isUnitTestMode(), false, true) - .invokeCompletion(project, editor, 1, false); + .invokeCompletion(project, editor, 1); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java index 2936bb697bd2..90018da3a772 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/macro/CompleteSmartMacro.java @@ -27,6 +27,6 @@ public class CompleteSmartMacro extends BaseCompleteMacro { } protected void invokeCompletionHandler(Project project, Editor editor) { - new CodeCompletionHandlerBase(CompletionType.SMART).invokeCompletion(project, editor, 1, false); + new CodeCompletionHandlerBase(CompletionType.SMART).invokeCompletion(project, editor, 1); } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 70d44c53888f..06c0d2d3ddb2 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -300,7 +300,7 @@ public abstract class SpeedSearchBase extends SpeedSear if (!UIUtil.isReallyTypedEvent(e)) return; char c = e.getKeyChar(); - if (Character.isLetterOrDigit(c) || c == '_' || c == '*' || c == '/' || c == ':') { + if (Character.isLetterOrDigit(c) || c == '_' || c == '*' || c == '/' || c == ':' || c == '.' || c == '#') { manageSearchPopup(new SearchPopup(String.valueOf(c))); e.consume(); } diff --git a/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java b/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java index ef0108a05aa4..2f5f17c32b8c 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/util/NameUtilTest.java @@ -26,6 +26,7 @@ import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.util.ThrowableRunnable; import com.intellij.util.containers.CollectionFactory; +import com.intellij.util.text.Matcher; import org.jetbrains.annotations.NonNls; import java.util.ArrayList; @@ -120,8 +121,13 @@ public class NameUtilTest extends UsefulTestCase { assertMatches("foo bar", "fooGooBar"); assertMatches("foo bar", "fooGoo bar"); assertDoesntMatch(" b", "fbi"); - assertTrue(NameUtil.buildCompletionMatcher(" us", 0, true, true).matches("getUsage")); - assertTrue(NameUtil.buildCompletionMatcher(" us", 0, true, true).matches("getMyUsage")); + assertDoesntMatch(" for", "performAction"); + assertTrue(caseInsensitiveMatcher(" us").matches("getUsage")); + assertTrue(caseInsensitiveMatcher(" us").matches("getMyUsage")); + } + + private static Matcher caseInsensitiveMatcher(String pattern) { + return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE); } public void testStartDot() { @@ -194,11 +200,11 @@ public class NameUtilTest extends UsefulTestCase { } public void testLowerCaseWords() throws Exception { - assertTrue(matches("uct", "unit_controller_test", true)); - assertTrue(matches("unictest", "unit_controller_test", true)); - assertTrue(matches("uc", "unit_controller_test", true)); - assertFalse(matches("nc", "unit_controller_test", true)); - assertFalse(matches("utc", "unit_controller_test", true)); + assertTrue(matches("uct", "unit_controller_test")); + assertTrue(matches("unictest", "unit_controller_test")); + assertTrue(matches("uc", "unit_controller_test")); + assertFalse(matches("nc", "unit_controller_test")); + assertFalse(matches("utc", "unit_controller_test")); } public void testObjectiveCCases() throws Exception { @@ -221,9 +227,9 @@ public class NameUtilTest extends UsefulTestCase { assertMatches("*Git*", "AtpGenerationItem"); assertMatches("Collec*Util*", "CollectionUtils"); assertMatches("Collec*Util*", "CollectionUtilsTest"); - assertTrue(NameUtil.buildCompletionMatcher("*us", 0, true, true).matches("usage")); - assertTrue(NameUtil.buildCompletionMatcher(" us", 0, true, true).matches("usage")); - assertTrue(NameUtil.buildCompletionMatcher(" fo. ba", 0, true, true).matches("getFoo.getBar")); + assertTrue(caseInsensitiveMatcher("*us").matches("usage")); + assertTrue(caseInsensitiveMatcher(" us").matches("usage")); + assertTrue(caseInsensitiveMatcher(" fo. ba").matches("getFoo.getBar")); assertMatches(" File. sepa", "File.separator"); assertMatches(" File. sepa", "File._separator"); assertMatches(" File. _sepa", "File._separator"); @@ -231,32 +237,35 @@ public class NameUtilTest extends UsefulTestCase { } public void testMiddleMatchingFirstLetterSensitive() { - assertTrue(NameUtil.buildCompletionMatcher(" cl", 1, true, true).matches("getClass")); - assertTrue(NameUtil.buildCompletionMatcher(" EUC-", 1, true, true).matches("x-EUC-TW")); - assertTrue(NameUtil.buildCompletionMatcher(" a", 1, true, true).matches("aaa")); - assertFalse(NameUtil.buildCompletionMatcher(" a", 1, true, true).matches("Aaa")); - assertFalse(NameUtil.buildCompletionMatcher(" a", 1, true, true).matches("Aaa")); - assertFalse(NameUtil.buildCompletionMatcher(" _bl", 1, true, true).matches("_top")); + assertTrue(firstLetterMatcher(" cl").matches("getClass")); + assertTrue(firstLetterMatcher(" EUC-").matches("x-EUC-TW")); + assertTrue(firstLetterMatcher(" a").matches("aaa")); + assertFalse(firstLetterMatcher(" a").matches("Aaa")); + assertFalse(firstLetterMatcher(" a").matches("Aaa")); + assertFalse(firstLetterMatcher(" _bl").matches("_top")); + } + + private static Matcher firstLetterMatcher(String pattern) { + return NameUtil.buildMatcher(pattern, NameUtil.MatchingCaseSensitivity.FIRST_LETTER); } public void testSpaceInCompletionPrefix() throws Exception { - assertTrue(NameUtil.buildCompletionMatcher("create ", 0, true, true).matches("create module")); + assertTrue(caseInsensitiveMatcher("create ").matches("create module")); } public void testLong() throws Exception { - assertTrue(matches("Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqual", "Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqualsIntellijIdeaRulezzz", false)); + assertTrue(matches("Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqual", "Product.findByDateAndNameGreaterThanEqualsAndQualityGreaterThanEqualsIntellijIdeaRulezzz")); } private static void assertMatches(@NonNls String pattern, @NonNls String name) { - assertTrue(matches(pattern, name, false)); + assertTrue(matches(pattern, name)); } private static void assertDoesntMatch(@NonNls String pattern, @NonNls String name) { - assertFalse(matches(pattern, name, false)); + assertFalse(matches(pattern, name)); } - private static boolean matches(@NonNls final String pattern, @NonNls final String name, final boolean lowerCaseWords) { - //System.out.println("\n--- " + name + " " + lowerCaseWords); - return NameUtil.buildMatcher(pattern, 0, true, true, lowerCaseWords).matches(name); + private static boolean matches(@NonNls final String pattern, @NonNls final String name) { + return caseInsensitiveMatcher(pattern).matches(name); } public void testLowerCaseHumps() { @@ -380,6 +389,7 @@ public class NameUtilTest extends UsefulTestCase { } public void testPreferStartMatchToMiddleMatch() { + assertPreference(" fb", "FooBar", "_fooBar", NameUtil.MatchingCaseSensitivity.NONE); assertPreference("*foo", "barFoo", "foobar"); assertPreference("*f", "barfoo", "barFoo"); assertPreference("*f", "barfoo", "foo"); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 74f21c4e530d..0d92f7d818d9 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -941,7 +941,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } }; Editor editor = getCompletionEditor(); - handler.invokeCompletion(getProject(), editor, invocationCount, false); + handler.invokeCompletion(getProject(), editor, invocationCount); PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); // to compare with file text } }, null, null); diff --git a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java index fcac227f07d9..59919fd3e0d0 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java +++ b/platform/util/src/com/intellij/psi/codeStyle/MinusculeMatcher.java @@ -269,18 +269,31 @@ public class MinusculeMatcher implements Matcher { fragmentCount++; } + if (first == null) { + return 0; + } + int commonStart = 0; while (commonStart < name.length() && commonStart < myPattern.length && name.charAt(commonStart) == myPattern[commonStart]) { commonStart++; } - boolean prefixMatching = first != null && first.getStartOffset() == 0; - boolean middleWordStart = first != null && first.getStartOffset() > 0 && NameUtil.isWordStart(name, first.getStartOffset()); - int startIndex = first != null ? first.getStartOffset() : 42; + int startIndex = first.getStartOffset(); + boolean prefixMatching = isStartMatch(name, startIndex); + boolean middleWordStart = !prefixMatching && NameUtil.isWordStart(name, first.getStartOffset()); return -fragmentCount + matchingCase * 10 + commonStart - startIndex + (prefixMatching ? 2 : middleWordStart ? 1 : 0) * 100; } + public static boolean isStartMatch(String name, int startIndex) { + for (int i = 0; i < startIndex; i++) { + if (!NameUtil.isWordSeparator(name.charAt(i))) { + return false; + } + } + return true; + } + @Override public boolean matches(String name) { return matchingFragments(name) != null; diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 5725e6460a48..600a9cf1852c 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -358,7 +358,7 @@ public class NameUtil { } return i - 1; } - while (i < text.length() && !isWordStart(text, i) && !!Character.isLetterOrDigit(text.charAt(i))) { + while (i < text.length() && !isWordStart(text, i) && Character.isLetterOrDigit(text.charAt(i))) { i++; } return i; @@ -384,6 +384,8 @@ public class NameUtil { boolean matches(String name); } + @SuppressWarnings("UnusedDeclaration") + @Deprecated public static com.intellij.util.text.Matcher buildCompletionMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; return buildMatcher(pattern, options); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index e956617d9901..d76c850c98e0 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -126,6 +126,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java index aad90873f1a1..07961dd39581 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrTypeConverter.java @@ -1,6 +1,8 @@ package org.jetbrains.plugins.groovy.lang.psi; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiClassType; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,4 +21,20 @@ public abstract class GrTypeConverter { @Nullable public abstract Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context); + protected static boolean resolvesTo(PsiType type, String fqn) { + if (type instanceof PsiClassType) { + final PsiClass resolved = ((PsiClassType)type).resolve(); + return resolved != null && fqn.equals(resolved.getQualifiedName()); + } + return false; + } + + protected static boolean isEnum(PsiType type) { + if (type instanceof PsiClassType) { + final PsiClass resolved = ((PsiClassType)type).resolve(); + return resolved != null && resolved.isEnum(); + } + + return false; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrStringTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrStringTypeConverter.java new file mode 100644 index 000000000000..d5c9b30e8392 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrStringTypeConverter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2012 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 org.jetbrains.plugins.groovy.lang.psi.impl.types; + +import com.intellij.psi.PsiType; +import com.intellij.psi.util.InheritanceUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; +import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; + +import static com.intellij.psi.CommonClassNames.JAVA_LANG_BOOLEAN; +import static com.intellij.psi.CommonClassNames.JAVA_LANG_CLASS; +import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_GSTRING; +import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.JAVA_LANG_CHAR_SEQUENCE; + +/** + * @author Max Medvedev + */ +public class GrStringTypeConverter extends GrTypeConverter { + @Override + public Boolean isConvertible(@NotNull PsiType lType, @NotNull PsiType rType, @NotNull GroovyPsiElement context) { + if (isMethodCallConversion(context)) return null; + if (!GroovyConfigUtils.getInstance().isVersionAtLeast(context, GroovyConfigUtils.GROOVY1_8)) return null; + if (!(InheritanceUtil.isInheritor(rType, JAVA_LANG_CHAR_SEQUENCE) || InheritanceUtil.isInheritor(rType, GROOVY_LANG_GSTRING))) { + return null; + } + + if (lType == PsiType.BOOLEAN || resolvesTo(lType, JAVA_LANG_BOOLEAN)) return true; + if (resolvesTo(lType, JAVA_LANG_CLASS)) return true; + if (isEnum(lType)) return true; + + return null; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java index 2e4e919fecb8..8749f37ee5d2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureParameterEnhancer.java @@ -23,6 +23,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import java.util.Map; import java.util.Set; +import static com.intellij.psi.CommonClassNames.JAVA_IO_FILE; import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.skipParentheses; /** @@ -44,13 +45,13 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { simpleTypes.put("withDataOutputStream", "java.io.DataOutputStream"); simpleTypes.put("withDataInputStream", "java.io.DataInputStream"); simpleTypes.put("eachLine", "java.lang.String"); - simpleTypes.put("eachFile", "java.io.File"); - simpleTypes.put("eachDir", "java.io.File"); - simpleTypes.put("eachFileRecurse", "java.io.File"); - simpleTypes.put("traverse", "java.io.File"); - simpleTypes.put("eachDirRecurse", "java.io.File"); - simpleTypes.put("eachFileMatch", "java.io.File"); - simpleTypes.put("eachDirMatch", "java.io.File"); + simpleTypes.put("eachFile", JAVA_IO_FILE); + simpleTypes.put("eachDir", JAVA_IO_FILE); + simpleTypes.put("eachFileRecurse", JAVA_IO_FILE); + simpleTypes.put("traverse", JAVA_IO_FILE); + simpleTypes.put("eachDirRecurse", JAVA_IO_FILE); + simpleTypes.put("eachFileMatch", JAVA_IO_FILE); + simpleTypes.put("eachDirMatch", JAVA_IO_FILE); simpleTypes.put("withReader", "java.io.Reader"); simpleTypes.put("withWriter", "java.io.Writer"); simpleTypes.put("withWriterAppend", "java.io.Writer"); @@ -259,7 +260,7 @@ public class ClosureParameterEnhancer extends AbstractClosureParameterEnhancer { return res; } - if (TypesUtil.isClassType(iterType, CommonClassNames.JAVA_LANG_STRING) || TypesUtil.isClassType(iterType, "java.io.File")) { + if (TypesUtil.isClassType(iterType, CommonClassNames.JAVA_LANG_STRING) || TypesUtil.isClassType(iterType, JAVA_IO_FILE)) { return TypesUtil.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, context); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java index d939e0f36379..3c481fe510da 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java @@ -54,6 +54,7 @@ public final class GroovyCommonClassNames { @NonNls public static final String GROOVY_TRANSFORM_COMPILE_STATIC = "groovy.transform.CompileStatic"; @NonNls public static final String GROOVY_TRANSFORM_TYPE_CHECKED = "groovy.transform.TypeChecked"; @NonNls public static final String GROOVY_TRANSFORM_TYPE_CHECKING_MODE = "groovy.transform.TypeCheckingMode"; + @NonNls public static final String JAVA_LANG_CHAR_SEQUENCE = "java.lang.CharSequence"; private GroovyCommonClassNames() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy index dc92c267363d..5b9058c1e562 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy @@ -604,11 +604,11 @@ println new Bar().zzz } class GppProjectDescriptor extends DefaultLightProjectDescriptor { - static def instance = new GppProjectDescriptor() + public static final instance = new GppProjectDescriptor() @Override public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { - final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY++").getModifiableModel(); + final Library.ModifiableModel modifiableModel = model.moduleLibraryTable.createLibrary("GROOVY++").modifiableModel; modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.absoluteTestDataPath + "mockGroovypp/groovypp-0.9.0_1.8.2.jar!/"), OrderRootType.CLASSES) modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"), OrderRootType.CLASSES); modifiableModel.commit();