From 78964997d997fe0bf204d284731d5ca00e34a9ad Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 13 Feb 2011 13:50:42 +0300 Subject: [PATCH 01/95] IDEA-65051 Groovy: Imports: Classes from current package should have priority than classes imported using '*'. --- .../groovy/lang/psi/impl/GroovyFileImpl.java | 23 +++++++++++++++---- .../lang/resolve/ResolveClassTest.groovy | 6 +++++ .../class/preferClassFromCurPackage/a.groovy | 6 +++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 plugins/groovy/testdata/resolve/class/preferClassFromCurPackage/a.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java index d728756bb6e2..3bdbbbaca2d6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyFileImpl.java @@ -145,11 +145,7 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { } }; GrImportStatement[] importStatements = getImportStatements(); - for (int i = importStatements.length - 1; i >= 0; i--) { - if (!importStatements[i].processDeclarations(importProcessor, state, lastParent, place)) { - return false; - } - } + if (!processImports(state, lastParent, place, importProcessor, importStatements, false)) return false; if (processClasses && !processImplicitImports(processor, state, lastParent, place)) { return false; @@ -173,6 +169,8 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { } } + if (!processImports(state, lastParent, place, importProcessor, importStatements, true)) return false; + if (lastParent != null && !(lastParent instanceof GrTypeDefinition) && scriptClass != null) { if (!ResolveUtil.processElement(processor, getSyntheticArgsParameter(), state)) return false; } @@ -180,6 +178,21 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile { return true; } + private static boolean processImports(ResolveState state, + PsiElement lastParent, + PsiElement place, + PsiScopeProcessor importProcessor, + GrImportStatement[] importStatements, boolean shouldProcessOnDemand) { + for (int i = importStatements.length - 1; i >= 0; i--) { + final GrImportStatement imp = importStatements[i]; + if (shouldProcessOnDemand != imp.isOnDemand()) continue; + if (!imp.processDeclarations(importProcessor, state, lastParent, place)) { + return false; + } + } + return true; + } + private boolean isImplicitlyImported(PsiElement element, String expectedName) { if (!(element instanceof PsiClass)) return false; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy index 022d571c23cf..1e30936c4e88 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveClassTest.groovy @@ -215,6 +215,12 @@ interface Super { assertEquals "C2", resolve("A.groovy").getName() } + void testPreferClassFromCurPackage() { + myFixture.addFileToProject "a/Cl.groovy", "package a; class Cl{}" + myFixture.addFileToProject "b/Cl.groovy", "package b; class Cl{}" + assertEquals "a.Cl", resolve("a.groovy").qualifiedName + } + private void doTest() { doTest(getTestName(true) + "/" + getTestName(false) + ".groovy"); } diff --git a/plugins/groovy/testdata/resolve/class/preferClassFromCurPackage/a.groovy b/plugins/groovy/testdata/resolve/class/preferClassFromCurPackage/a.groovy new file mode 100644 index 000000000000..4072f48b6e22 --- /dev/null +++ b/plugins/groovy/testdata/resolve/class/preferClassFromCurPackage/a.groovy @@ -0,0 +1,6 @@ +package a + +import b.* + + +new Cl() \ No newline at end of file From 587e9430c57a4496cc49eababd476dbe7184dbb0 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 13 Feb 2011 16:39:40 +0300 Subject: [PATCH 02/95] IDEA-64814 Move-refactoring import statements bug --- .../MoveClassHandler.java | 4 + .../MoveClassesOrPackagesProcessor.java | 5 +- .../MoveClassesOrPackagesUtil.java | 12 ++ .../MoveJavaClassHandler.java | 15 ++ .../move/MoveGroovyClassHandler.java | 140 +++++++++++++++- .../refactoring/move/MoveGroovyClassUtil.java | 151 ------------------ .../refactoring/move/GroovyMoveClassTest.java | 8 +- .../twoClasses/after/p1/dummy.groovy | 0 .../moveClass/twoClasses/after/p2/C1.groovy | 7 + .../moveClass/twoClasses/after/p2/C2.groovy | 7 + .../twoClasses/after/p2/dummy.groovy | 0 .../moveClass/twoClasses/before/p1/C1.groovy | 7 + .../moveClass/twoClasses/before/p1/C2.groovy | 7 + .../twoClasses/before/p1/dummy.groovy | 0 .../twoClasses/before/p2/dummy.groovy | 0 15 files changed, 203 insertions(+), 160 deletions(-) delete mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassUtil.java create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p1/dummy.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C1.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C2.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/dummy.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C1.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C2.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/dummy.groovy create mode 100644 plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p2/dummy.groovy diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassHandler.java index 8840f1fc3c24..7d843351b0ad 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassHandler.java @@ -28,6 +28,10 @@ import org.jetbrains.annotations.Nullable; public interface MoveClassHandler { ExtensionPointName EP_NAME = new ExtensionPointName("com.intellij.refactoring.moveClassHandler"); + void prepareMove(@NotNull PsiClass aClass); + + void finishMoveClass(@NotNull PsiClass aClass); + /** * @return null if it cannot move aClass */ diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java index d0349e634db4..a176951ac42c 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java @@ -15,7 +15,6 @@ */ package com.intellij.refactoring.move.moveClassesOrPackages; -import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -448,7 +447,7 @@ public class MoveClassesOrPackagesProcessor extends BaseRefactoringProcessor { element = newElement; } else if (element instanceof PsiClass) { - ChangeContextUtil.encodeContextInfo(element, true); + MoveClassesOrPackagesUtil.prepareMoveClass((PsiClass)element); final PsiClass newElement = MoveClassesOrPackagesUtil.doMoveClass((PsiClass)element, myMoveDestination.getTargetDirectory(element.getContainingFile())); oldToNewElementsMapping.put(element, newElement); element = newElement; @@ -461,7 +460,7 @@ public class MoveClassesOrPackagesProcessor extends BaseRefactoringProcessor { for (PsiElement element : myElementsToMove) { if (element instanceof PsiClass) { - ChangeContextUtil.decodeContextInfo(element, null, null); + MoveClassesOrPackagesUtil.finishMoveClass((PsiClass)element); } } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java index 90494fe0d2f0..931917201cb6 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesUtil.java @@ -207,6 +207,18 @@ public class MoveClassesOrPackagesUtil { } } + public static void prepareMoveClass(PsiClass aClass) { + for (MoveClassHandler handler : MoveClassHandler.EP_NAME.getExtensions()) { + handler.prepareMove(aClass); + } + } + + public static void finishMoveClass(PsiClass aClass) { + for (MoveClassHandler handler : MoveClassHandler.EP_NAME.getExtensions()) { + handler.finishMoveClass(aClass); + } + } + // Does not process non-code usages! public static PsiClass doMoveClass(PsiClass aClass, PsiDirectory moveDestination) throws IncorrectOperationException { PsiClass newClass; diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java index 585544210885..d5153e6e8f46 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaClassHandler.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.move.moveClassesOrPackages; +import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.psi.*; @@ -32,6 +33,20 @@ import java.util.Set; public class MoveJavaClassHandler implements MoveClassHandler { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.move.moveClassesOrPackages.MoveJavaClassHandler"); + @Override + public void finishMoveClass(@NotNull PsiClass aClass) { + if (aClass.getContainingFile() instanceof PsiJavaFile) { + ChangeContextUtil.decodeContextInfo(aClass, null, null); + } + } + + @Override + public void prepareMove(@NotNull PsiClass aClass) { + if (aClass.getContainingFile() instanceof PsiJavaFile) { + ChangeContextUtil.encodeContextInfo(aClass, true); + } + } + public PsiClass doMoveClass(@NotNull final PsiClass aClass, @NotNull PsiDirectory moveDestination) throws IncorrectOperationException { PsiFile file = aClass.getContainingFile(); final PsiPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java index 16458a4934ee..41f9fcc1cd06 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java @@ -16,22 +16,115 @@ package org.jetbrains.plugins.groovy.refactoring.move; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiFile; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.Factory; +import com.intellij.psi.impl.source.tree.TreeElement; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.refactoring.PackageWrapper; +import com.intellij.refactoring.move.moveClassesOrPackages.AutocreatingSingleSourceRootMoveDestination; import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.actions.GroovyTemplatesFactory; +import org.jetbrains.plugins.groovy.actions.NewGroovyActionBase; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; +import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil; /** * @author Maxim.Medvedev */ public class MoveGroovyClassHandler implements MoveClassHandler { public PsiClass doMoveClass(@NotNull PsiClass aClass, @NotNull PsiDirectory moveDestination) throws IncorrectOperationException { - return MoveGroovyClassUtil.moveGroovyClass(aClass, moveDestination); + if (!aClass.getLanguage().equals(GroovyFileType.GROOVY_LANGUAGE)) return null; + PsiFile file = aClass.getContainingFile(); + if (!(file instanceof GroovyFile)) return null; + + final PsiPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); + assert newPackage != null; + + PsiClass newClass = null; + + if (aClass instanceof GroovyScriptClass) { + PackageWrapper targetPackage = new PackageWrapper(aClass.getManager(), newPackage.getQualifiedName()); + final VirtualFile sourceRoot = + ProjectRootManager.getInstance(aClass.getProject()).getFileIndex().getSourceRootForFile(moveDestination.getVirtualFile()); + assert sourceRoot != null; + + final AutocreatingSingleSourceRootMoveDestination destination = + new AutocreatingSingleSourceRootMoveDestination(targetPackage, sourceRoot); + new MoveGroovyScriptProcessor(aClass.getProject(), new PsiElement[]{file}, destination, true, true, null).run(); + } + else { + //GroovyChangeContextUtil.encodeContextInfo(aClass); + if (((GroovyFile)file).getClasses().length > 1) { + correctSelfReferences(aClass, newPackage); + String modifiersText = null; + if (newPackage.getQualifiedName().equals(((GroovyFile)file).getPackageName())) { + final GrPackageDefinition packageDefinition = ((GroovyFile)file).getPackageDefinition(); + if (packageDefinition != null) { + final PsiModifierList modifierList = packageDefinition.getModifierList(); + if (modifierList != null) { + modifiersText = modifierList.getText(); + } + } + } + final PsiClass created = ((GroovyFile)GroovyTemplatesFactory + .createFromTemplate(moveDestination, aClass.getName(), aClass.getName() + NewGroovyActionBase.GROOVY_EXTENSION, + "GroovyClass.groovy")).getClasses()[0]; + PsiDocComment docComment = aClass.getDocComment(); + if (docComment != null) { + final PsiDocComment createdDocComment = created.getDocComment(); + if (createdDocComment != null) { + createdDocComment.replace(docComment); + } + else { + created.getContainingFile().addBefore(docComment, created); + } + docComment.delete(); + } + newClass = (PsiClass)created.replace(aClass); + if (modifiersText != null) { + final GrPackageDefinition newPackageDefinition = (GrPackageDefinition)GroovyPsiElementFactory.getInstance(aClass.getProject()) + .createTopElementFromText(modifiersText + " package " + newPackage.getQualifiedName()); + ((GroovyFile)newClass.getContainingFile()).setPackage(newPackageDefinition); + } + correctOldClassReferences(newClass, aClass); + aClass.delete(); + } + else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) != null) { + // moving second of two classes which were in the same file to a different directory (IDEADEV-3089) + correctSelfReferences(aClass, newPackage); + PsiFile newFile = moveDestination.findFile(file.getName()); + TreeElement enter = Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, aClass.getManager()); + newFile.getNode().addChild(enter); + newClass = (GrTypeDefinition)newFile.add(aClass); + aClass.delete(); + } + else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) == null) { + if (!moveDestination.equals(file.getContainingDirectory())) { + aClass.getManager().moveFile(file, moveDestination); + newClass = ((GroovyFile)file).getClasses()[0]; + if (!newPackage.getQualifiedName().equals(((GroovyFile)file).getPackageName())) { + ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); + } + } + } + //if (newClass != null) GroovyChangeContextUtil.decodeContextInfo(newClass, null, null); + } + return newClass; } @Nullable @@ -41,4 +134,43 @@ public class MoveGroovyClassHandler implements MoveClassHandler { return ((GroovyFile)file).getClasses().length > 1 ? clazz.getName() + "." + GroovyFileType.DEFAULT_EXTENSION : file.getName(); } + @Override + public void prepareMove(@NotNull PsiClass aClass) { + if (aClass.getContainingClass() instanceof GroovyFileBase) { + GroovyChangeContextUtil.encodeContextInfo(getRealElement(aClass)); + } + } + + @Override + public void finishMoveClass(@NotNull PsiClass aClass) { + if (aClass.getContainingClass() instanceof GroovyFileBase) { + GroovyChangeContextUtil.decodeContextInfo(getRealElement(aClass), null, null); + } + } + + private static PsiElement getRealElement(PsiClass aClass) { + return aClass instanceof GroovyScriptClass ? aClass.getContainingFile() : aClass; + } + + private static void correctOldClassReferences(final PsiClass newClass, final PsiClass oldClass) { + for (PsiReference reference : ReferencesSearch.search(oldClass, new LocalSearchScope(newClass)).findAll()) { + reference.bindToElement(newClass); + } + } + + private static void correctSelfReferences(final PsiClass aClass, final PsiPackage newContainingPackage) { + final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(aClass.getContainingFile().getContainingDirectory()); + if (aPackage == null) { + return; + } + + for (PsiReference reference : ReferencesSearch.search(aClass, new LocalSearchScope(aClass)).findAll()) { + if (reference instanceof GrCodeReferenceElement) { + final GrCodeReferenceElement qualifier = ((GrCodeReferenceElement)reference).getQualifier(); + if (qualifier != null) { + qualifier.bindToElement(newContainingPackage); + } + } + } + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassUtil.java deleted file mode 100644 index a1dae4eca300..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassUtil.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2000-2010 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.refactoring.move; - -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.tree.Factory; -import com.intellij.psi.impl.source.tree.TreeElement; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.refactoring.PackageWrapper; -import com.intellij.refactoring.move.moveClassesOrPackages.AutocreatingSingleSourceRootMoveDestination; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.actions.GroovyTemplatesFactory; -import org.jetbrains.plugins.groovy.actions.NewGroovyActionBase; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; -import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil; - -/** - * @author Maxim.Medvedev - */ -public class MoveGroovyClassUtil { - private MoveGroovyClassUtil() { - } - - @Nullable - public static PsiClass moveGroovyClass(@NotNull PsiClass aClass, @NotNull PsiDirectory moveDestination) { - if (!aClass.getLanguage().equals(GroovyFileType.GROOVY_LANGUAGE)) return null; - PsiFile file = aClass.getContainingFile(); - if (!(file instanceof GroovyFile)) return null; - - final PsiPackage newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination); - assert newPackage != null; - - PsiClass newClass = null; - - if (aClass instanceof GroovyScriptClass) { - PackageWrapper targetPackage = new PackageWrapper(aClass.getManager(), newPackage.getQualifiedName()); - final VirtualFile sourceRoot = - ProjectRootManager.getInstance(aClass.getProject()).getFileIndex().getSourceRootForFile(moveDestination.getVirtualFile()); - assert sourceRoot != null; - - final AutocreatingSingleSourceRootMoveDestination destination = - new AutocreatingSingleSourceRootMoveDestination(targetPackage, sourceRoot); - new MoveGroovyScriptProcessor(aClass.getProject(), new PsiElement[]{file}, destination, true, true, null).run(); - } - else { - GroovyChangeContextUtil.encodeContextInfo(aClass); - if (((GroovyFile)file).getClasses().length > 1) { - correctSelfReferences(aClass, newPackage); - String modifiersText = null; - if (newPackage.getQualifiedName().equals(((GroovyFile)file).getPackageName())) { - final GrPackageDefinition packageDefinition = ((GroovyFile)file).getPackageDefinition(); - if (packageDefinition != null) { - final PsiModifierList modifierList = packageDefinition.getModifierList(); - if (modifierList != null) { - modifiersText = modifierList.getText(); - } - } - } - final PsiClass created = ((GroovyFile)GroovyTemplatesFactory - .createFromTemplate(moveDestination, aClass.getName(), aClass.getName() + NewGroovyActionBase.GROOVY_EXTENSION, - "GroovyClass.groovy")).getClasses()[0]; - PsiDocComment docComment = aClass.getDocComment(); - if (docComment != null) { - final PsiDocComment createdDocComment = created.getDocComment(); - if (createdDocComment != null) { - createdDocComment.replace(docComment); - } - else { - created.getContainingFile().addBefore(docComment, created); - } - docComment.delete(); - } - newClass = (PsiClass)created.replace(aClass); - if (modifiersText != null) { - final GrPackageDefinition newPackageDefinition = (GrPackageDefinition)GroovyPsiElementFactory.getInstance(aClass.getProject()) - .createTopElementFromText(modifiersText + " package " + newPackage.getQualifiedName()); - ((GroovyFile)newClass.getContainingFile()).setPackage(newPackageDefinition); - } - correctOldClassReferences(newClass, aClass); - aClass.delete(); - } - else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) != null) { - // moving second of two classes which were in the same file to a different directory (IDEADEV-3089) - correctSelfReferences(aClass, newPackage); - PsiFile newFile = moveDestination.findFile(file.getName()); - TreeElement enter = Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, aClass.getManager()); - newFile.getNode().addChild(enter); - newClass = (GrTypeDefinition)newFile.add(aClass); - aClass.delete(); - } - else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) == null) { - if (!moveDestination.equals(file.getContainingDirectory())) { - aClass.getManager().moveFile(file, moveDestination); - newClass = ((GroovyFile)file).getClasses()[0]; - if (!newPackage.getQualifiedName().equals(((GroovyFile)file).getPackageName())) { - ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); - } - } - } - if (newClass != null) GroovyChangeContextUtil.decodeContextInfo(newClass, null, null); - } - return newClass; - } - - private static void correctOldClassReferences(final PsiClass newClass, final PsiClass oldClass) { - for (PsiReference reference : ReferencesSearch.search(oldClass, new LocalSearchScope(newClass)).findAll()) { - reference.bindToElement(newClass); - } - } - - private static void correctSelfReferences(final PsiClass aClass, final PsiPackage newContainingPackage) { - final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(aClass.getContainingFile().getContainingDirectory()); - if (aPackage == null) { - return; - } - - for (PsiReference reference : ReferencesSearch.search(aClass, new LocalSearchScope(aClass)).findAll()) { - if (reference instanceof GrCodeReferenceElement) { - final GrCodeReferenceElement qualifier = ((GrCodeReferenceElement)reference).getQualifier(); - if (qualifier != null) { - qualifier.bindToElement(newContainingPackage); - } - } - } - } -} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java index 1ae43ed356aa..da4b71bc46d4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java @@ -122,7 +122,11 @@ public class GroovyMoveClassTest extends LightCodeInsightFixtureTestCase { doTest("script", new String[]{"pack1.Xx"}, "pack2"); } - private void performAction(String[] classNames, String newPackageName) throws Exception { + public void testTwoClasses() { + doTest("twoClasses", new String[] {"p1.C1", "p1.C2"}, "p2"); + } + + private void performAction(String[] classNames, String newPackageName) { final PsiClass[] classes = new PsiClass[classNames.length]; for (int i = 0; i < classes.length; i++) { String className = classNames[i]; @@ -153,7 +157,7 @@ public class GroovyMoveClassTest extends LightCodeInsightFixtureTestCase { FileDocumentManager.getInstance().saveAllDocuments(); } - private void doTest(String testName, String[] classNames, String newPackageName) throws Exception { + private void doTest(String testName, String[] classNames, String newPackageName) { final VirtualFile actualRoot = myFixture.copyDirectoryToProject(testName + "/before", ""); performAction(classNames, newPackageName); diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p1/dummy.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p1/dummy.groovy new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C1.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C1.groovy new file mode 100644 index 000000000000..88877aa953a3 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C1.groovy @@ -0,0 +1,7 @@ +package p2 + +class C1 { + def foo(){ + new C2() + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C2.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C2.groovy new file mode 100644 index 000000000000..ac529498ef43 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/C2.groovy @@ -0,0 +1,7 @@ +package p2 + +class C2 { + def foo() { + new C1() + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/dummy.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/after/p2/dummy.groovy new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C1.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C1.groovy new file mode 100644 index 000000000000..3c3e9e6de8cd --- /dev/null +++ b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C1.groovy @@ -0,0 +1,7 @@ +package p1 + +class C1 { + def foo(){ + new C2() + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C2.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C2.groovy new file mode 100644 index 000000000000..d478164edd53 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/C2.groovy @@ -0,0 +1,7 @@ +package p1 + +class C2 { + def foo() { + new C1() + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/dummy.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p1/dummy.groovy new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p2/dummy.groovy b/plugins/groovy/testdata/refactoring/move/moveClass/twoClasses/before/p2/dummy.groovy new file mode 100644 index 000000000000..e69de29bb2d1 From 5436cbad013bc0542b53f82391613df6915e26f8 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 1 Mar 2011 16:58:08 +0100 Subject: [PATCH 03/95] inplace introduce parameter: move occurrences chooser to balloon --- .../InplaceIntroduceParameterPopup.java | 170 +++++++++++------- .../IntroduceParameterDialog.java | 62 +------ .../IntroduceParameterHandler.java | 26 +-- .../IntroduceParameterSettingsUI.java | 66 ++++++- 4 files changed, 196 insertions(+), 128 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 895aa80e2892..cce7d69e081a 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -17,6 +17,8 @@ package com.intellij.refactoring.introduceParameter; import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.codeInsight.intention.impl.TypeExpression; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.ide.IdeTooltipManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; @@ -33,17 +35,17 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.introduceVariable.OccurrencesChooser; import com.intellij.refactoring.introduceVariable.VariableInplaceIntroducer; import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; -import com.intellij.refactoring.ui.NameSuggestionsGenerator; +import com.intellij.refactoring.ui.TypeSelectorManager; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; -import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.awt.RelativePoint; import com.intellij.usageView.UsageInfo; import gnu.trove.TIntArrayList; @@ -61,30 +63,30 @@ import java.util.List; * Date: 2/25/11 */ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { - private JCheckBox myDelegateCb; private Balloon myBalloon; private final Project myProject; private final Editor myEditor; private final TypeSelectorManagerImpl myTypeSelectorManager; - private final NameSuggestionsGenerator myNameSuggestionsGenerator; - private final PsiExpression myExpr; + private PsiExpression myExpr; private final PsiLocalVariable myLocalVar; private final PsiMethod myMethod; private final PsiMethod myMethodToSearchFor; private final PsiExpression[] myOccurrences; private final boolean myMustBeFinal; - private final RangeMarker myExprMarker; - private final List myOccurrenceMarkers; + private RangeMarker myExprMarker; + private List myOccurrenceMarkers; private final JPanel myWholePanel; + private int myParameterIndex = -1; + private String myParameterName; + private final String myExprText; InplaceIntroduceParameterPopup(final Project project, final Editor editor, final List classMemberRefs, final TypeSelectorManagerImpl typeSelectorManager, - final NameSuggestionsGenerator nameSuggestionsGenerator, final PsiExpression expr, final PsiLocalVariable localVar, final PsiMethod method, @@ -96,7 +98,6 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { myProject = project; myEditor = editor; myTypeSelectorManager = typeSelectorManager; - myNameSuggestionsGenerator = nameSuggestionsGenerator; myExpr = expr; myLocalVar = localVar; myMethod = method; @@ -104,14 +105,17 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { myOccurrences = occurrences; myMustBeFinal = mustBeFinal; myExprMarker = expr != null ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null; - myOccurrenceMarkers = new ArrayList(); + myExprText = myExpr != null ? myExpr.getText() : null; myWholePanel = new JPanel(new GridBagLayout()); myWholePanel.setBorder(BorderFactory.createTitledBorder(IntroduceParameterHandler.REFACTORING_NAME)); - myDelegateCb = new NonFocusableCheckBox(RefactoringBundle.message("delegation.panel.delegate.via.overloading.method")); final GridBagConstraints gc = new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 0), 0, 0); - myWholePanel.add(myDelegateCb, gc); + + if (myOccurrences.length > 1 && !myIsInvokedOnDeclaration) { + gc.gridy++; + createOccurrencesCb(gc, myWholePanel, myOccurrences.length); + } final JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance(); createLocalVariablePanel(gc, myWholePanel, settings); createRemoveParamsPanel(gc, myWholePanel); @@ -119,52 +123,51 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { gc.gridy++; myWholePanel.add(createReplaceFieldsWithGettersPanel(), gc); } + gc.gridy++; + createDelegateCb(gc, myWholePanel); } void inplaceIntroduceParameter() { - final LinkedHashMap occurrencesMap = - new LinkedHashMap(); - - for (PsiExpression occurrence : myOccurrences) { - myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); - } - - OccurrencesChooser.fillChoices(myExpr, myOccurrences, occurrencesMap); - new OccurrencesChooser(myEditor).showChooser(new IntroduceParameterPass(), occurrencesMap); + new IntroduceParameterPass().pass(OccurrencesChooser.ReplaceChoice.NO); } @Override - protected void updateControls(JCheckBox[] removeParamsCb) { + protected TypeSelectorManager getTypeSelectionManager() { + return myTypeSelectorManager; + } + + private PsiParameter getParameter() { + return myMethod.getParameterList().getParameters()[myParameterIndex]; + } + + public List getOccurrenceMarkers() { + if (myOccurrenceMarkers == null) { + myOccurrenceMarkers = new ArrayList(); + for (PsiExpression occurrence : myOccurrences) { + myOccurrenceMarkers.add(myEditor.getDocument().createRangeMarker(occurrence.getTextRange())); + } + } + return myOccurrenceMarkers; } private class ParameterInplaceIntroducer extends VariableInplaceIntroducer { - private String myParameterName; + private SmartTypePointer myParameterTypePointer; private SmartTypePointer myDefaultParameterTypePointer; - private final PsiParameter myParameter; - private int myParameterIndex; - private PsiExpression myExpression; - private final OccurrencesChooser.ReplaceChoice myReplaceChoice; private boolean myFinal; - private final String myExprText; - public ParameterInplaceIntroducer(PsiParameter parameter, - OccurrencesChooser.ReplaceChoice replaceChoice) { + public ParameterInplaceIntroducer(PsiParameter parameter) { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, parameter, myMustBeFinal, - myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, myOccurrenceMarkers); - myParameter = parameter; - myReplaceChoice = replaceChoice; - myExprText = myExpr != null ? myExpr.getText() : null; - myParameterIndex = myMethod.getParameterList().getParameterIndex(myParameter); + myTypeSelectorManager.getTypesForAll().length > 1, myExprMarker, getOccurrenceMarkers()); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(parameter.getType()); } @Override protected PsiVariable getVariable() { - return myMethod.getParameterList().getParameters()[myParameterIndex]; + return getParameter(); } @Override @@ -184,8 +187,12 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { @Override protected void collectAdditionalElementsToRename(boolean processTextOccurrences, List> stringUsages) { - for (PsiExpression expression : myOccurrences) { - stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); + if (isReplaceAllOccurences()) { + for (PsiExpression expression : myOccurrences) { + stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); + } + } else if (myExpr != null){ + stringUsages.add(Pair.create(myExpr, new TextRange(0, myExpr.getTextLength()))); } } @@ -202,9 +209,15 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { @NotNull HighlightManager highlightManager) { final TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - for (RangeMarker marker : myOccurrenceMarkers) { - final int startOffset = marker.getStartOffset(); - highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + myParameter.getName().length(), attributes, 0, highlighters, null); + final int variableNameLength = getVariable().getName().length(); + if (isReplaceAllOccurences()) { + for (RangeMarker marker : getOccurrenceMarkers()) { + final int startOffset = marker.getStartOffset(); + highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); + } + } else if (myExpr != null) { + final int startOffset = myExprMarker.getStartOffset(); + highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); } super.addHighlights(ranges, editor, highlighters, highlightManager); } @@ -222,7 +235,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { if (success) { boolean isDeleteLocalVariable = false; - PsiExpression parameterInitializer = myExpression; + PsiExpression parameterInitializer = myExpr; if (myLocalVar != null) { if (isUseInitializer()) { parameterInitializer = myLocalVar.getInitializer(); @@ -233,10 +246,10 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { final IntroduceParameterProcessor processor = new IntroduceParameterProcessor(myProject, myMethod, - myMethodToSearchFor, parameterInitializer, myExpression, + myMethodToSearchFor, parameterInitializer, myExpr, myLocalVar, isDeleteLocalVariable, myParameterName, - myReplaceChoice == OccurrencesChooser.ReplaceChoice.ALL, - getReplaceFieldsWithGetters(), myMustBeFinal || myFinal, myDelegateCb.isSelected(), + isReplaceAllOccurences(), + getReplaceFieldsWithGetters(), myMustBeFinal || myFinal, isGenerateDelegate(), myParameterTypePointer.getType(), parametersToRemove); processor.setPrepareSuccessfulSwingThreadCallback(new Runnable() { @@ -268,35 +281,50 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { public void finish() { super.finish(); myBalloon.hide(); - final PsiParameter psiParameter = myMethod.getParameterList().getParameters()[myParameterIndex]; - myParameterName = psiParameter.getName(); + final PsiParameter psiParameter = (PsiParameter)getVariable(); + LOG.assertTrue(psiParameter != null); myFinal = psiParameter.hasModifierProperty(PsiModifier.FINAL); myParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(psiParameter.getType()); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + myParameterName = psiParameter.getName(); ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { final PsiFile containingFile = myMethod.getContainingFile(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - myExpression = restoreExpression(containingFile, elementFactory, myExprMarker); - for (RangeMarker marker : myOccurrenceMarkers) { - if (myExprMarker != null && marker.getStartOffset() == myExprMarker.getStartOffset()) continue; - restoreExpression(containingFile, elementFactory, marker); + myExpr = restoreExpression(containingFile, psiParameter, elementFactory, myExprMarker); + if (myExpr != null) { + myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); } + final List occurrenceMarkers = getOccurrenceMarkers(); + for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { + RangeMarker marker = occurrenceMarkers.get(i); + if (myExprMarker != null && marker.getStartOffset() == myExprMarker.getStartOffset()) { + myOccurrences[i] = myExpr; + continue; + } + final PsiExpression psiExpression = restoreExpression(containingFile, psiParameter, elementFactory, marker); + if (psiExpression != null) { + myOccurrences[i] = psiExpression; + } + } + myOccurrenceMarkers = null; if (psiParameter.isValid()) { psiParameter.delete(); } } }); - } @Nullable - private PsiExpression restoreExpression(PsiFile containingFile, PsiElementFactory elementFactory, RangeMarker marker) { + private PsiExpression restoreExpression(PsiFile containingFile, + PsiParameter psiParameter, + PsiElementFactory elementFactory, + RangeMarker marker) { if (myExprText == null) return null; - if (myParameter == null || !myParameter.isValid()) return null; + if (psiParameter == null || !psiParameter.isValid()) return null; final PsiElement refVariableElement = containingFile.findElementAt(marker.getStartOffset()); final PsiExpression expression = PsiTreeUtil.getParentOfType(refVariableElement, PsiReferenceExpression.class); - if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() == myParameter) { + if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() == psiParameter) { return (PsiExpression)expression.replace(elementFactory.createExpressionFromText(myExprText, myMethod)); } return null; @@ -313,6 +341,17 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { return createFinals == null ? CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS : createFinals.booleanValue(); } + @Override + protected void updateControls(JCheckBox[] removeParamsCb) { + super.updateControls(removeParamsCb); + if (myParameterIndex < 0) return; + final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); + if (templateState != null) { + templateState.gotoEnd(true); + new IntroduceParameterPass().pass(isReplaceAllOccurences() ? OccurrencesChooser.ReplaceChoice.ALL : OccurrencesChooser.ReplaceChoice.NO); + } + } + private class IntroduceParameterPass extends Pass { @Override @@ -321,14 +360,20 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { public void run() { myTypeSelectorManager.setAllOccurences(replaceChoice != OccurrencesChooser.ReplaceChoice.NO); final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); - final String[] names = myNameSuggestionsGenerator.getSuggestedNameInfo(defaultType).names; + final String propName = myLocalVar != null ? JavaCodeStyleManager + .getInstance(myProject).variableNameToPropertyName(myLocalVar.getName(), VariableKind.LOCAL_VARIABLE) : null; + final String[] names = IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName) + .getSuggestedNameInfo(defaultType).names; final PsiParameter parameter = createParameterToStartTemplateOn(names, defaultType); if (parameter != null) { + myParameterIndex = myMethod.getParameterList().getParameterIndex(parameter); myEditor.getCaretModel().moveToOffset(parameter.getTextOffset()); showSettingsPopup(); - final VariableInplaceRenamer renamer = - new ParameterInplaceIntroducer(parameter, replaceChoice); - renamer.performInplaceRename(false, new LinkedHashSet(Arrays.asList(names))); + final LinkedHashSet nameSuggestions = new LinkedHashSet(); + nameSuggestions.add(parameter.getName()); + nameSuggestions.addAll(Arrays.asList(names)); + final VariableInplaceRenamer renamer = new ParameterInplaceIntroducer(parameter); + renamer.performInplaceRename(false, nameSuggestions); } } }, IntroduceParameterHandler.REFACTORING_NAME, null); @@ -340,9 +385,10 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override public PsiParameter compute() { + final String name = myParameterName != null ? myParameterName : names[0]; + final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod); final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList() - .addAfter(elementFactory.createParameter(names[0], defaultType), - JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod)); + .addAfter(elementFactory.createParameter(name, defaultType), anchor); PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, hasFinalModifier()); return psiParameter; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java index 8876e3826590..5d4186ae438c 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java @@ -40,8 +40,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.util.List; public class IntroduceParameterDialog extends RefactoringDialog { @@ -60,8 +58,7 @@ public class IntroduceParameterDialog extends RefactoringDialog { // private JComponent myParameterNameField = null; private NameSuggestionsField myParameterNameField; - private JCheckBox myCbReplaceAllOccurences = null; - private JCheckBox myCbGenerateDelegate = null; + private final NameSuggestionsGenerator myNameSuggestionsGenerator; private final TypeSelectorManager myTypeSelectorManager; @@ -106,13 +103,7 @@ public class IntroduceParameterDialog extends RefactoringDialog { return myCbDeclareFinal != null && myCbDeclareFinal.isSelected(); } - private boolean isReplaceAllOccurences() { - return myPanel.myIsInvokedOnDeclaration || myCbReplaceAllOccurences != null && myCbReplaceAllOccurences.isSelected(); - } - private boolean isGenerateDelegate() { - return myCbGenerateDelegate != null && myCbGenerateDelegate.isSelected(); - } private String getParameterName() { return myParameterNameField.getEnteredName().trim(); @@ -196,11 +187,7 @@ public class IntroduceParameterDialog extends RefactoringDialog { gbConstraints.gridwidth = 2; if (myOccurenceNumber > 1 && !myPanel.myIsInvokedOnDeclaration) { gbConstraints.gridy++; - myCbReplaceAllOccurences = new NonFocusableCheckBox(); - myCbReplaceAllOccurences.setText(RefactoringBundle.message("replace.all.occurences", myOccurenceNumber)); - - panel.add(myCbReplaceAllOccurences, gbConstraints); - myCbReplaceAllOccurences.setSelected(false); + myPanel.createOccurrencesCb(gbConstraints, panel, myOccurenceNumber); } JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance(); @@ -218,31 +205,19 @@ public class IntroduceParameterDialog extends RefactoringDialog { myCbDeclareFinal.setEnabled(false); } - if(myCbReplaceAllOccurences != null) { + if(myPanel.myCbReplaceAllOccurences != null) { gbConstraints.insets = new Insets(0, 16, 4, 8); } myPanel.createLocalVariablePanel(gbConstraints, panel, settings); gbConstraints.insets = new Insets(4, 0, 4, 8); gbConstraints.gridy++; - myCbGenerateDelegate = new NonFocusableCheckBox(RefactoringBundle.message("delegation.panel.delegate.via.overloading.method")); - panel.add(myCbGenerateDelegate, gbConstraints); + myPanel.createDelegateCb(gbConstraints, panel); - final JCheckBox[] removeParamsCb = myPanel.createRemoveParamsPanel(gbConstraints, panel); - if (myCbReplaceAllOccurences != null) { - myCbReplaceAllOccurences.addItemListener( - new ItemListener() { - public void itemStateChanged(ItemEvent e) { - myPanel.updateControls(removeParamsCb); - } - } - ); - } return panel; } - protected JComponent createCenterPanel() { if(Util.anyFieldsWithGettersPresent(myClassMembersList)) { return myPanel.createReplaceFieldsWithGettersPanel(); @@ -276,8 +251,8 @@ public class IntroduceParameterDialog extends RefactoringDialog { myProject, myMethodToReplaceIn, myMethodToSearchFor, parameterInitializer, myExpression, myLocalVar, isDeleteLocalVariable, - getParameterName(), isReplaceAllOccurences(), - myPanel.getReplaceFieldsWithGetters(), isDeclareFinal(), isGenerateDelegate(), getSelectedType(), myPanel.getParametersToRemove()); + getParameterName(), myPanel.isReplaceAllOccurences(), + myPanel.getReplaceFieldsWithGetters(), isDeclareFinal(), myPanel.isGenerateDelegate(), getSelectedType(), myPanel.getParametersToRemove()); invokeRefactoring(processor); myParameterNameField.requestFocusInWindow(); } @@ -299,29 +274,10 @@ public class IntroduceParameterDialog extends RefactoringDialog { super(project, onLocalVariable, onExpression, methodToReplaceIn, parametersToRemove); } + @Override - protected void updateControls(JCheckBox[] removeParamsCb) { - if (myCbReplaceAllOccurences != null) { - for (JCheckBox box : removeParamsCb) { - if (box != null) { - box.setEnabled(myCbReplaceAllOccurences.isSelected()); - } - } - myTypeSelectorManager.setAllOccurences(myCbReplaceAllOccurences.isSelected()); - if (myCbReplaceAllOccurences.isSelected()) { - if (myCbDeleteLocalVariable != null) { - myCbDeleteLocalVariable.makeSelectable(); - } - } - else { - if (myCbDeleteLocalVariable != null) { - myCbDeleteLocalVariable.makeUnselectable(false); - } - } - } - else { - myTypeSelectorManager.setAllOccurences(myIsInvokedOnDeclaration); - } + protected TypeSelectorManager getTypeSelectionManager() { + return myTypeSelectorManager; } } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index 64e08642e02d..76cf915b1d26 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -196,15 +196,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R ? new TypeSelectorManagerImpl(project, initializerType, expr, occurences) : new TypeSelectorManagerImpl(project, initializerType, occurences); - NameSuggestionsGenerator nameSuggestionsGenerator = new NameSuggestionsGenerator() { - public SuggestedNameInfo getSuggestedNameInfo(PsiType type) { - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(myProject); - final SuggestedNameInfo info = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, propName, expr, type); - final String[] strings = JavaCompletionUtil.completeVariableNameForRefactoring(codeStyleManager, type, VariableKind.LOCAL_VARIABLE, info); - return new SuggestedNameInfo.Delegate(strings, info); - } - - }; + NameSuggestionsGenerator nameSuggestionsGenerator = createNameSuggestionGenerator(expr, propName); boolean isInplaceAvailableOnDataContext = editor != null && editor.getSettings().isVariableInplaceRenameEnabled() && method == methodToSearchFor && method.hasModifierProperty(PsiModifier.PRIVATE); @@ -220,7 +212,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R } } else { new InplaceIntroduceParameterPopup(project, editor, classMemberRefs, - typeSelectorManager, nameSuggestionsGenerator, + typeSelectorManager, expr, localVar, method, methodToSearchFor, occurences, parametersToRemove, mustBeFinal).inplaceIntroduceParameter(); } @@ -228,6 +220,20 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R return true; } + protected static NameSuggestionsGenerator createNameSuggestionGenerator(final PsiExpression expr, + final String propName) { + return new NameSuggestionsGenerator() { + public SuggestedNameInfo getSuggestedNameInfo(PsiType type) { + final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expr.getProject()); + final SuggestedNameInfo info = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, propName, expr, type); + final String[] strings = JavaCompletionUtil + .completeVariableNameForRefactoring(codeStyleManager, type, VariableKind.LOCAL_VARIABLE, info); + return new SuggestedNameInfo.Delegate(strings, info); + } + + }; + } + private static void showErrorMessage(Project project, String message, Editor editor) { CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INTRODUCE_PARAMETER); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java index a82a481b7f12..21fee109fade 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterSettingsUI.java @@ -24,6 +24,7 @@ import com.intellij.refactoring.IntroduceParameterRefactoring; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.ui.RefactoringDialog; +import com.intellij.refactoring.ui.TypeSelectorManager; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.StateRestoringCheckBox; @@ -34,6 +35,8 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; /** * User: anna @@ -53,6 +56,9 @@ public abstract class IntroduceParameterSettingsUI { protected final boolean[] myParametersToRemoveChecked; protected final boolean myIsLocalVariable; + protected JCheckBox myCbReplaceAllOccurences = null; + private JCheckBox myCbGenerateDelegate = null; + public IntroduceParameterSettingsUI(Project project, PsiLocalVariable onLocalVariable, PsiExpression onExpression, @@ -97,6 +103,14 @@ public abstract class IntroduceParameterSettingsUI { return IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE; } + public boolean isReplaceAllOccurences() { + return myIsInvokedOnDeclaration || myCbReplaceAllOccurences != null && myCbReplaceAllOccurences.isSelected(); + } + + public boolean isGenerateDelegate() { + return myCbGenerateDelegate != null && myCbGenerateDelegate.isSelected(); + } + protected JPanel createReplaceFieldsWithGettersPanel() { JPanel radioButtonPanel = new JPanel(new GridBagLayout()); @@ -169,9 +183,33 @@ public abstract class IntroduceParameterSettingsUI { return parameters; } - protected abstract void updateControls(JCheckBox[] removeParamsCb); + protected void updateControls(JCheckBox[] removeParamsCb) { + if (myCbReplaceAllOccurences != null) { + for (JCheckBox box : removeParamsCb) { + if (box != null) { + box.setEnabled(myCbReplaceAllOccurences.isSelected()); + } + } + getTypeSelectionManager().setAllOccurences(myCbReplaceAllOccurences.isSelected()); + if (myCbReplaceAllOccurences.isSelected()) { + if (myCbDeleteLocalVariable != null) { + myCbDeleteLocalVariable.makeSelectable(); + } + } + else { + if (myCbDeleteLocalVariable != null) { + myCbDeleteLocalVariable.makeUnselectable(false); + } + } + } + else { + getTypeSelectionManager().setAllOccurences(myIsInvokedOnDeclaration); + } + } - protected JCheckBox[] createRemoveParamsPanel(GridBagConstraints gbConstraints, JPanel panel) { + protected abstract TypeSelectorManager getTypeSelectionManager(); + + protected void createRemoveParamsPanel(GridBagConstraints gbConstraints, JPanel panel) { final JCheckBox[] removeParamsCb = new JCheckBox[myParametersToRemove.length]; for (int i = 0; i < myParametersToRemove.length; i++) { PsiParameter parameter = myParametersToRemove[i]; @@ -192,7 +230,15 @@ public abstract class IntroduceParameterSettingsUI { } updateControls(removeParamsCb); - return removeParamsCb; + if (myCbReplaceAllOccurences != null) { + myCbReplaceAllOccurences.addItemListener( + new ItemListener() { + public void itemStateChanged(ItemEvent e) { + updateControls(removeParamsCb); + } + } + ); + } } protected void createLocalVariablePanel(GridBagConstraints gbConstraints, JPanel panel, JavaRefactoringSettings settings) { @@ -216,4 +262,18 @@ public abstract class IntroduceParameterSettingsUI { } } } + + + protected void createDelegateCb(GridBagConstraints gbConstraints, JPanel panel) { + myCbGenerateDelegate = new NonFocusableCheckBox(RefactoringBundle.message("delegation.panel.delegate.via.overloading.method")); + panel.add(myCbGenerateDelegate, gbConstraints); + } + + protected void createOccurrencesCb(GridBagConstraints gbConstraints, JPanel panel, final int occurenceNumber) { + myCbReplaceAllOccurences = new NonFocusableCheckBox(); + myCbReplaceAllOccurences.setText(RefactoringBundle.message("replace.all.occurences", occurenceNumber)); + + panel.add(myCbReplaceAllOccurences, gbConstraints); + myCbReplaceAllOccurences.setSelected(false); + } } From 703612fcc7297f71002258e6bf776ffd1820c581 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 1 Mar 2011 20:21:08 +0100 Subject: [PATCH 04/95] inplace introduce parameter: choose methods to introduce parameters in popup --- .../BaseExpressionToFieldHandler.java | 10 +- .../IntroduceParameterDialog.java | 2 +- .../IntroduceParameterHandler.java | 303 +++++++++++++----- 3 files changed, 229 insertions(+), 86 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java index f203196b8d56..f99ae678c7c5 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java @@ -28,6 +28,7 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.codeInsight.TestUtil; import com.intellij.codeInsight.highlighting.HighlightManager; +import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.ide.util.DirectoryChooserUtil; import com.intellij.ide.util.PackageUtil; import com.intellij.openapi.application.ApplicationManager; @@ -552,15 +553,18 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase public void pass(final ElementToWorkOn elementToWorkOn) { if (elementToWorkOn == null) return; + final boolean hasRunTemplate = LookupManager.getActiveLookup(editor) == null; if (elementToWorkOn.getExpression() == null) { final PsiLocalVariable localVariable = elementToWorkOn.getLocalVariable(); - final boolean result = invokeImpl(project, localVariable, editor); + final boolean result = invokeImpl(project, localVariable, editor) && hasRunTemplate; if (result) { editor.getSelectionModel().removeSelection(); } } - else if (invokeImpl(project, elementToWorkOn.getExpression(), editor)) { - editor.getSelectionModel().removeSelection(); + else { + if (invokeImpl(project, elementToWorkOn.getExpression(), editor) && hasRunTemplate) { + editor.getSelectionModel().removeSelection(); + } } } }; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java index 5d4186ae438c..828e93793032 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterDialog.java @@ -209,7 +209,7 @@ public class IntroduceParameterDialog extends RefactoringDialog { gbConstraints.insets = new Insets(0, 16, 4, 8); } myPanel.createLocalVariablePanel(gbConstraints, panel, settings); - + myPanel.createRemoveParamsPanel(gbConstraints, panel); gbConstraints.insets = new Insets(4, 0, 4, 8); gbConstraints.gridy++; myPanel.createDelegateCb(gbConstraints, panel); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index 76cf915b1d26..1a8665a108d2 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -32,8 +32,16 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.*; +import com.intellij.openapi.ui.popup.util.BaseListPopupStep; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pass; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.SuggestedNameInfo; @@ -41,17 +49,28 @@ import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.*; import com.intellij.refactoring.introduceField.ElementToWorkOn; +import com.intellij.refactoring.ui.MethodCellRenderer; import com.intellij.refactoring.ui.NameSuggestionsGenerator; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.occurences.ExpressionOccurenceManager; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.components.JBList; import com.intellij.usageView.UsageInfo; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; import java.util.*; import java.util.List; @@ -60,6 +79,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceParameter.IntroduceParameterHandler"); static final String REFACTORING_NAME = RefactoringBundle.message("introduce.parameter.title"); private Project myProject; + private JBPopup myEnclosingMethodsPopup; public void invoke(@NotNull final Project project, final Editor editor, PsiFile file, DataContext dataContext) { PsiDocumentManager.getInstance(project).commitAllDocuments(); @@ -86,7 +106,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R return invoke(editor, project, null, localVariable, true); } - private boolean invoke(Editor editor, Project project, final PsiExpression expr, + private boolean invoke(final Editor editor, final Project project, final PsiExpression expr, PsiLocalVariable localVar, boolean invokedOnDeclaration) { LOG.assertTrue(!PsiDocumentManager.getInstance(project).hasUncommitedDocuments()); PsiMethod method; @@ -131,95 +151,108 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R return false; } - method = chooseEnclosingMethod(method); - if (method == null) return false; - - final PsiMethod methodToSearchFor = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor")); - if (methodToSearchFor == null) return false; - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, methodToSearchFor)) return false; - - PsiExpression[] occurences; - if (expr != null) { - occurences = new ExpressionOccurenceManager(expr, method, null).findExpressionOccurrences(); + final List validEnclosingMethods = getEnclosingMethods(method); + if (validEnclosingMethods.isEmpty()) { + return false; } - else { // local variable - occurences = CodeInsightUtil.findReferenceExpressions(method, localVar); - } - PsiExpression expressionToRemoveParamFrom = expr; - if (expr == null) { - expressionToRemoveParamFrom = localVar.getInitializer(); - } - TIntArrayList parametersToRemove = expressionToRemoveParamFrom == null ? new TIntArrayList() : Util.findParametersToRemove(method, expressionToRemoveParamFrom, occurences); - - boolean mustBeFinal = false; - if (localVar != null) { - for(PsiExpression occurrence: occurences) { - if (PsiTreeUtil.getParentOfType(occurrence, PsiClass.class, PsiMethod.class) != method) { - mustBeFinal = true; - break; - } + final Introducer introducer = new Introducer(project, expr, localVar, editor); + final boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); + if (validEnclosingMethods.size() == 1 || unitTestMode) { + if (validEnclosingMethods.get(0).findDeepestSuperMethod() == null || unitTestMode) { + introducer.introduceParameter(method, method); + return true; } } - List localVars = new ArrayList(); - List classMemberRefs = new ArrayList(); - List params = new ArrayList(); + chooseMethodToIntroduceParameter(editor, validEnclosingMethods, introducer); - - if (expr != null) { - Util.analyzeExpression(expr, localVars, classMemberRefs, params); - } - - if (expr instanceof PsiReferenceExpression) { - PsiElement resolved = ((PsiReferenceExpression) expr).resolve(); - if (resolved instanceof PsiLocalVariable) { - localVar = (PsiLocalVariable) resolved; - } - } - - - if (ApplicationManager.getApplication().isUnitTestMode()) { - @NonNls String parameterName = "anObject"; - boolean replaceAllOccurences = true; - boolean isDeleteLocalVariable = true; - PsiExpression initializer = localVar != null && expr == null ? localVar.getInitializer() : expr; - new IntroduceParameterProcessor(myProject, method, methodToSearchFor, initializer, expr, localVar, isDeleteLocalVariable, parameterName, - replaceAllOccurences, IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, mustBeFinal, - false, null, - parametersToRemove).run(); - } - else { - final String propName = localVar != null ? JavaCodeStyleManager.getInstance(myProject).variableNameToPropertyName(localVar.getName(), VariableKind.LOCAL_VARIABLE) : null; - final PsiType initializerType = IntroduceParameterProcessor.getInitializerType(null, expr, localVar); - - TypeSelectorManagerImpl typeSelectorManager = expr != null - ? new TypeSelectorManagerImpl(project, initializerType, expr, occurences) - : new TypeSelectorManagerImpl(project, initializerType, occurences); - - NameSuggestionsGenerator nameSuggestionsGenerator = createNameSuggestionGenerator(expr, propName); - boolean isInplaceAvailableOnDataContext = editor != null && editor.getSettings().isVariableInplaceRenameEnabled() - && method == methodToSearchFor - && method.hasModifierProperty(PsiModifier.PRIVATE); - - if (!isInplaceAvailableOnDataContext) { - if (editor != null) { - RefactoringUtil.highlightAllOccurences(myProject, occurences, editor); - } - new IntroduceParameterDialog(myProject, classMemberRefs, occurences.length, localVar, expr, nameSuggestionsGenerator, - typeSelectorManager, methodToSearchFor, method, parametersToRemove, mustBeFinal).show(); - if (editor != null) { - editor.getSelectionModel().removeSelection(); - } - } else { - new InplaceIntroduceParameterPopup(project, editor, classMemberRefs, - typeSelectorManager, - expr, localVar, method, methodToSearchFor, occurences, parametersToRemove, - mustBeFinal).inplaceIntroduceParameter(); - } - } return true; } + private void chooseMethodToIntroduceParameter(final Editor editor, + final List validEnclosingMethods, + final Introducer introducer) { + final JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(IdeBorderFactory.createRoundedBorder()); + final JCheckBox superMethod = new JCheckBox("Choose base method", true); + superMethod.setMnemonic('b'); + panel.add(superMethod, BorderLayout.SOUTH); + final JBList list = new JBList(validEnclosingMethods.toArray()); + list.setCellRenderer(new MethodCellRenderer()); + list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.setSelectedIndex(0); + final List highlighters = new ArrayList(); + final TextAttributes attributes = + EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + list.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(final ListSelectionEvent e) { + final PsiMethod selectedMethod = (PsiMethod)list.getSelectedValue(); + if (selectedMethod == null) return; + dropHighlighters(highlighters); + updateView(selectedMethod, editor, attributes, highlighters, superMethod); + } + }); + updateView(validEnclosingMethods.get(0), editor, attributes, highlighters, superMethod); + panel.add(ScrollPaneFactory.createScrollPane(list), BorderLayout.CENTER); + + final List> + keyboardActions = Collections.singletonList(Pair.create(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + final PsiMethod methodToSearchIn = (PsiMethod)list.getSelectedValue(); + if (myEnclosingMethodsPopup != null && myEnclosingMethodsPopup.isVisible()) { + myEnclosingMethodsPopup.cancel(); + } + + final PsiMethod methodToSearchFor = superMethod.isEnabled() && superMethod.isSelected() + ? methodToSearchIn.findDeepestSuperMethod() : methodToSearchIn; + Runnable runnable = new Runnable() { + public void run() { + introducer.introduceParameter(methodToSearchIn, methodToSearchFor); + } + }; + IdeFocusManager.findInstance().doWhenFocusSettlesDown(runnable); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0))); + myEnclosingMethodsPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, list) + .setTitle("Introduce parameter to method") + .setMovable(false) + .setResizable(false) + .setRequestFocus(true) + .setKeyboardActions(keyboardActions).addListener(new JBPopupAdapter() { + @Override + public void onClosed(LightweightWindowEvent event) { + dropHighlighters(highlighters); + } + }).createPopup(); + myEnclosingMethodsPopup.showInBestPositionFor(editor); + } + + private static void updateView(PsiMethod selectedMethod, + Editor editor, + TextAttributes attributes, + List highlighters, + JCheckBox superMethod) { + final MarkupModel markupModel = editor.getMarkupModel(); + final PsiIdentifier nameIdentifier = selectedMethod.getNameIdentifier(); + if (nameIdentifier != null) { + final TextRange textRange = nameIdentifier.getTextRange(); + final RangeHighlighter rangeHighlighter = markupModel.addRangeHighlighter( + textRange.getStartOffset(), textRange.getEndOffset(), HighlighterLayer.SELECTION - 1, + attributes, + HighlighterTargetArea.EXACT_RANGE); + highlighters.add(rangeHighlighter); + } + superMethod.setEnabled(selectedMethod.findDeepestSuperMethod() != null); + } + + private static void dropHighlighters(List highlighters) { + for (RangeHighlighter highlighter : highlighters) { + highlighter.dispose(); + } + highlighters.clear(); + } + protected static NameSuggestionsGenerator createNameSuggestionGenerator(final PsiExpression expr, final String propName) { return new NameSuggestionsGenerator() { @@ -291,4 +324,110 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R private static boolean isLibraryInterfaceMethod(final PsiMethod method) { return method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.getManager().isInProject(method); } + + private static class Introducer { + + private final Project myProject; + + private final PsiExpression myExpr; + private PsiLocalVariable myLocalVar; + private final Editor myEditor; + + public Introducer(Project project, + PsiExpression expr, + PsiLocalVariable localVar, + Editor editor) { + myProject = project; + myExpr = expr; + myLocalVar = localVar; + myEditor = editor; + } + + public void introduceParameter(PsiMethod method, PsiMethod methodToSearchFor) { + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, methodToSearchFor)) return; + + PsiExpression[] occurences; + if (myExpr != null) { + occurences = new ExpressionOccurenceManager(myExpr, method, null).findExpressionOccurrences(); + } + else { // local variable + occurences = CodeInsightUtil.findReferenceExpressions(method, myLocalVar); + } + PsiExpression expressionToRemoveParamFrom = myExpr; + if (myExpr == null) { + expressionToRemoveParamFrom = myLocalVar.getInitializer(); + } + TIntArrayList parametersToRemove = expressionToRemoveParamFrom == null ? new TIntArrayList() : Util + .findParametersToRemove(method, expressionToRemoveParamFrom, occurences); + + boolean mustBeFinal = false; + if (myLocalVar != null) { + for(PsiExpression occurrence: occurences) { + if (PsiTreeUtil.getParentOfType(occurrence, PsiClass.class, PsiMethod.class) != method) { + mustBeFinal = true; + break; + } + } + } + + List localVars = new ArrayList(); + List classMemberRefs = new ArrayList(); + List params = new ArrayList(); + + + if (myExpr != null) { + Util.analyzeExpression(myExpr, localVars, classMemberRefs, params); + } + + if (myExpr instanceof PsiReferenceExpression) { + PsiElement resolved = ((PsiReferenceExpression)myExpr).resolve(); + if (resolved instanceof PsiLocalVariable) { + myLocalVar = (PsiLocalVariable) resolved; + } + } + + + if (ApplicationManager.getApplication().isUnitTestMode()) { + @NonNls String parameterName = "anObject"; + boolean replaceAllOccurences = true; + boolean isDeleteLocalVariable = true; + PsiExpression initializer = myLocalVar != null && myExpr == null ? myLocalVar.getInitializer() : myExpr; + new IntroduceParameterProcessor(myProject, method, methodToSearchFor, initializer, myExpr, myLocalVar, isDeleteLocalVariable, parameterName, + replaceAllOccurences, IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, mustBeFinal, + false, null, + parametersToRemove).run(); + } + else { + final String propName = myLocalVar != null ? JavaCodeStyleManager + .getInstance(myProject).variableNameToPropertyName(myLocalVar.getName(), VariableKind.LOCAL_VARIABLE) : null; + final PsiType initializerType = IntroduceParameterProcessor.getInitializerType(null, myExpr, myLocalVar); + + TypeSelectorManagerImpl typeSelectorManager = myExpr != null + ? new TypeSelectorManagerImpl(myProject, initializerType, myExpr, occurences) + : new TypeSelectorManagerImpl(myProject, initializerType, occurences); + + NameSuggestionsGenerator nameSuggestionsGenerator = createNameSuggestionGenerator(myExpr, propName); + boolean isInplaceAvailableOnDataContext = myEditor != null && myEditor.getSettings().isVariableInplaceRenameEnabled(); + + if (!isInplaceAvailableOnDataContext) { + if (myEditor != null) { + RefactoringUtil.highlightAllOccurences(myProject, occurences, myEditor); + } + new IntroduceParameterDialog(myProject, classMemberRefs, occurences.length, myLocalVar, myExpr, nameSuggestionsGenerator, + typeSelectorManager, methodToSearchFor, method, parametersToRemove, mustBeFinal).show(); + if (myEditor != null) { + myEditor.getSelectionModel().removeSelection(); + } + } + else { + new InplaceIntroduceParameterPopup(myProject, myEditor, classMemberRefs, + typeSelectorManager, + myExpr, myLocalVar, method, methodToSearchFor, occurences, parametersToRemove, + mustBeFinal).inplaceIntroduceParameter(); + } + } + } + } + + } From 92696623d4cd47f80d960db7d402eb4e2581027e Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 1 Mar 2011 21:17:20 +0100 Subject: [PATCH 05/95] NPE --- .../InplaceIntroduceParameterPopup.java | 2 +- .../introduceParameter/IntroduceParameterHandler.java | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index cce7d69e081a..468109d654fb 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -362,7 +362,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); final String propName = myLocalVar != null ? JavaCodeStyleManager .getInstance(myProject).variableNameToPropertyName(myLocalVar.getName(), VariableKind.LOCAL_VARIABLE) : null; - final String[] names = IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName) + final String[] names = IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName, myProject) .getSuggestedNameInfo(defaultType).names; final PsiParameter parameter = createParameterToStartTemplateOn(names, defaultType); if (parameter != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index 1a8665a108d2..463b38926bd7 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -26,7 +26,6 @@ package com.intellij.refactoring.introduceParameter; import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.completion.JavaCompletionUtil; -import com.intellij.ide.util.SuperMethodWarningUtil; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -37,7 +36,6 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; -import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.TextRange; @@ -254,10 +252,11 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R } protected static NameSuggestionsGenerator createNameSuggestionGenerator(final PsiExpression expr, - final String propName) { + final String propName, + final Project project) { return new NameSuggestionsGenerator() { public SuggestedNameInfo getSuggestedNameInfo(PsiType type) { - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expr.getProject()); + final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); final SuggestedNameInfo info = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, propName, expr, type); final String[] strings = JavaCompletionUtil .completeVariableNameForRefactoring(codeStyleManager, type, VariableKind.LOCAL_VARIABLE, info); @@ -277,7 +276,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R /* do nothing */ } - private static List getEnclosingMethods(PsiMethod nearest) { + public static List getEnclosingMethods(PsiMethod nearest) { List enclosingMethods = new ArrayList(); enclosingMethods.add(nearest); PsiMethod method = nearest; @@ -406,7 +405,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase implements R ? new TypeSelectorManagerImpl(myProject, initializerType, myExpr, occurences) : new TypeSelectorManagerImpl(myProject, initializerType, occurences); - NameSuggestionsGenerator nameSuggestionsGenerator = createNameSuggestionGenerator(myExpr, propName); + NameSuggestionsGenerator nameSuggestionsGenerator = createNameSuggestionGenerator(myExpr, propName, myProject); boolean isInplaceAvailableOnDataContext = myEditor != null && myEditor.getSettings().isVariableInplaceRenameEnabled(); if (!isInplaceAvailableOnDataContext) { From de8ae316f5e5cc79e48dd2a603e7871cbe414453 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 1 Mar 2011 21:36:05 +0100 Subject: [PATCH 06/95] inplace introduce parameter: cleanup --- .../InplaceIntroduceParameterPopup.java | 121 +++++++++--------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 468109d654fb..b94db818fdaf 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -41,7 +41,6 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.JavaRefactoringSettings; -import com.intellij.refactoring.introduceVariable.OccurrencesChooser; import com.intellij.refactoring.introduceVariable.VariableInplaceIntroducer; import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.intellij.refactoring.ui.TypeSelectorManager; @@ -129,7 +128,31 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { void inplaceIntroduceParameter() { - new IntroduceParameterPass().pass(OccurrencesChooser.ReplaceChoice.NO); + startIntroduceTemplate(false); + } + + private void startIntroduceTemplate(final boolean replaceAllOccurrences) { + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + myTypeSelectorManager.setAllOccurences(replaceAllOccurrences); + final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); + final String propName = myLocalVar != null ? JavaCodeStyleManager + .getInstance(myProject).variableNameToPropertyName(myLocalVar.getName(), VariableKind.LOCAL_VARIABLE) : null; + final String[] names = IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName, myProject) + .getSuggestedNameInfo(defaultType).names; + final PsiParameter parameter = createParameterToStartTemplateOn(names, defaultType); + if (parameter != null) { + myParameterIndex = myMethod.getParameterList().getParameterIndex(parameter); + myEditor.getCaretModel().moveToOffset(parameter.getTextOffset()); + showBalloon(); + final LinkedHashSet nameSuggestions = new LinkedHashSet(); + nameSuggestions.add(parameter.getName()); + nameSuggestions.addAll(Arrays.asList(names)); + final VariableInplaceRenamer renamer = new ParameterInplaceIntroducer(parameter); + renamer.performInplaceRename(false, nameSuggestions); + } + } + }, IntroduceParameterHandler.REFACTORING_NAME, null); } @Override @@ -191,7 +214,8 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { for (PsiExpression expression : myOccurrences) { stringUsages.add(Pair.create(expression, new TextRange(0, expression.getTextLength()))); } - } else if (myExpr != null){ + } + else if (myExpr != null) { stringUsages.add(Pair.create(myExpr, new TextRange(0, myExpr.getTextLength()))); } } @@ -215,7 +239,8 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { final int startOffset = marker.getStartOffset(); highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); } - } else if (myExpr != null) { + } + else if (myExpr != null) { final int startOffset = myExprMarker.getStartOffset(); highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); } @@ -276,7 +301,6 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { } - @Override public void finish() { super.finish(); @@ -348,67 +372,40 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); if (templateState != null) { templateState.gotoEnd(true); - new IntroduceParameterPass().pass(isReplaceAllOccurences() ? OccurrencesChooser.ReplaceChoice.ALL : OccurrencesChooser.ReplaceChoice.NO); + startIntroduceTemplate(isReplaceAllOccurences()); } } - private class IntroduceParameterPass extends Pass { - @Override - public void pass(final OccurrencesChooser.ReplaceChoice replaceChoice) { - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - myTypeSelectorManager.setAllOccurences(replaceChoice != OccurrencesChooser.ReplaceChoice.NO); - final PsiType defaultType = myTypeSelectorManager.getTypeSelector().getSelectedType(); - final String propName = myLocalVar != null ? JavaCodeStyleManager - .getInstance(myProject).variableNameToPropertyName(myLocalVar.getName(), VariableKind.LOCAL_VARIABLE) : null; - final String[] names = IntroduceParameterHandler.createNameSuggestionGenerator(myExpr, propName, myProject) - .getSuggestedNameInfo(defaultType).names; - final PsiParameter parameter = createParameterToStartTemplateOn(names, defaultType); - if (parameter != null) { - myParameterIndex = myMethod.getParameterList().getParameterIndex(parameter); - myEditor.getCaretModel().moveToOffset(parameter.getTextOffset()); - showSettingsPopup(); - final LinkedHashSet nameSuggestions = new LinkedHashSet(); - nameSuggestions.add(parameter.getName()); - nameSuggestions.addAll(Arrays.asList(names)); - final VariableInplaceRenamer renamer = new ParameterInplaceIntroducer(parameter); - renamer.performInplaceRename(false, nameSuggestions); - } - } - }, IntroduceParameterHandler.REFACTORING_NAME, null); - } + private PsiParameter createParameterToStartTemplateOn(final String[] names, + final PsiType defaultType) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myMethod.getProject()); + return ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public PsiParameter compute() { + final String name = myParameterName != null ? myParameterName : names[0]; + final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod); + final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList() + .addAfter(elementFactory.createParameter(name, defaultType), anchor); + PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, hasFinalModifier()); + return psiParameter; + } + }); + } - private PsiParameter createParameterToStartTemplateOn(final String[] names, - final PsiType defaultType) { - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myMethod.getProject()); - return ApplicationManager.getApplication().runWriteAction(new Computable() { - @Override - public PsiParameter compute() { - final String name = myParameterName != null ? myParameterName : names[0]; - final PsiParameter anchor = JavaIntroduceParameterMethodUsagesProcessor.getAnchorParameter(myMethod); - final PsiParameter psiParameter = (PsiParameter)myMethod.getParameterList() - .addAfter(elementFactory.createParameter(name, defaultType), anchor); - PsiUtil.setModifierProperty(psiParameter, PsiModifier.FINAL, hasFinalModifier()); - return psiParameter; - } - }); - } - - private void showSettingsPopup() { - BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(myWholePanel); - balloonBuilder.setFadeoutTime(0); - balloonBuilder.setFillColor(IdeTooltipManager.GRAPHITE_COLOR); - balloonBuilder.setAnimationCycle(0); - balloonBuilder.setHideOnClickOutside(false); - balloonBuilder.setHideOnKeyOutside(false); - balloonBuilder.setHideOnAction(false); - balloonBuilder.setCloseButtonEnabled(true); - final RelativePoint target = JBPopupFactory.getInstance().guessBestPopupLocation(myEditor); - final Point screenPoint = target.getScreenPoint(); - myBalloon = balloonBuilder.createBalloon(); - myBalloon - .show(new RelativePoint(new Point(screenPoint.x, screenPoint.y - myEditor.getLineHeight())), Balloon.Position.above); - } + private void showBalloon() { + final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(myWholePanel); + balloonBuilder.setFadeoutTime(0); + balloonBuilder.setFillColor(IdeTooltipManager.GRAPHITE_COLOR); + balloonBuilder.setAnimationCycle(0); + balloonBuilder.setHideOnClickOutside(false); + balloonBuilder.setHideOnKeyOutside(false); + balloonBuilder.setHideOnAction(false); + balloonBuilder.setCloseButtonEnabled(true); + final RelativePoint target = JBPopupFactory.getInstance().guessBestPopupLocation(myEditor); + final Point screenPoint = target.getScreenPoint(); + myBalloon = balloonBuilder.createBalloon(); + myBalloon + .show(new RelativePoint(new Point(screenPoint.x, screenPoint.y - myEditor.getLineHeight())), Balloon.Position.above); } } From cb86b6978fce45baf62c3bd85fefea25045331da Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 6 Mar 2011 18:08:37 +0300 Subject: [PATCH 07/95] improved 'move' for groovy scripts and classes --- .../MoveClassesOrPackagesHandlerBase.java | 19 ++- .../MoveClassesOrPackagesProcessor.java | 4 +- .../groovy/lang/psi/impl/PsiImplUtil.java | 4 +- .../typedef/GrTypeDefinitionImpl.java | 5 +- .../psi/impl/synthetic/GroovyScriptClass.java | 10 +- ...roovyImportOptimizerRefactoringHelper.java | 4 +- .../move/MoveGroovyClassHandler.java | 141 +++++++++++++----- .../refactoring/move/GroovyMoveClassTest.java | 2 +- .../move/GroovyMoveScriptTest.java | 12 +- .../fileWithTwoClasses/after/b/A.groovy | 5 + .../fileWithTwoClasses/after/b/Foo.groovy | 5 - 11 files changed, 146 insertions(+), 65 deletions(-) create mode 100644 plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/A.groovy diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java index 005ab5c7b057..32cf4cb8c812 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java @@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vfs.VirtualFile; @@ -31,10 +32,9 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.move.MoveHandlerDelegate; import com.intellij.refactoring.move.MoveCallback; +import com.intellij.refactoring.move.MoveHandlerDelegate; import com.intellij.refactoring.util.CommonRefactoringUtil; -import com.intellij.openapi.project.Project; import com.intellij.refactoring.util.RadioUpDownListener; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; @@ -70,8 +70,8 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { public static boolean invalid4Move(PsiElement element) { PsiFile parentFile; - if (element instanceof PsiJavaFile) { - final PsiClass[] classes = ((PsiJavaFile)element).getClasses(); + if (element instanceof PsiClassOwner) { + final PsiClass[] classes = ((PsiClassOwner)element).getClasses(); if (classes.length == 0) return true; for (PsiClass aClass : classes) { if (aClass instanceof JspClass) return true; @@ -81,8 +81,9 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { else { if (element instanceof JspClass) return true; if (!(element instanceof PsiClass)) return true; - if (!(element.getParent() instanceof PsiFile)) return true; - parentFile = (PsiFile)element.getParent(); + if (element instanceof PsiAnonymousClass) return true; + if (((PsiClass)element).getContainingClass() != null) return true; + parentFile = element.getContainingFile(); } if (CollectHighlightsUtil.isOutsideSourceRootJavaFile(parentFile)) return true; return false; @@ -313,12 +314,10 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { public boolean tryToMove(final PsiElement element, final Project project, final DataContext dataContext, final PsiReference reference, final Editor editor) { if (isPackageOrDirectory(element)) return false; - if (CollectHighlightsUtil.isOutsideSourceRootJavaFile(element.getContainingFile())) return false; if (isReferenceInAnonymousClass(reference)) return false; - if (element instanceof PsiClass && !(element instanceof PsiAnonymousClass) && element.getParent() instanceof PsiFile) { - MoveClassesOrPackagesImpl.doMove(project, new PsiElement[]{element}, - LangDataKeys.TARGET_PSI_ELEMENT.getData(dataContext), null); + if (!invalid4Move(element)) { + MoveClassesOrPackagesImpl.doMove(project, new PsiElement[]{element}, LangDataKeys.TARGET_PSI_ELEMENT.getData(dataContext), null); return true; } return false; diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java index a176951ac42c..002445ca5a20 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesProcessor.java @@ -79,8 +79,8 @@ public class MoveClassesOrPackagesProcessor extends BaseRefactoringProcessor { super(project); final Set toMove = new LinkedHashSet(); for (PsiElement element : elements) { - if (element instanceof PsiJavaFile) { - Collections.addAll(toMove, ((PsiJavaFile)element).getClasses()); + if (element instanceof PsiClassOwner) { + Collections.addAll(toMove, ((PsiClassOwner)element).getClasses()); } else { toMove.add(element); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index b5d5883667cf..a4678972892a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -381,7 +381,7 @@ public class PsiImplUtil { container.deleteChildRange(next, next); next = nnext; } - else if (type == mNLS) { + else if (type == mNLS || type == TokenType.WHITE_SPACE && next.getText().contains("\n")) { final String text = next.getText(); final int first = text.indexOf("\n"); final int second = text.indexOf("\n", first + 1); @@ -391,7 +391,7 @@ public class PsiImplUtil { } final String substring = text.substring(second); container.getNode() - .replaceChild(node, createSingleLeafElement(mNLS, substring, 0, substring.length(), null, container.getManager())); + .replaceChild(node, createSingleLeafElement(type, substring, 0, substring.length(), null, container.getManager())); return; } else { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java index cbebd79ba5e0..9ed6d1c834c8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/GrTypeDefinitionImpl.java @@ -234,10 +234,7 @@ public abstract class GrTypeDefinitionImpl extends GrStubElementBase, Set> pair = redundants.get(groovyFile); final List redundantPerFile = pair.getFirst(); final Set usedInFile = pair.getSecond(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java index 41f9fcc1cd06..84d4974db43d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/move/MoveGroovyClassHandler.java @@ -16,16 +16,12 @@ package org.jetbrains.plugins.groovy.refactoring.move; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.lang.FileASTNode; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.Factory; -import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.refactoring.PackageWrapper; -import com.intellij.refactoring.move.moveClassesOrPackages.AutocreatingSingleSourceRootMoveDestination; import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -33,16 +29,23 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.actions.GroovyTemplatesFactory; import org.jetbrains.plugins.groovy.actions.NewGroovyActionBase; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocCommentOwner; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.impl.GrDocCommentUtil; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.refactoring.GroovyChangeContextUtil; +import java.util.Collection; + /** * @author Maxim.Medvedev */ @@ -58,18 +61,54 @@ public class MoveGroovyClassHandler implements MoveClassHandler { PsiClass newClass = null; if (aClass instanceof GroovyScriptClass) { - PackageWrapper targetPackage = new PackageWrapper(aClass.getManager(), newPackage.getQualifiedName()); - final VirtualFile sourceRoot = - ProjectRootManager.getInstance(aClass.getProject()).getFileIndex().getSourceRootForFile(moveDestination.getVirtualFile()); - assert sourceRoot != null; + final PsiClass[] classes = ((GroovyFile)file).getClasses(); + if (classes.length == 1) { + if (!moveDestination.equals(file.getContainingDirectory())) { + aClass.getManager().moveFile(file, moveDestination); + ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); + } + return ((GroovyFile)file).getScriptClass(); + } + //script class is moved the first from the file due to MoveClassOrPackageProcessor:88 (element sort) + correctSelfReferences(aClass, newPackage); + final GroovyFile newFile = generateNewScript((GroovyFile)file, newPackage); - final AutocreatingSingleSourceRootMoveDestination destination = - new AutocreatingSingleSourceRootMoveDestination(targetPackage, sourceRoot); - new MoveGroovyScriptProcessor(aClass.getProject(), new PsiElement[]{file}, destination, true, true, null).run(); + for (PsiElement child : file.getChildren()) { + if (!(child instanceof GrTopStatement || child instanceof PsiComment)) continue; + if (child instanceof PsiClass || child instanceof GrImportStatement || child instanceof GrPackageDefinition) continue; + if (child instanceof GrDocComment) { + final GrDocCommentOwner owner = GrDocCommentUtil.findDocOwner((GrDocComment)child); + if (owner instanceof PsiClass) continue; + } + child.delete(); + } + + + if (!moveDestination.equals(file.getContainingDirectory())) { + moveDestination.add(newFile); + + //aClass.getManager().moveFile(newFile, moveDestination); + } + newClass = newFile.getClasses()[0]; + correctOldClassReferences(newClass, aClass); } else { - //GroovyChangeContextUtil.encodeContextInfo(aClass); - if (((GroovyFile)file).getClasses().length > 1) { + if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) != null) { + // moving second of two classes which were in the same file to a different directory (IDEADEV-3089) + correctSelfReferences(aClass, newPackage); + PsiFile newFile = moveDestination.findFile(file.getName()); + final FileASTNode fileNode = newFile.getNode(); + fileNode.addChild(Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n\n", 0, 2, null, aClass.getManager())); + final PsiDocComment docComment = aClass.getDocComment(); + if (docComment != null) { + newFile.add(docComment); + fileNode.addChild(Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, aClass.getManager())); + } + newClass = (GrTypeDefinition)newFile.add(aClass); + correctOldClassReferences(newClass, aClass); + aClass.delete(); + } + else if (((GroovyFile)file).getClasses().length > 1) { correctSelfReferences(aClass, newPackage); String modifiersText = null; if (newPackage.getQualifiedName().equals(((GroovyFile)file).getPackageName())) { @@ -104,29 +143,54 @@ public class MoveGroovyClassHandler implements MoveClassHandler { correctOldClassReferences(newClass, aClass); aClass.delete(); } - else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) != null) { - // moving second of two classes which were in the same file to a different directory (IDEADEV-3089) - correctSelfReferences(aClass, newPackage); - PsiFile newFile = moveDestination.findFile(file.getName()); - TreeElement enter = Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, aClass.getManager()); - newFile.getNode().addChild(enter); - newClass = (GrTypeDefinition)newFile.add(aClass); - aClass.delete(); - } - else if (!moveDestination.equals(file.getContainingDirectory()) && moveDestination.findFile(file.getName()) == null) { - if (!moveDestination.equals(file.getContainingDirectory())) { - aClass.getManager().moveFile(file, moveDestination); - newClass = ((GroovyFile)file).getClasses()[0]; - if (!newPackage.getQualifiedName().equals(((GroovyFile)file).getPackageName())) { - ((PsiClassOwner)file).setPackageName(newPackage.getQualifiedName()); - } - } - } - //if (newClass != null) GroovyChangeContextUtil.decodeContextInfo(newClass, null, null); } return newClass; } + private static GroovyFile generateNewScript(GroovyFile file, PsiPackage newPackage) { + for (GrImportStatement importStatement : file.getImportStatements()) { + importStatement.delete(); + } + final GroovyFile newFile = GroovyPsiElementFactory.getInstance(file.getProject()).createGroovyFile("", true, null); + + newFile.addRange(file.getFirstChild(), file.getLastChild()); + + final PsiClass[] newFileClasses = newFile.getClasses(); + for (PsiClass psiClass : newFileClasses) { + if (psiClass instanceof GroovyScriptClass) continue; + final GrDocComment docComment = GrDocCommentUtil.findDocComment((GrDocCommentOwner)psiClass); + if (docComment != null) docComment.delete(); + psiClass.delete(); + } + + final GrPackageDefinition packageDefinition = newFile.getPackageDefinition(); + if (packageDefinition != null) packageDefinition.delete(); + + PsiElement cur = newFile.getFirstChild(); + while (cur != null && GroovyTokenTypes.WHITE_SPACES_SET.contains(cur.getNode().getElementType())) { + cur = cur.getNextSibling(); + } + if (cur != null && cur != newFile.getFirstChild()) { + cur = cur.getPrevSibling(); + newFile.deleteChildRange(newFile.getFirstChild(), cur); + } + + cur = newFile.getLastChild(); + while (cur != null && GroovyTokenTypes.WHITE_SPACES_SET.contains(cur.getNode().getElementType())) { + cur = cur.getPrevSibling(); + } + if (cur != null && cur != newFile.getLastChild()) { + cur = cur.getNextSibling(); + newFile.deleteChildRange(cur, newFile.getLastChild()); + } + + newFile.setName(file.getName()); + newFile.setPackageName(newPackage.getQualifiedName()); + + GroovyChangeContextUtil.decodeContextInfo(newFile, null, null); + return newFile; + } + @Nullable public String getName(PsiClass clazz) { final PsiFile file = clazz.getContainingFile(); @@ -136,14 +200,14 @@ public class MoveGroovyClassHandler implements MoveClassHandler { @Override public void prepareMove(@NotNull PsiClass aClass) { - if (aClass.getContainingClass() instanceof GroovyFileBase) { + if (aClass.getContainingFile() instanceof GroovyFileBase) { GroovyChangeContextUtil.encodeContextInfo(getRealElement(aClass)); } } @Override public void finishMoveClass(@NotNull PsiClass aClass) { - if (aClass.getContainingClass() instanceof GroovyFileBase) { + if (aClass.getContainingFile() instanceof GroovyFileBase) { GroovyChangeContextUtil.decodeContextInfo(getRealElement(aClass), null, null); } } @@ -153,7 +217,12 @@ public class MoveGroovyClassHandler implements MoveClassHandler { } private static void correctOldClassReferences(final PsiClass newClass, final PsiClass oldClass) { - for (PsiReference reference : ReferencesSearch.search(oldClass, new LocalSearchScope(newClass)).findAll()) { + final Collection all = ReferencesSearch.search(oldClass, new LocalSearchScope(newClass.getContainingFile())).findAll(); + for (PsiReference reference : all) { + final PsiElement element = reference.getElement(); + if (element.getParent() instanceof GrImportStatement) { + element.getParent().delete(); + } reference.bindToElement(newClass); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java index da4b71bc46d4..aaf003207fc0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveClassTest.java @@ -188,7 +188,7 @@ public class GroovyMoveClassTest extends LightCodeInsightFixtureTestCase { } }); - assertEquals(ch1.length, ch2.length); + assertEquals("check dir '"+d1.getName()+"': ", ch1.length, ch2.length); for (int i = 1; i < ch1.length; i++) { assertEquals(ch1[i].isDirectory(), ch2[i].isDirectory()); if (ch1[i].isDirectory() && !".svn".equals(ch1[i].getName())) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveScriptTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveScriptTest.java index f7f14f5a9f97..26a7488e07e3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveScriptTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/move/GroovyMoveScriptTest.java @@ -25,11 +25,15 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.*; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.refactoring.PackageWrapper; +import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor; import com.intellij.refactoring.move.moveClassesOrPackages.SingleSourceRootMoveDestination; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.plugins.groovy.util.TestUtils; import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * @author Maxim.Medvedev @@ -82,11 +86,15 @@ public class GroovyMoveScriptTest extends LightCodeInsightFixtureTestCase { assertNotNull("Directory " + newDirName + " not found", psiDirectory); final PsiPackage pkg = JavaDirectoryService.getInstance().getPackage(psiDirectory); - final SingleSourceRootMoveDestination destination = new SingleSourceRootMoveDestination(PackageWrapper.create(pkg), psiDirectory); + List classList = new ArrayList(); + for (PsiFile file : files) { + Collections.addAll(classList, ((PsiClassOwner)file).getClasses()); + } + final PsiClass[] classes = classList.toArray(new PsiClass[classList.size()]); new WriteCommandAction(myFixture.getProject()) { @Override protected void run(Result result) throws Throwable { - new MoveGroovyScriptProcessor(getProject(), files, destination, false, false, null).run(); + new MoveClassesOrPackagesProcessor(getProject(), classes, new SingleSourceRootMoveDestination(PackageWrapper.create(pkg), psiDirectory), true, true, null).run(); } }.execute(); diff --git a/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/A.groovy b/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/A.groovy new file mode 100644 index 000000000000..c5c7be735ef7 --- /dev/null +++ b/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/A.groovy @@ -0,0 +1,5 @@ +package b + +class A { + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/Foo.groovy b/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/Foo.groovy index cef6dbee0a46..1e55f195f6fc 100644 --- a/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/Foo.groovy +++ b/plugins/groovy/testdata/refactoring/move/moveScript/fileWithTwoClasses/after/b/Foo.groovy @@ -1,9 +1,4 @@ package b -class A { - def foo() { - print new B() - } -} class B { def bar() { From 9d9063bbb4300e80f2ffb53ea337c9306fab168f Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 6 Mar 2011 19:33:46 +0300 Subject: [PATCH 08/95] IDEA-66202: Groovy Extract Method Broken: Nested Closures drop 'it' reference --- .../GrReferenceExpressionImpl.java | 17 +--- .../plugins/groovy/lang/psi/util/PsiUtil.java | 80 +++++++++++++------ .../extractMethod/ExtractMethodTest.java | 1 + .../dontShortenRefsIncorrect.test | 7 ++ 4 files changed, 66 insertions(+), 39 deletions(-) create mode 100644 plugins/groovy/testdata/groovy/refactoring/extractMethod/dontShortenRefsIncorrect.test diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 495b287497b4..e54159c83bb6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -48,7 +48,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; @@ -437,8 +436,9 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl boolean shortenReference(GrQualifiedReference ref) { final Qualifier qualifier = ref.getQualifier(); - if (qualifier != null && !(qualifier instanceof GrSuperReferenceExpression) && - (PsiTreeUtil.getParentOfType(ref, GrDocMemberReference.class) != null || - PsiTreeUtil.getParentOfType(ref, GrDocComment.class) == null) && - PsiTreeUtil.getParentOfType(ref, GrImportStatement.class) == null && - PsiTreeUtil.getParentOfType(ref, GroovyCodeFragment.class) == null) { - final PsiElement resolved = ref.resolve(); - if (resolved != null) { - ref.setQualifier(null); - if (ref.isReferenceTo(resolved)) return true; + if (qualifier == null || qualifier instanceof GrSuperReferenceExpression || cannotShortenInContext(ref)) { + return false; + } + if (!canShorten(qualifier)) return false; - if (resolved instanceof PsiClass) { - final GroovyFileBase file = (GroovyFileBase)ref.getContainingFile(); - final PsiClass clazz = (PsiClass)resolved; - final String qName = clazz.getQualifiedName(); - if (qName != null) { - if (mayInsertImport(ref)) { - final GrImportStatement added = file.addImportForClass(clazz); - if (!ref.isReferenceTo(resolved)) { - file.removeImport(added); - } - } + final PsiElement resolved = ref.resolve(); + if (resolved == null) return false; + + ref.setQualifier(null); + if (ref.isReferenceTo(resolved)) return true; + + if (resolved instanceof PsiClass) { + final GroovyFileBase file = (GroovyFileBase)ref.getContainingFile(); + final PsiClass clazz = (PsiClass)resolved; + final String qName = clazz.getQualifiedName(); + if (qName != null) { + if (mayInsertImport(ref)) { + final GrImportStatement added = file.addImportForClass(clazz); + if (!ref.isReferenceTo(resolved)) { + file.removeImport(added); } } + } + } - if (!ref.isReferenceTo(resolved)) { - ref.setQualifier((Qualifier)qualifier.copy()); - return false; - } else { - return true; - } + if (!ref.isReferenceTo(resolved)) { + ref.setQualifier((Qualifier)qualifier.copy()); + return false; + } + else { + return true; + } + } + + private static boolean canShorten(Qualifier qualifier) { + if (qualifier instanceof GrCodeReferenceElement) return true; + if (qualifier instanceof GrExpression) { + if (qualifier instanceof GrThisReferenceExpression) return true; + if (seemsToBeQualifiedClassName((GrExpression)qualifier)) { + final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass || resolved instanceof PsiPackage) return true; } } return false; } + private static boolean cannotShortenInContext(GrQualifiedReference ref) { + return (PsiTreeUtil.getParentOfType(ref, GrDocMemberReference.class) == null && + PsiTreeUtil.getParentOfType(ref, GrDocComment.class) != null) || + PsiTreeUtil.getParentOfType(ref, GrImportStatement.class) != null || + PsiTreeUtil.getParentOfType(ref, GroovyCodeFragment.class) != null; + } + private static boolean mayInsertImport(GrQualifiedReference ref) { return PsiTreeUtil.getParentOfType(ref, GrDocComment.class) == null && !(ref.getContainingFile() instanceof GroovyCodeFragment) && @@ -1069,4 +1088,13 @@ public class PsiUtil { return ((GrListOrMap)firstArg).getNamedArguments(); } + + public static boolean seemsToBeQualifiedClassName(@Nullable GrExpression qualifier) { + if (qualifier == null) return false; + while (qualifier instanceof GrReferenceExpression) { + if (((GrReferenceExpression)qualifier).getReferenceNameElement() instanceof GrLiteral) return false; + qualifier = ((GrReferenceExpression)qualifier).getQualifierExpression(); + } + return qualifier == null; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java index 6697a9d1f111..386a7d4063e8 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java @@ -96,4 +96,5 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testMultiOutput4() {doTest();} public void testMultiOutput5() {doTest();} + public void testDontShortenRefsIncorrect() {doTest();} } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/dontShortenRefsIncorrect.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/dontShortenRefsIncorrect.test new file mode 100644 index 000000000000..f729cf2e6552 --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/dontShortenRefsIncorrect.test @@ -0,0 +1,7 @@ +print 1.getClass() +----- +testMethod() + +private def testMethod() { + print 1.getClass() +} From c0dc198a949cc1fd5897c6ce24125a80f3f8e2c6 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 6 Mar 2011 21:13:08 +0300 Subject: [PATCH 09/95] IDEA-66069 Groovy: AssertionError at GrTypeParameterImpl.getOwner() on incorrect generic method definition --- .../groovy/lang/psi/impl/types/GrTypeParameterImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterImpl.java index 3d4bc5692344..f1a372122fa5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrTypeParameterImpl.java @@ -313,8 +313,8 @@ public class GrTypeParameterImpl extends GrStubElementBase final PsiElement parent = getParent(); if (parent == null) throw new PsiInvalidElementAccessException(this); final PsiElement parentParent = parent.getParent(); - if (parentParent != null && !(parentParent instanceof PsiTypeParameterListOwner)) { - throw new AssertionError("CCE: " + parentParent); + if (!(parentParent instanceof PsiTypeParameterListOwner)) { + return null; } return (PsiTypeParameterListOwner)parentParent; } From edc07cad8e8a52d668f4d0bfd85361e1bffbce6f Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Sun, 6 Mar 2011 23:13:40 +0300 Subject: [PATCH 10/95] IDEA-66007 Groovy: Duplicated named arguments should be highlighted as error because it is compilation error. --- .../plugins/groovy/GroovyBundle.properties | 1 + .../groovy/annotator/GroovyAnnotator.java | 114 +++++++----------- .../groovy/lang/psi/GroovyElementVisitor.java | 2 +- .../statements/GrConstructorInvocation.java | 6 + .../impl/types/GrClosureSignatureUtil.java | 12 +- .../groovy/lang/GroovyHighlightingTest.java | 2 + .../highlighting/DuplicatedNamedArgs.groovy | 5 + 7 files changed, 64 insertions(+), 78 deletions(-) create mode 100644 plugins/groovy/testdata/highlighting/DuplicatedNamedArgs.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties index 7d372d9b73c1..061901668483 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyBundle.properties @@ -345,3 +345,4 @@ no.implements.clause.allowed.for.interface=No implements clause allowed for inte groovy.file.extension.is.not.mapped.to.groovy.file.type=*.groovy files are mapped to ''{0}''.\nYou can map them to Groovy in Settings | File types class.is.not.annotation=''{0}'' is not an annotation method.call.is.ambiguous=Method call is ambiguous +duplicated.named.parameter=Duplicated named parameter ''{0}'' found diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 5f0c0ca5b71a..47cce3e2ec68 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -25,7 +25,6 @@ import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.IndexNotReadyException; -import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -50,7 +49,10 @@ import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter; import org.jetbrains.plugins.groovy.findUsages.LiteralConstructorReference; import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter; import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil; -import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.*; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocFieldReference; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocMemberReference; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocMethodReference; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; @@ -104,18 +106,12 @@ import java.util.Set; /** * @author ven */ +@SuppressWarnings({"unchecked"}) public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.annotator.GroovyAnnotator"); - private static final Key CLEAR_IMPORTS = Key.create("ClearImports"); private AnnotationHolder myHolder; - private static boolean isDocCommentElement(PsiElement element) { - if (element == null) return false; - ASTNode node = element.getNode(); - return node != null && PsiTreeUtil.getParentOfType(element, GrDocComment.class) != null || element instanceof GrDocComment; - } - public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { if (element instanceof GroovyPsiElement) { myHolder = holder; @@ -424,20 +420,20 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { checkStaticDeclarationsInInnerClass((GrMember)variable, myHolder); } - GroovyPsiElement duplicate = - ResolveUtil - .resolveExistingElement(variable, new DuplicateVariablesProcessor(variable), GrVariable.class, GrReferenceExpression.class); + PsiNamedElement duplicate = ResolveUtil + .resolveExistingElement(variable, new DuplicateVariablesProcessor(variable), GrReferenceExpression.class, GrVariable.class); if (duplicate == null) { if (variable instanceof GrParameter) { + @SuppressWarnings({"ConstantConditions"}) final PsiElement parent = variable.getContext().getContext(); if (parent instanceof GrClosableBlock) { - duplicate = ResolveUtil - .resolveExistingElement((GrClosableBlock)parent, new DuplicateVariablesProcessor(variable), GrVariable.class, GrReferenceExpression.class); + duplicate = ResolveUtil.resolveExistingElement((GrClosableBlock)parent, new DuplicateVariablesProcessor(variable), + GrVariable.class, GrReferenceExpression.class); } } } - if (duplicate instanceof GrLightParameter && "args".equals(((GrLightParameter)duplicate).getName())) { + if (duplicate instanceof GrLightParameter && "args".equals(duplicate.getName())) { duplicate = null; } @@ -511,25 +507,32 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - MultiMap map = new MultiMap(); + checkNamedArgs(listOrMap.getNamedArguments(), false); + } - for (GrNamedArgument element : listOrMap.getNamedArguments()) { + private void checkNamedArgs(GrNamedArgument[] namedArguments, boolean forArgList) { + MultiMap map = new MultiMap(); + for (GrNamedArgument element : namedArguments) { final GrArgumentLabel label = element.getLabel(); if (label != null) { final String name = label.getName(); if (name != null) { - map.putValue(name, element); + map.putValue(name, label); } } } for (String key : map.keySet()) { - final Collection arguments = map.get(key); + final List arguments = (List)map.get(key); if (arguments.size() > 1) { - final List args = new ArrayList(arguments); - for (int i = 1; i < args.size(); i++) { - GrNamedArgument namedArgument = args.get(i); - myHolder.createWarningAnnotation(namedArgument.getLabel(), GroovyBundle.message("duplicate.element.in.the.map")); + for (int i = 1; i < arguments.size(); i++) { + final GrArgumentLabel label = arguments.get(i); + if (forArgList) { + myHolder.createErrorAnnotation(label, GroovyBundle.message("duplicated.named.parameter", key)); + } + else { + myHolder.createWarningAnnotation(label, GroovyBundle.message("duplicate.element.in.the.map")); + } } } } @@ -626,6 +629,11 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } + @Override + public void visitArgumentList(GrArgumentList list) { + checkNamedArgs(list.getNamedArguments(), true); + } + @Override public void visitDocMethodReference(GrDocMethodReference reference) { checkGrDocMemberReference(reference, myHolder); @@ -681,7 +689,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(psiDirectory); if (aPackage != null) { String packageName = aPackage.getQualifiedName(); - if (!packageDefinition.getPackageName().equals(packageName)) { + if (!packageName.equals(packageDefinition.getPackageName())) { final Annotation annotation = myHolder.createWarningAnnotation(packageDefinition, "wrong package name"); annotation.registerFix(new ChangePackageQuickFix((GroovyFile)packageDefinition.getContainingFile(), packageName)); } @@ -1005,14 +1013,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - else if (containingTypeDef.isEnum()) { - //enumeration - //todo - } - else if (containingTypeDef.isAnnotationType()) { - //annotation - //todo - } else if (containingTypeDef.isAnonymous()) { //anonymous class if (isMethodStatic) { @@ -1070,7 +1070,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - catch (IndexNotReadyException e) { + catch (IndexNotReadyException ignored) { + //nothing to do } } @@ -1165,17 +1166,19 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } private static void checkDuplicateMethod(GrMethod[] methods, AnnotationHolder holder) { - MultiMap map = GrClosureSignatureUtil.findMethodSignatures(methods); + MultiMap map = GrClosureSignatureUtil.findMethodSignatures(methods); processMethodDuplicates(map, holder); } - protected static void processMethodDuplicates(MultiMap map, AnnotationHolder holder) { + protected static void processMethodDuplicates(MultiMap map, AnnotationHolder holder) { for (MethodSignature signature : map.keySet()) { - Collection methods = map.get(signature); + Collection methods = map.get(signature); if (methods.size() > 1) { String signaturePresentation = GroovyPresentationUtil.getSignaturePresentation(signature); - for (PsiMethod method : methods) { - holder.createErrorAnnotation(method.getNameIdentifier(), GroovyBundle.message("method.duplicate", signaturePresentation, method.getContainingClass().getName())); + for (GrMethod method : methods) { + //noinspection ConstantConditions + holder.createErrorAnnotation(method.getNameIdentifierGroovy(), GroovyBundle.message("method.duplicate", signaturePresentation, + method.getContainingClass().getName())); } } } @@ -1222,16 +1225,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { checkForExtendingInterface(holder, extendsClause, implementsClause, ((GrTypeDefinition)extendsClause.getParent())); } - /* - if (implementsClause != null) { - checkForImplementingClass(holder, extendsClause, implementsClause, ((GrTypeDefinition)implementsClause.getParent())); - } - - if (extendsClause != null) { - checkForExtendingInterface(holder, extendsClause, implementsClause, ((GrTypeDefinition)extendsClause.getParent())); - } - */ - checkForWildCards(holder, extendsClause); checkForWildCards(holder, implementsClause); @@ -1346,28 +1339,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - private static void checkForImplementingClass(AnnotationHolder holder, - GrExtendsClause extendsClause, - GrImplementsClause implementsClause, - GrTypeDefinition myClass) { - if (myClass.isInterface()) { - final Annotation annotation = - holder.createErrorAnnotation(implementsClause, GroovyBundle.message("interface.cannot.contain.implements.clause")); - annotation.registerFix(new ChangeExtendsImplementsQuickFix(extendsClause, implementsClause)); - return; - } - - for (GrCodeReferenceElement ref : implementsClause.getReferenceElements()) { - final PsiElement clazz = ref.resolve(); - if (clazz == null) continue; - - if (!((PsiClass)clazz).isInterface()) { - final Annotation annotation = holder.createErrorAnnotation(ref, GroovyBundle.message("interface.expected.here")); - annotation.registerFix(new ChangeExtendsImplementsQuickFix(extendsClause, implementsClause)); - } - } - } - private static void checkGrDocMemberReference(final GrDocMemberReference reference, AnnotationHolder holder) { PsiElement resolved = reference.resolve(); if (resolved == null) { @@ -1522,7 +1493,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { final PsiElement nameElement = label.getNameElement(); if (nameElement instanceof GrExpression) { final PsiType stringType = TypesUtil.createType(CommonClassNames.JAVA_LANG_STRING, arg); - if (!TypesUtil.isAssignable(stringType, ((GrExpression)nameElement).getType(), arg)) { + final PsiType argType = ((GrExpression)nameElement).getType(); + if (argType != null && !TypesUtil.isAssignable(stringType, argType, arg)) { holder.createWarningAnnotation(nameElement, GroovyBundle.message("property.name.expected")); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java index c7a87505d677..6da5d04023db 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GroovyElementVisitor.java @@ -298,7 +298,7 @@ public abstract class GroovyElementVisitor { } public void visitConstructorInvocation(GrConstructorInvocation invocation) { - visitElement(invocation); + visitStatement(invocation); } public void visitThrowsClause(GrThrowsClause throwsClause) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrConstructorInvocation.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrConstructorInvocation.java index a3adb540c85f..19f049ea6fd1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrConstructorInvocation.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/GrConstructorInvocation.java @@ -16,7 +16,9 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements; import com.intellij.psi.PsiClass; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrConstructorCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrThisSuperReferenceExpression; @@ -33,4 +35,8 @@ public interface GrConstructorInvocation extends GrStatement, GrConstructorCall @Nullable PsiClass getDelegatedClass(); + + @Override + @NotNull + GrArgumentList getArgumentList(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java index a7baeb69f644..0d08f068148b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrClosureSignatureUtil.java @@ -512,9 +512,9 @@ public class GrClosureSignatureUtil { return generateAllMethodSignaturesByClosureSignature(name, signature, typeParameters, substitutor); } - public static MultiMap findMethodSignatures(PsiMethod[] methods) { - List> signatures = new ArrayList>(); - for (PsiMethod method : methods) { + public static MultiMap findMethodSignatures(Method[] methods) { + List> signatures = new ArrayList>(); + for (Method method : methods) { List current; if (method instanceof GrMethod) { current = generateAllSignaturesForMethod((GrMethod)method, PsiSubstitutor.EMPTY); @@ -523,12 +523,12 @@ public class GrClosureSignatureUtil { current = Collections.singletonList(method.getSignature(PsiSubstitutor.EMPTY)); } for (MethodSignature signature : current) { - signatures.add(new Pair(signature, method)); + signatures.add(new Pair(signature, method)); } } - MultiMap map = new MultiMap(); - for (Pair pair : signatures) { + MultiMap map = new MultiMap(); + for (Pair pair : signatures) { map.putValue(pair.first, pair.second); } return map; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index 31375bacd0dd..ecbc59ae27d0 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -363,4 +363,6 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { myFixture.configureByText("a.txt", psiAfter); myFixture.checkResultByFile(getTestName(false) + "2.txt"); } + + public void testDuplicatedNamedArgs() {doTest();} } \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/DuplicatedNamedArgs.groovy b/plugins/groovy/testdata/highlighting/DuplicatedNamedArgs.groovy new file mode 100644 index 000000000000..0c0cea0ae915 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/DuplicatedNamedArgs.groovy @@ -0,0 +1,5 @@ +def foo(Map map) { + +} + +foo(a:2, "a":2); \ No newline at end of file From 3df58b681b161c40c452aa778a3f2b4f56650ee5 Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 7 Mar 2011 10:46:05 +0100 Subject: [PATCH 11/95] extract method dialog: cosmetics: space between (IDEA-66099) --- .../refactoring/extractMethod/ExtractMethodDialog.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java index c5637ed8a6ce..a935d6046c5a 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java @@ -373,8 +373,11 @@ public class ExtractMethodDialog extends AbstractExtractDialog { buffer.append("static "); } if (myTypeParameterList != null) { - buffer.append(myTypeParameterList.getText()); - buffer.append(" "); + final String typeParamsText = myTypeParameterList.getText(); + if (!typeParamsText.isEmpty()) { + buffer.append(typeParamsText); + buffer.append(" "); + } } if (isChainedConstructor()) { From 32c493302d72006b440b39de52171ed1407d688a Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 7 Mar 2011 11:10:00 +0100 Subject: [PATCH 12/95] base refactorings: check for element at caret language if no context element found (IDEA-66166 ) --- .../intellij/refactoring/actions/BaseRefactoringAction.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java index cd9b719d660a..db42a641c67e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java @@ -126,14 +126,18 @@ public abstract class BaseRefactoringAction extends AnAction { } else { PsiElement element = e.getData(LangDataKeys.PSI_ELEMENT); + Language[] languages = e.getData(LangDataKeys.CONTEXT_LANGUAGES); if (element == null || !isAvailableForLanguage(element.getLanguage())) { if (file == null) { hideAction(e); return; } element = getElementAtCaret(editor, file); + if (element != null) { + languages = new Language[] {element.getLanguage()}; + } } - Language[] languages = e.getData(LangDataKeys.CONTEXT_LANGUAGES); + if (element == null || element instanceof SyntheticElement || languages == null) { hideAction(e); return; From 9372039c595b4f6815b0d4fbb5362b611b44c0e2 Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 7 Mar 2011 11:14:43 +0100 Subject: [PATCH 13/95] NPE (IDEA-66164) --- .../com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java b/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java index 8c951540a383..6b036bc933d1 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java @@ -16,6 +16,7 @@ package com.intellij.psi.controlFlow; import com.intellij.psi.*; +import org.jetbrains.annotations.Nullable; public class LocalsControlFlowPolicy implements ControlFlowPolicy { private final PsiElement myCodeFragment; @@ -36,6 +37,7 @@ public class LocalsControlFlowPolicy implements ControlFlowPolicy { } } + @Nullable private PsiVariable checkCodeFragment(PsiElement refElement) { PsiElement codeFragement; if (refElement instanceof PsiParameter @@ -45,6 +47,7 @@ public class LocalsControlFlowPolicy implements ControlFlowPolicy { else{ codeFragement = ControlFlowUtil.findCodeFragment(refElement); } + if (codeFragement == null) return null; if (myCodeFragment.getContainingFile() == codeFragement.getContainingFile() && //In order for jsp includes to work !myCodeFragment.equals(codeFragement)) return null; return (PsiVariable)refElement; From d4fae71f3811d5a6ba33afb0f7f91e04d7a3bd39 Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 7 Mar 2011 11:27:42 +0100 Subject: [PATCH 14/95] introduce constant in non existing class: NPE (IDEA-66180) --- .../refactoring/introduceField/IntroduceConstantDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantDialog.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantDialog.java index c61a82d31b32..8fcb8390d532 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceConstantDialog.java @@ -397,7 +397,7 @@ class IntroduceConstantDialog extends DialogWrapper { errorString = RefactoringBundle.message("no.field.name.specified"); } else if (!JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(fieldName)) { errorString = RefactoringMessageUtil.getIncorrectIdentifierMessage(fieldName); - } else if (!myParentClass.getLanguage().equals(newClass.getLanguage())) { + } else if (newClass != null && !myParentClass.getLanguage().equals(newClass.getLanguage())) { errorString = RefactoringBundle.message("move.to.different.language", UsageViewUtil.getType(myParentClass), myParentClass.getQualifiedName(), newClass.getQualifiedName()); } From bb8d65f436432340dc8ffbb803a50cb21b49068d Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 7 Mar 2011 15:16:33 +0100 Subject: [PATCH 15/95] reduce mem usage when traversing Psi --- .../ChangedConstantsDependencyProcessor.java | 72 +++++++++++-------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/make/ChangedConstantsDependencyProcessor.java b/java/compiler/impl/src/com/intellij/compiler/make/ChangedConstantsDependencyProcessor.java index fde5ee1fe91e..e4102a9899f5 100644 --- a/java/compiler/impl/src/com/intellij/compiler/make/ChangedConstantsDependencyProcessor.java +++ b/java/compiler/impl/src/com/intellij/compiler/make/ChangedConstantsDependencyProcessor.java @@ -27,6 +27,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.*; @@ -88,7 +89,7 @@ class ChangedConstantsDependencyProcessor { } } catch (CacheCorruptedException e) { - _ex[0] = e; + _ex[0] = e; } catch (ProcessCanceledException e) { // supressed deliberately @@ -100,7 +101,7 @@ class ChangedConstantsDependencyProcessor { } } - private void processFieldRemoved(FieldInfo info, PsiClass aClass) throws CacheCorruptedException { + private void processFieldRemoved(FieldInfo info, final PsiClass aClass) throws CacheCorruptedException { if (info.isPrivate()) { return; // optimization: don't need to search, cause may be used only in this class } @@ -118,41 +119,54 @@ class ChangedConstantsDependencyProcessor { } final PsiSearchHelper psiSearchHelper = PsiManager.getInstance(myProject).getSearchHelper(); + final Ref exRef = new Ref(null); final long analysisStart = System.currentTimeMillis(); - boolean skipResolve = mySkipExpressionResolve; - - PsiIdentifier[] identifiers = findIdentifiers(psiSearchHelper, myDependencyCache.resolve(info.getName()), searchScope, UsageSearchContext.IN_CODE); - for (PsiIdentifier identifier : identifiers) { - PsiElement parent = identifier.getParent(); - if (parent instanceof PsiReferenceExpression) { - PsiReferenceExpression refExpr = (PsiReferenceExpression)parent; - PsiReference reference = refExpr.getReference(); - skipResolve = skipResolve || (System.currentTimeMillis() - analysisStart) > ANALYSIS_DURATION_THRESHOLD_MILLIS; - if (skipResolve || reference == null || reference.resolve() == null) { - PsiClass ownerClass = getOwnerClass(refExpr); - if (ownerClass != null && !ownerClass.equals(aClass)) { - int qualifiedName = myDependencyCache.getSymbolTable().getId(ownerClass.getQualifiedName()); - // should force marking of the class no matter was it compiled or not - // This will ensure the class was recompiled _after_ all the constants get their new values - if (myDependencyCache.markClass(qualifiedName, true)) { - if (LOG.isDebugEnabled()) { - LOG.debug("Mark dependent class " + myDependencyCache.resolve(qualifiedName) + - "; reason: some constants were removed from " + myDependencyCache.resolve(myQName)); + + processIdentifiers(psiSearchHelper, new PsiElementProcessor() { + private boolean skipResolve = mySkipExpressionResolve; + @Override + public boolean execute(PsiIdentifier identifier) { + try { + final PsiElement parent = identifier.getParent(); + if (parent instanceof PsiReferenceExpression) { + PsiReferenceExpression refExpr = (PsiReferenceExpression)parent; + PsiReference reference = refExpr.getReference(); + skipResolve = skipResolve || (System.currentTimeMillis() - analysisStart) > ANALYSIS_DURATION_THRESHOLD_MILLIS; + if (skipResolve || reference == null || reference.resolve() == null) { + final PsiClass ownerClass = getOwnerClass(refExpr); + if (ownerClass != null && !ownerClass.equals(aClass)) { + final String _qName = ownerClass.getQualifiedName(); + if (_qName != null) { + int qualifiedName = myDependencyCache.getSymbolTable().getId(_qName); + // should force marking of the class no matter was it compiled or not + // This will ensure the class was recompiled _after_ all the constants get their new values + if (myDependencyCache.markClass(qualifiedName, true)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Mark dependent class " + myDependencyCache.resolve(qualifiedName) + "; reason: some constants were removed from " + myDependencyCache.resolve(myQName)); + } + } + } + else { + LOG.warn("Class with null qualified name was not expected here: " + ownerClass); + } } } } + return true; + } + catch (CacheCorruptedException e) { + exRef.set(e); + return false; } } + }, myDependencyCache.resolve(info.getName()), searchScope, UsageSearchContext.IN_CODE); + + final CacheCorruptedException cacheCorruptedException = exRef.get(); + if (cacheCorruptedException != null) { + throw cacheCorruptedException; } } - @NotNull - private static PsiIdentifier[] findIdentifiers(PsiSearchHelper helper, @NotNull String identifier, @NotNull SearchScope searchScope, short searchContext) { - PsiElementProcessor.CollectElements processor = new PsiElementProcessor.CollectElements(); - processIdentifiers(helper, processor, identifier, searchScope, searchContext); - return processor.toArray(PsiIdentifier.EMPTY_ARRAY); - } - private static boolean processIdentifiers(PsiSearchHelper helper, @NotNull final PsiElementProcessor processor, @NotNull final String identifier, @@ -196,7 +210,7 @@ class ChangedConstantsDependencyProcessor { if (myDependencyCache.markClass(qualifiedName, true)) { if (LOG.isDebugEnabled()) { LOG.debug("Marked dependent class " + myDependencyCache.resolve(qualifiedName) + "; reason: constants changed in " + - myDependencyCache.resolve(myQName)); + myDependencyCache.resolve(myQName)); } } } From 539c6b24b8d6d3e48acdee32e310796e41b5b5bb Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 7 Mar 2011 18:20:31 +0100 Subject: [PATCH 16/95] fix document leak in tests --- .../src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java index f8008c47e39f..b2578293b317 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiToDocumentSynchronizer.java @@ -205,9 +205,11 @@ public class PsiToDocumentSynchronizer extends PsiTreeChangeAdapter { mySyncDocument = null; } } - + + @TestOnly public void doCommitTransaction(final Document document){ doCommitTransaction(document, getTransaction(document)); + myBus.syncPublisher(PsiDocumentTransactionListener.TOPIC).transactionCompleted(document, null); } private static void doCommitTransaction(final Document document, final DocumentChangeTransaction documentChangeTransaction) { From 2099206254e14269ee73ed6f76808cb805342bd6 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 18:14:16 +0100 Subject: [PATCH 17/95] forget about the hint autopopup as of a nightmare --- .../completion/CodeCompletionHandlerBase.java | 2 +- .../CompletionProgressIndicator.java | 12 +- .../codeInsight/lookup/impl/EndHandler.java | 2 +- .../codeInsight/lookup/impl/HomeHandler.java | 2 +- .../lookup/impl/LookupActionHandler.java | 23 +-- .../codeInsight/lookup/impl/LookupImpl.java | 169 +----------------- .../impl/actions/ChooseItemReplaceAction.java | 2 +- .../src/misc/registry.properties | 4 +- 8 files changed, 17 insertions(+), 199 deletions(-) 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 bc2278885174..4a55ff85d4be 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -219,7 +219,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { @NotNull private LookupImpl obtainLookup(Editor editor) { LookupImpl existing = (LookupImpl)LookupManager.getActiveLookup(editor); - if (existing != null && existing.isCompletion() && !existing.isHintMode()) { + if (existing != null && existing.isCompletion()) { existing.markReused(); if (!autopopup) { existing.setFocused(true); 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 fd4f81c6cf2a..5fd530db23e3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -38,7 +38,6 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; import com.intellij.psi.PsiReference; @@ -329,22 +328,13 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } } - if (isAutopopupCompletion() && showHintAutopopup()) { - myLookup.setHintMode(true); - } - else { - myLookup.show(); - } + myLookup.show(); } myLookup.refreshUi(); hideAutopopupIfMeaningless(); updateFocus(); } - public static boolean showHintAutopopup() { - return "true".equals(Registry.stringValue("hint.autopopup")) && !ApplicationManager.getApplication().isUnitTestMode(); - } - final boolean isInsideIdentifier() { return getIdentifierEndOffset() != getSelectionEndOffset(); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/EndHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/EndHandler.java index 8c443306c5f5..419d88935ad3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/EndHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/EndHandler.java @@ -31,7 +31,7 @@ public class EndHandler extends EditorActionHandler { public void execute(Editor editor, DataContext dataContext){ LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); - if (lookup == null || !lookup.isFocused() || lookup.isHintMode()) { + if (lookup == null || !lookup.isFocused()) { myOriginalHandler.execute(editor, dataContext); return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/HomeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/HomeHandler.java index badc854bea87..a8699b9454c8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/HomeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/HomeHandler.java @@ -31,7 +31,7 @@ public class HomeHandler extends EditorActionHandler { public void execute(Editor editor, DataContext dataContext){ LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); - if (lookup == null || !lookup.isFocused() || lookup.isHintMode()) { + if (lookup == null || !lookup.isFocused()) { myOriginalHandler.execute(editor, dataContext); return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java index 1530694e87f1..76fa7b940f9e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupActionHandler.java @@ -98,16 +98,8 @@ public abstract class LookupActionHandler extends EditorActionHandler { public void actionPerformed(AnActionEvent e) { LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(PlatformDataKeys.EDITOR.getData(e.getDataContext())); assert lookup != null; - if (!CompletionProgressIndicator.showHintAutopopup()) { - lookup.hide(); - ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP).actionPerformed(e); - return; - } - - - lookup.setHintMode(false); - lookup.refreshUi(); - UpHandler.executeUp(lookup); + lookup.hide(); + ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP).actionPerformed(e); } @Override @@ -123,15 +115,8 @@ public abstract class LookupActionHandler extends EditorActionHandler { public void actionPerformed(AnActionEvent e) { LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(PlatformDataKeys.EDITOR.getData(e.getDataContext())); assert lookup != null; - if (!CompletionProgressIndicator.showHintAutopopup()) { - lookup.hide(); - ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN).actionPerformed(e); - return; - } - - lookup.setHintMode(false); - lookup.refreshUi(); - DownHandler.executeDown(lookup); + lookup.hide(); + ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN).actionPerformed(e); } @Override 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 63f067a96829..7e208378234c 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 @@ -35,10 +35,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.*; -import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopup; @@ -51,7 +48,10 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.DebugUtil; -import com.intellij.ui.*; +import com.intellij.ui.LightweightHint; +import com.intellij.ui.ListScrollingUtil; +import com.intellij.ui.ScreenUtil; +import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBList; import com.intellij.ui.plaf.beg.BegPopupMenuBorder; @@ -60,7 +60,6 @@ import com.intellij.util.CollectConsumer; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.AsyncProcessIcon; -import com.intellij.util.ui.GridBag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -69,7 +68,6 @@ import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; -import javax.swing.border.MatteBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; @@ -391,7 +389,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { if (!model.isEmpty()) { myList.setFixedCellWidth(Math.max(myLookupTextWidth + myCellRenderer.getIconIndent(), myAdComponent.getPreferredSize().width)); - if (isFocused() && (!isExactPrefixItem(model.iterator().next()) || mySelectionTouched) && !isHintMode()) { + if (isFocused() && (!isExactPrefixItem(model.iterator().next()) || mySelectionTouched)) { restoreSelection(oldSelected, hasPreselected, oldInvariant); } else { @@ -481,22 +479,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { model.addElement(item); } - public void setHintMode(final boolean hintMode) { - if (!hintMode) { - hideAutopopupHint(); - markSelectionTouched(); - setFocused(true); - if (!myShown) { - show(); - } - } - myHintMode = hintMode; - } - - public boolean isHintMode() { - return myHintMode; - } - private static LookupElementPresentation renderItemApproximately(LookupElement item) { final LookupElementPresentation p = new LookupElementPresentation(); item.renderElement(p); @@ -1109,8 +1091,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { myDisposed = true; disposeTrace = DebugUtil.currentStackTrace(); - - hideAutopopupHint(); } private int doSelectMostPreferableItem(List items) { @@ -1139,156 +1119,21 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { updateList(); - final Editor editor = myEditor; if (isVisible()) { LOG.assertTrue(!ApplicationManager.getApplication().isUnitTestMode()); - if (editor.getComponent().getRootPane() == null) { + if (myEditor.getComponent().getRootPane() == null) { LOG.error("Null root pane"); } updateScrollbarVisibility(); - HintManagerImpl.adjustEditorHintPosition(this, editor, calculatePosition(getComponent())); + HintManagerImpl.adjustEditorHintPosition(this, myEditor, calculatePosition(getComponent())); layoutStatusIcons(); if (reused) { ensureSelectionVisible(); } } - else if (myHintMode) { - final int itemTextPadding = 2; - - final JPanel hintComponent = createAutopopupHintComponent(itemTextPadding); - Point bestPoint = calculatePosition(hintComponent); - bestPoint.x += myCellRenderer.getIconIndent() - itemTextPadding; - Point editorPoint = SwingUtilities.convertPoint( - editor.getComponent().getRootPane().getLayeredPane(), - bestPoint, - editor.getContentComponent() - ); - - final HintHint hintHint = new HintHint(editor, editorPoint); - - final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl(); - if (myAutopopupHint == null) { - final JPanel panel = new JPanel(new BorderLayout()); - panel.add(hintComponent); - myAutopopupHint = new MyLightweightHint(panel); - myAutopopupHint.setForceShowAsPopup(true); - hintManager.showEditorHint(myAutopopupHint, editor, new Point(bestPoint), - HintManagerImpl.HIDE_BY_ESCAPE | HintManagerImpl.UPDATE_BY_SCROLLING, 0, false, hintHint); - } else { - final JComponent panel = myAutopopupHint.getComponent(); - panel.remove(0); - panel.add(hintComponent); - HintManagerImpl.adjustEditorHintPosition(myAutopopupHint, editor, bestPoint); - } - } - } - - private JPanel createAutopopupHintComponent(int itemTextPadding) { - int maxAutopopupItems = 7; - JPanel pane = new JPanel(new GridBagLayout()); - pane.setBackground(HintUtil.INFORMATION_COLOR); - - final Font editorFont = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN); - final String ctrlSpace = KeymapUtil.getFirstKeyboardShortcutText( - ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION)); - final String ctrlDown = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("EditorLookupDown")); - final String tab = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE)); - final String enter = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM)); - - final List items = getItems(); - GridBag gb = new GridBag().setDefaultFill(GridBagConstraints.HORIZONTAL).setDefaultWeightX(1); - for (int i = 0; i < Math.min(maxAutopopupItems, items.size()); i++) { - final LookupElement element = items.get(i); - final LookupElementPresentation presentation = new LookupElementPresentation(); - element.renderElement(presentation); - - { - final GridBagLayout gridBagLayout = new GridBagLayout(); - final JPanel row = new JPanel(gridBagLayout); - row.setOpaque(false); - - GridBag rgb = new GridBag().setDefaultAnchor(GridBagConstraints.BASELINE); - - final SimpleColoredComponent nameLabel = new SimpleColoredComponent(); - nameLabel.setIpad(new Insets(0, 0, 0, 0)); - nameLabel.setFont(editorFont); - final int style = presentation.isItemTextBold() ? Font.BOLD : Font.PLAIN; - myCellRenderer.renderItemName(element, LookupCellRenderer.FOREGROUND_COLOR, false, style, - StringUtil.notNullize(presentation.getItemText()), nameLabel); - nameLabel.setOpaque(false); - row.add(nameLabel, rgb.next()); - - final JLabel tailLabel = normalizedLabel(presentation.getTailText(), editorFont); - tailLabel.setForeground(LookupCellRenderer.getTailTextColor(false, presentation, tailLabel.getForeground())); - row.add(tailLabel, rgb.next()); - - String keys = i == 0 ? " [" + tab + (isFocused() ? ", " + enter : "") + "]" : i == 1 ? " [" + ctrlDown + "]" : ""; - JLabel adLabel = new JLabel(keys); - adLabel.setFont(adLabel.getFont().deriveFont(Font.BOLD, editorFont.getSize())); - row.add(adLabel, rgb.next().weightx(1).fillCellHorizontally()); - - row.add(normalizedLabel(" " + StringUtil.notNullize(presentation.getTypeText()) + " ", editorFont), rgb.next()); - - if (i == 1) { - row.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(5, 0, 0, 0), - BorderFactory.createCompoundBorder(new MatteBorder(1, 0, 0, 0, Color.lightGray), - new EmptyBorder(5, itemTextPadding, 0, 0)))); - } - else { - row.setBorder(new EmptyBorder(0, itemTextPadding, 0, 0)); - } - - - row.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - setCurrentItem(element); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - finishLookup(NORMAL_SELECT_CHAR); - } - }, "", null); - } - }); - - pane.add(row, gb.nextLine()); - } - - } - - if (items.size() > maxAutopopupItems) { - final JPanel lastLine = new JPanel(new BorderLayout()); - lastLine.setBorder(new EmptyBorder(4, 0, 2, 0)); - lastLine.setOpaque(false); - - JLabel moreLabel = new JLabel(" " + (items.size() - maxAutopopupItems) + " more"); - moreLabel.setFont(moreLabel.getFont().deriveFont(Font.ITALIC, editorFont.getSize())); - lastLine.add(moreLabel, BorderLayout.WEST); - - JLabel keyLabel = new JLabel(" [" + ctrlSpace + "]"); - keyLabel.setFont(keyLabel.getFont().deriveFont(Font.BOLD, editorFont.getSize())); - lastLine.add(keyLabel); - - pane.add(lastLine, gb.nextLine().padx(5).pady(2).coverColumn()); - } - - return pane; - } - - private static JLabel normalizedLabel(String text, Font font) { - JLabel label = new JLabel(text); - label.setFont(label.getFont().deriveFont(Font.PLAIN, font.getSize())); - return label; - } - - private void hideAutopopupHint() { - if (myAutopopupHint != null) { - myAutopopupHint.justHide(); - myPositionedAbove = null; - } } private void layoutStatusIcons() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java index 6ce7bbbec8a7..77bb54608f9b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/actions/ChooseItemReplaceAction.java @@ -46,7 +46,7 @@ public class ChooseItemReplaceAction extends EditorAction { FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_REPLACE); LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(editor); assert lookup != null; - lookup.finishLookup(lookup.isHintMode() ? Lookup.NORMAL_SELECT_CHAR : Lookup.REPLACE_SELECT_CHAR); + lookup.finishLookup(Lookup.REPLACE_SELECT_CHAR); } @Override diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index d71e316e438b..7e58a12cb257 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -116,6 +116,4 @@ vcs.show.history.numbers=true navbar.updateMergeTime=250 navbar.userActivityMergeTime=500 -inspectionGadgets.telemetry.enabled=false - -hint.autopopup=true \ No newline at end of file +inspectionGadgets.telemetry.enabled=false \ No newline at end of file From a2235cb13e802190723978d4d3eccdf00e4a2661 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 19:43:40 +0100 Subject: [PATCH 18/95] an ability to show several ads in one completion --- .../codeInsight/lookup/impl/Advertiser.java | 126 ++++++++++++++++++ .../codeInsight/lookup/impl/LookupImpl.java | 43 ++---- 2 files changed, 136 insertions(+), 33 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java new file mode 100644 index 000000000000..05f11f4f6cea --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java @@ -0,0 +1,126 @@ +/* + * Copyright 2000-2011 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.lookup.impl; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.util.ui.Animator; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author peter + */ +public class Advertiser implements Disposable { + public static final int ourScrollingResolution = 15; + private final List myTexts = new CopyOnWriteArrayList(); + private final JPanel myComponent = new JPanel() { + + @Override + public Dimension getPreferredSize() { + List texts = getTexts(); + if (texts.isEmpty()) return new Dimension(0, 0); + + FontMetrics fm = getFontMetrics(adFont()); + int w = 0; + for (String text : texts) { + w = Math.max(w, fm.stringWidth(text)); + } + + Insets insets = getBorder().getBorderInsets(this); + return new Dimension(w + insets.left + insets.right, fm.getHeight() + insets.top + insets.bottom); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + List texts = getTexts(); + if (texts.isEmpty()) return; + + Font font = adFont(); + FontMetrics metrics = g.getFontMetrics(font); + g.setFont(font); + + int height = getHeight(); + int y = (height - metrics.getHeight()) / 2 + metrics.getAscent() - (myScrollingOffset * height / ourScrollingResolution); + int x = getBorder().getBorderInsets(this).left; + + g.drawString(texts.get(myCurrentItem), x, y); + if (myScrollingOffset != 0) { + g.drawString(texts.get((myCurrentItem + 1) % texts.size()), x, y + height); + } + } + }; + private int myCurrentItem = 0; + private int myScrollingOffset = 0; + + public Advertiser(Disposable parentDisposable) { + Disposer.register(parentDisposable, this); + } + + private synchronized List getTexts() { + return new ArrayList(myTexts); + } + + private static Font adFont() { + Font font = UIUtil.getLabelFont(); + return font.deriveFont((float)(font.getSize() - 2)); + } + + public synchronized void addAdvertisement(@NotNull String text) { + myTexts.add(text); + if (myTexts.size() == 2) { + int interCycleGap = 4000; + Animator animator = new Animator("completion ad", ourScrollingResolution, 800, true, interCycleGap, -1) { + boolean first = true; + @Override + public void paintNow(float frame, float totalFrames, float cycle) { + if (first && frame > 0) { + return; + } + + myScrollingOffset = (int)frame; + if (myScrollingOffset == 0) { + if (first) { + first = false; + } else { + myCurrentItem = (myCurrentItem + 1) % getTexts().size(); + } + } + myComponent.paintImmediately(0, 0, myComponent.getWidth(), myComponent.getHeight()); + } + }; + animator.setTakInitialDelay(true); + animator.resume(); + Disposer.register(this, animator); + } + } + + public JComponent getAdComponent() { + return myComponent; + } + + @Override + public void dispose() { + } +} 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 7e208378234c..ac3946c1c986 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 @@ -22,7 +22,6 @@ import com.intellij.codeInsight.completion.PrefixMatcher; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; -import com.intellij.codeInsight.hint.HintUtil; import com.intellij.codeInsight.lookup.*; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.ui.UISettings; @@ -113,7 +112,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { private final AsyncProcessIcon myProcessIcon = new AsyncProcessIcon("Completion progress"); private final JPanel myIconPanel = new JPanel(new BorderLayout()); private volatile boolean myCalculating; - private final JLabel myAdComponent; + private final Advertiser myAdComponent; private volatile String myAdText; private volatile int myLookupTextWidth = 50; private boolean myReused; @@ -123,8 +122,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { private Alarm myHintAlarm = new Alarm(); private JLabel mySortingLabel; private final JScrollPane myScrollPane; - private boolean myHintMode; - private MyLightweightHint myAutopopupHint; public LookupImpl(Project project, Editor editor, @NotNull LookupArranger arranger){ super(new JPanel(new BorderLayout())); @@ -148,8 +145,10 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { getComponent().add(myScrollPane, BorderLayout.NORTH); myScrollPane.setBorder(null); - myAdComponent = HintUtil.createAdComponent(null, new EmptyBorder(1, 2, 1, 2 + relevanceSortIcon.getIconWidth())); - getComponent().add(myAdComponent, BorderLayout.SOUTH); + myAdComponent = new Advertiser(this); + JComponent adComponent = myAdComponent.getAdComponent(); + adComponent.setBorder(new EmptyBorder(0, 1, 1, 2 + relevanceSortIcon.getIconWidth())); + getComponent().add(adComponent, BorderLayout.SOUTH); getComponent().setBorder(new BegPopupMenuBorder()); myIconPanel.setBackground(Color.LIGHT_GRAY); @@ -295,6 +294,9 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { public void setAdvertisementText(@Nullable String text) { myAdText = text; + if (StringUtil.isNotEmpty(text)) { + myAdComponent.addAdvertisement(text); + } } public String getAdvertisementText() { @@ -384,10 +386,8 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { updateListHeight(listModel); - myAdComponent.setText(myAdText); - if (!model.isEmpty()) { - myList.setFixedCellWidth(Math.max(myLookupTextWidth + myCellRenderer.getIconIndent(), myAdComponent.getPreferredSize().width)); + myList.setFixedCellWidth(Math.max(myLookupTextWidth + myCellRenderer.getIconIndent(), myAdComponent.getAdComponent().getPreferredSize().width)); if (isFocused() && (!isExactPrefixItem(model.iterator().next()) || mySelectionTouched)) { restoreSelection(oldSelected, hasPreselected, oldInvariant); @@ -772,9 +772,6 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { setFocused(true); markSelectionTouched(); - final Point point = e.getPoint(); - final int i = myList.locationToIndex(point); - if (e.getClickCount() == 2){ CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { public void run() { @@ -1145,7 +1142,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { final Dimension sortSize = mySortingLabel.getPreferredSize(); final Point sbLocation = SwingUtilities.convertPoint(myScrollPane.getVerticalScrollBar(), 0, 0, layeredPane); - final int sortHeight = (StringUtil.isNotEmpty(myAdText) ? myAdComponent : mySortingLabel).getPreferredSize().height; + final int sortHeight = (StringUtil.isNotEmpty(myAdText) ? myAdComponent.getAdComponent() : mySortingLabel).getPreferredSize().height; mySortingLabel.setBounds(sbLocation.x, layeredPane.getHeight() - sortHeight, sortSize.width, sortHeight); } @@ -1234,24 +1231,4 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { return myModel.getRelevanceStrings(); } - private class MyLightweightHint extends LightweightHint { - private boolean myHidden; - - public MyLightweightHint(JPanel panel) { - super(panel); - } - - @Override - public void hide() { - if (myHidden) return; - - hideLookup(true); - justHide(); - } - - private void justHide() { - myHidden = true; - super.hide(); - } - } } From 57ebab5f581862cdc52a3e2b896b0d932a6681f0 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 19:44:57 +0100 Subject: [PATCH 19/95] on lookup reuse, the ads should be cleared --- .../src/com/intellij/codeInsight/lookup/impl/Advertiser.java | 4 ++++ .../src/com/intellij/codeInsight/lookup/impl/LookupImpl.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java index 05f11f4f6cea..a224a51f0499 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java @@ -82,6 +82,10 @@ public class Advertiser implements Disposable { return new ArrayList(myTexts); } + public synchronized void clearAdvertisements() { + myTexts.clear(); + } + private static Font adFont() { Font font = UIUtil.getLabelFont(); return font.deriveFont((float)(font.getSize() - 2)); 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 ac3946c1c986..844bc7fa6c1d 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 @@ -1161,7 +1161,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { public void markReused() { myReused = true; myModel.clearItems(); - setAdvertisementText(null); + myAdComponent.clearAdvertisements(); myPreselectedItem = null; } From 8c6b5a8d9c4b4060573d02104bf129c3cd56aeab Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 19:58:10 +0100 Subject: [PATCH 20/95] advertise autopopup shortcuts --- .../completion/CompletionProgressIndicator.java | 7 ++++--- .../com/intellij/codeInsight/lookup/impl/Advertiser.java | 2 ++ .../com/intellij/codeInsight/lookup/impl/LookupImpl.java | 6 +++++- .../src/com/intellij/openapi/actionSystem/IdeActions.java | 3 +++ 4 files changed, 14 insertions(+), 4 deletions(-) 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 5fd530db23e3..909e841d81a1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -23,6 +23,7 @@ import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.lookup.*; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.lang.Language; +import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.CommandProcessor; @@ -150,11 +151,11 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement ((CompletionPhase.BgCalculation)phase).focusLookupWhenDone = true; } } else { - /* - myLookup.setAdvertisementText("Press " + + myLookup.addAdvertisement("Press " + CompletionContributor.getActionShortcut(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE) + " to choose the first suggestion"); - */ + myLookup.addAdvertisement(CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_DOWN) + " and " + CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_UP) + + " will move caret down and up"); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java index a224a51f0499..be79b9705e09 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java @@ -84,6 +84,8 @@ public class Advertiser implements Disposable { public synchronized void clearAdvertisements() { myTexts.clear(); + myCurrentItem = 0; + myScrollingOffset = 0; } private static Font adFont() { 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 844bc7fa6c1d..69897372505b 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 @@ -295,7 +295,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { public void setAdvertisementText(@Nullable String text) { myAdText = text; if (StringUtil.isNotEmpty(text)) { - myAdComponent.addAdvertisement(text); + addAdvertisement(text); } } @@ -1165,6 +1165,10 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { myPreselectedItem = null; } + public void addAdvertisement(@NotNull String text) { + myAdComponent.addAdvertisement(text); + } + public boolean isLookupDisposed() { return myDisposed; } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java index 919717957f94..c7d1ef878132 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java @@ -71,6 +71,9 @@ public interface IdeActions { @NonNls String ACTION_CHOOSE_LOOKUP_ITEM_REPLACE = "EditorChooseLookupItemReplace"; @NonNls String ACTION_CHOOSE_LOOKUP_ITEM_COMPLETE_STATEMENT = "EditorChooseLookupItemCompleteStatement"; + @NonNls String ACTION_LOOKUP_UP = "EditorLookupUp"; + @NonNls String ACTION_LOOKUP_DOWN = "EditorLookupDown"; + @NonNls String GROUP_EXTERNAL_TOOLS = "ExternalToolsGroup"; @NonNls String GROUP_MAIN_MENU = "MainMenu"; From 0acd0fe077732746fa08a3933ea4df527536edd0 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 20:00:01 +0100 Subject: [PATCH 21/95] public -> private --- .../src/com/intellij/codeInsight/lookup/impl/Advertiser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java index be79b9705e09..503a5ca5dabf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java @@ -31,7 +31,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * @author peter */ public class Advertiser implements Disposable { - public static final int ourScrollingResolution = 15; + private static final int ourScrollingResolution = 15; private final List myTexts = new CopyOnWriteArrayList(); private final JPanel myComponent = new JPanel() { From 08965e4d8a6555afa1f85cca3f2ffde307a5b48d Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 20:04:37 +0100 Subject: [PATCH 22/95] some logging --- .../codeInsight/editorActions/CompletionAutoPopupHandler.java | 4 ++++ 1 file changed, 4 insertions(+) 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 a8dedbe9deb3..89757366fe0a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -27,6 +27,7 @@ import com.intellij.codeInsight.lookup.LookupAdapter; import com.intellij.codeInsight.lookup.LookupEvent; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.editor.event.*; @@ -87,6 +88,9 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { } if (!CompletionServiceImpl.isPhase(CompletionPhase.AutoPopupAlarm.class, CompletionPhase.NoCompletion.getClass())) { + if ("peter".equals(System.getProperty("user.name")) && ApplicationManagerEx.getApplicationEx().isInternal()) { + System.out.println(CompletionServiceImpl.getCompletionPhase() + " at " + System.currentTimeMillis()); + } return Result.CONTINUE; } From 7f5a3de0bb4b2e429c5f133564f0a2c1cbbb1271 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2011 20:14:52 +0100 Subject: [PATCH 23/95] ctrl+arrows should be advertised even within a focused completion --- .../codeInsight/completion/CompletionProgressIndicator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 909e841d81a1..b3990a318c77 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -154,9 +154,10 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement myLookup.addAdvertisement("Press " + CompletionContributor.getActionShortcut(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE) + " to choose the first suggestion"); - myLookup.addAdvertisement(CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_DOWN) + " and " + CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_UP) + - " will move caret down and up"); } + myLookup.addAdvertisement(CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_DOWN) + " and " + + CompletionContributor.getActionShortcut(IdeActions.ACTION_LOOKUP_UP) + + " will move caret down and up"); } ProgressManager.checkCanceled(); From 0bfa72f5a86bf83c0310b1735711967af848cb42 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 15:44:03 +0100 Subject: [PATCH 24/95] move the first ad text initially --- .../codeInsight/lookup/impl/Advertiser.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java index 503a5ca5dabf..ca1ad95dd20f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java @@ -65,7 +65,9 @@ public class Advertiser implements Disposable { int y = (height - metrics.getHeight()) / 2 + metrics.getAscent() - (myScrollingOffset * height / ourScrollingResolution); int x = getBorder().getBorderInsets(this).left; - g.drawString(texts.get(myCurrentItem), x, y); + if (myCurrentItem >= 0) { + g.drawString(texts.get(myCurrentItem), x, y); + } if (myScrollingOffset != 0) { g.drawString(texts.get((myCurrentItem + 1) % texts.size()), x, y + height); } @@ -96,27 +98,20 @@ public class Advertiser implements Disposable { public synchronized void addAdvertisement(@NotNull String text) { myTexts.add(text); if (myTexts.size() == 2) { + if (!myComponent.isShowing()) { + myCurrentItem = -1; + } int interCycleGap = 4000; Animator animator = new Animator("completion ad", ourScrollingResolution, 800, true, interCycleGap, -1) { - boolean first = true; @Override public void paintNow(float frame, float totalFrames, float cycle) { - if (first && frame > 0) { - return; - } - myScrollingOffset = (int)frame; if (myScrollingOffset == 0) { - if (first) { - first = false; - } else { - myCurrentItem = (myCurrentItem + 1) % getTexts().size(); - } + myCurrentItem = (myCurrentItem + 1) % getTexts().size(); } myComponent.paintImmediately(0, 0, myComponent.getWidth(), myComponent.getHeight()); } }; - animator.setTakInitialDelay(true); animator.resume(); Disposer.register(this, animator); } From 8d18973374c3d3075abc6431457f46038cb1e228 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 15:55:57 +0100 Subject: [PATCH 25/95] ctrl+arrows on mac as well --- platform/platform-resources/src/idea/Keymap_Mac.xml | 4 ++-- platform/platform-resources/src/idea/Keymap_MacClassic.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/platform-resources/src/idea/Keymap_Mac.xml b/platform/platform-resources/src/idea/Keymap_Mac.xml index f1f615b3ce42..97673b9ad796 100644 --- a/platform/platform-resources/src/idea/Keymap_Mac.xml +++ b/platform/platform-resources/src/idea/Keymap_Mac.xml @@ -309,8 +309,8 @@ - - + + diff --git a/platform/platform-resources/src/idea/Keymap_MacClassic.xml b/platform/platform-resources/src/idea/Keymap_MacClassic.xml index 91b192d9cf14..43d7a13abf56 100644 --- a/platform/platform-resources/src/idea/Keymap_MacClassic.xml +++ b/platform/platform-resources/src/idea/Keymap_MacClassic.xml @@ -77,8 +77,8 @@ - - + + From 49aa619693170154afca4319120b80b89cbe4156 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 15:58:11 +0100 Subject: [PATCH 26/95] preselect the first suggestion back --- .../src/com/intellij/application/options/CodeCompletion.form | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form b/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form index bfc550c6a6aa..9fcf3638ef97 100644 --- a/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form +++ b/platform/lang-impl/src/com/intellij/application/options/CodeCompletion.form @@ -133,7 +133,7 @@ - + From bb17460a04b88e6409df88105136289041a5fbb1 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 18:10:05 +0100 Subject: [PATCH 27/95] lowercase camelhump matching support --- .../completion/JavaCompletionContributor.java | 3 + .../com/intellij/psi/codeStyle/NameUtil.java | 118 +++++++++++++++++- 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 34c72286b8e6..24322a3e410e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -32,6 +32,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.*; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.filters.*; import com.intellij.psi.filters.classes.AssignableFromContextFilter; import com.intellij.psi.filters.element.ExcludeDeclaredFilter; @@ -315,6 +316,8 @@ public class JavaCompletionContributor extends CompletionContributor { return false; } + if (NameUtil.useMinusculeHumpMatcher) return true; + final String s = result.getPrefixMatcher().getPrefix(); if (StringUtil.isEmpty(s) || !Character.isUpperCase(s.charAt(0))) return false; return true; diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 9c7bda8404b2..1619c241cf9a 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -19,6 +19,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.StringTokenizer; import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.Perl5Compiler; @@ -38,6 +39,7 @@ public class NameUtil { } }; private static final int MAX_LENGTH = 40; + public static final boolean useMinusculeHumpMatcher = "true".equals(System.getProperty("minuscule.humps.sorting")); private NameUtil() {} @@ -388,7 +390,11 @@ public class NameUtil { return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, lowerCaseWords, false)); } - private static Matcher buildMatcher(String pattern, String regexp) { + private static Matcher buildMatcher(final String pattern, String regexp) { + if (useMinusculeHumpMatcher) { + return new MinusculeMatcher(pattern); + } + return new OptimizedMatcher(pattern, regexp); } @@ -468,4 +474,114 @@ public class NameUtil { return true; } } + + + public static class MinusculeMatcher implements Matcher { + private final String myPattern; + + public MinusculeMatcher(String pattern) { + myPattern = pattern.replaceAll(":", "\\*:"); + } + + private boolean matches(int patternIndex, List words, int wordIndex) { + if (patternIndex == myPattern.length()) { + return true; + } + if (wordIndex == words.size()) { + return false; + } + + String w = words.get(wordIndex); + + if ('*' == myPattern.charAt(patternIndex)) { + return handleAsterisk(patternIndex, words, wordIndex); + } + + if (isWordSeparator(w.charAt(0))) { + assert w.length() == 1 : "'" + w + "'"; + return matches(isWordSeparator(myPattern.charAt(patternIndex)) ? patternIndex + 1 : patternIndex, words, wordIndex + 1); + } + + if (StringUtil.toLowerCase(w.charAt(0)) != StringUtil.toLowerCase(myPattern.charAt(patternIndex))) { + return false; + } + + int i = 1; + while (true) { + if (patternIndex + i == myPattern.length()) { + return true; + } + if (i == w.length()) { + break; + } + char p = myPattern.charAt(patternIndex + i); + char n = w.charAt(i); + if (n != p && (!Character.isLowerCase(p) || StringUtil.toLowerCase(n) != p)) { + break; + } + i++; + } + // there's more in the pattern, but no more words + if (wordIndex == words.size() - 1) { + return false; + } + while (i > 0) { + if (matches(patternIndex + i, words, wordIndex + 1)) { + return true; + } + i--; + } + return false; + } + + private boolean handleAsterisk(int patternIndex, List words, int wordIndex) { + while ('*' == myPattern.charAt(patternIndex)) { + patternIndex++; + if (patternIndex == myPattern.length()) { + return true; + } + } + + String nextChar = String.valueOf(myPattern.charAt(patternIndex)); + + for (int i = wordIndex; i < words.size(); i++) { + String s = words.get(i); + int fromIndex = 0; + while (true) { + int next = StringUtil.indexOfIgnoreCase(s, nextChar, fromIndex); + if (next < 0) { + break; + } + List newWords = new ArrayList(); + newWords.add(s.substring(fromIndex)); + newWords.addAll(words.subList(i + 1, words.size())); + if (matches(patternIndex, newWords, 0)) { + return true; + } + fromIndex = next + 1; + } + } + return false; + } + + private static boolean isWordSeparator(char c) { + return Character.isWhitespace(c) || c == '_' || c == '-'; + } + + @Override + public boolean matches(String name) { + StringTokenizer tokenizer = new StringTokenizer(name, " -_.:", true); + List words = new ArrayList(); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + addAllWords(token, words); + } + + if (words.isEmpty()) { + return myPattern.equals(name); + } + + return matches(0, words, 0); + } + } } From 09108a114136fca1fc6dc9b90e0d36d9f9b51bba Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 18:23:43 +0100 Subject: [PATCH 28/95] in a class, prefer member modifiers to other classes --- .../codeInsight/completion/JavaCompletionSorting.java | 1 + .../completion/normalSorting/PreferModifiers.java | 9 +++++++++ .../completion/NormalCompletionOrderingTest.java | 8 ++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normalSorting/PreferModifiers.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index 77ce85355add..3499436a3504 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -116,6 +116,7 @@ public class JavaCompletionSorting { @Override public Comparable weigh(@NotNull LookupElement element) { final Object o = element.getObject(); + if (o instanceof PsiKeyword) return -3; if (!(o instanceof PsiMember)) return 0; if (((PsiMember)o).hasModifierProperty(PsiModifier.STATIC)) { diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreferModifiers.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferModifiers.java new file mode 100644 index 000000000000..c3348c249c2f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/PreferModifiers.java @@ -0,0 +1,9 @@ +public class Test { + + p + + class paaa {} + + static class paab {} + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java index 6324ba539edf..521469010051 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java @@ -95,11 +95,11 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { } public void testClassStaticMembersInVoidContext() throws Throwable { - checkPreferredItems(0, "booleanMethod", "voidMethod", "AN_OBJECT", "BOOLEAN", "Inner"); + checkPreferredItems(0, "booleanMethod", "voidMethod", "AN_OBJECT", "BOOLEAN", "class"); } public void testClassStaticMembersInBooleanContext() throws Throwable { - checkPreferredItems(0, "booleanMethod", "voidMethod", "BOOLEAN", "AN_OBJECT", "Inner"); + checkPreferredItems(0, "booleanMethod", "voidMethod", "BOOLEAN", "AN_OBJECT", "class"); } public void testDispreferDeclared() throws Throwable { @@ -213,4 +213,8 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { checkPreferredItems(0, "return", "rLocal", "rParam", "rMethod"); } + public void testPreferModifiers() { + checkPreferredItems(0, "private", "protected", "public", "paaa", "paab"); + } + } \ No newline at end of file From a2d4cf4cde62cb9b45b4775ce130a02e43f45ee3 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 19:01:40 +0100 Subject: [PATCH 29/95] space at the end of the pattern matches the name end --- platform/util/src/com/intellij/psi/codeStyle/NameUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 1619c241cf9a..65132fb9c5af 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -523,6 +523,10 @@ public class NameUtil { } // there's more in the pattern, but no more words if (wordIndex == words.size() - 1) { + if (patternIndex + i == myPattern.length() - 1 && ' ' == myPattern.charAt(patternIndex + i)) { + return i == w.length(); + } + return false; } while (i > 0) { From f8a71caecd55bd6265901ef882808567b95a0437 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 19:19:47 +0100 Subject: [PATCH 30/95] no global member name completion with minuscule matcher --- .../JavaClassNameCompletionContributor.java | 87 +++++++++++-------- .../completion/JavaCompletionContributor.java | 20 +++-- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index cc3d3fd2178f..c299e311aa80 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.LangBundle; import com.intellij.lang.StdLanguages; import com.intellij.openapi.actionSystem.IdeActions; @@ -58,45 +59,10 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { final CompletionResultSet result = JavaCompletionSorting.addJavaSorting(parameters, _result); - final PsiElement insertedElement = parameters.getPosition(); - - final ElementFilter filter = - or(JavaSmartCompletionContributor.AFTER_THROW_NEW, - JavaCompletionContributor.INSIDE_METHOD_THROWS_CLAUSE, - JavaCompletionContributor.IN_CATCH_TYPE).accepts(insertedElement) ? new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE) : - IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : - TrueFilter.INSTANCE; - - - final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; - if (AFTER_NEW.accepts(insertedElement)) { - final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true); - for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) { - final PsiType type = info.getType(); - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass != null) { - result.addElement(createClassLookupItem(psiClass, inJavaContext)); - } - final PsiType defaultType = info.getDefaultType(); - if (!defaultType.equals(type)) { - final PsiClass defClass = PsiUtil.resolveClassInType(defaultType); - if (defClass != null) { - result.addElement(createClassLookupItem(defClass, inJavaContext)); - } - } - } - } - - final boolean lookingForAnnotations = PsiJavaPatterns.psiElement().afterLeaf("@").accepts(insertedElement); - - AllClassesGetter.processJavaClasses(parameters, result.getPrefixMatcher(), parameters.getInvocationCount() <= 1, new Consumer() { + addAllClasses(parameters, result, new Consumer() { @Override - public void consume(PsiClass psiClass) { - if (lookingForAnnotations && !psiClass.isAnnotationType()) return; - - if (filter.isAcceptable(psiClass, insertedElement)) { - result.addElement(createClassLookupItem(psiClass, inJavaContext)); - } + public void consume(LookupElement element) { + _result.addElement(element); } }); } @@ -104,6 +70,51 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { } + public static void addAllClasses(CompletionParameters parameters, final CompletionResultSet result, @NotNull final Consumer consumer) { + final PsiElement insertedElement = parameters.getPosition(); + + final ElementFilter filter = + or(JavaSmartCompletionContributor.AFTER_THROW_NEW, + JavaCompletionContributor.INSIDE_METHOD_THROWS_CLAUSE, + JavaCompletionContributor.IN_CATCH_TYPE).accepts(insertedElement) ? new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE) : + IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : + TrueFilter.INSTANCE; + + + final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; + if (AFTER_NEW.accepts(insertedElement)) { + final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true); + for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) { + final PsiType type = info.getType(); + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass != null) { + consumer.consume(createClassLookupItem(psiClass, inJavaContext)); + } + final PsiType defaultType = info.getDefaultType(); + if (!defaultType.equals(type)) { + final PsiClass defClass = PsiUtil.resolveClassInType(defaultType); + if (defClass != null) { + consumer.consume(createClassLookupItem(defClass, inJavaContext)); + } + } + } + } + + final boolean lookingForAnnotations = PsiJavaPatterns.psiElement().afterLeaf("@").accepts(insertedElement); + + AllClassesGetter + .processJavaClasses(parameters, result.getPrefixMatcher(), parameters.getInvocationCount() <= 1, new Consumer() { + @Override + public void consume(PsiClass psiClass) { + if (lookingForAnnotations && !psiClass.isAnnotationType()) return; + + if (filter.isAcceptable(psiClass, insertedElement)) { + consumer.consume(createClassLookupItem(psiClass, inJavaContext)); + } + } + }); + } + public static JavaPsiClassReferenceElement createClassLookupItem(final PsiClass psiClass, final boolean inJavaContext) { return AllClassesGetter.createLookupItem(psiClass, inJavaContext ? JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER : AllClassesGetter.TRY_SHORTENING); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 24322a3e410e..6ba1da7d07d4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -30,7 +30,10 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.patterns.*; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PatternCondition; +import com.intellij.patterns.PsiJavaElementPattern; +import com.intellij.patterns.PsiNameValuePairPattern; import com.intellij.psi.*; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.filters.*; @@ -212,15 +215,14 @@ public class JavaCompletionContributor extends CompletionContributor { PsiElement position, final InheritorsHolder inheritors) { if (shouldRunClassNameCompletion(result, position)) { - result.runRemainingContributors(parameters.withType(CompletionType.CLASS_NAME), - new Consumer() { - @Override - public void consume(LookupElement lookupElement) { - if (!inheritors.alreadyProcessed(lookupElement)) { - result.addElement(lookupElement); - } + JavaClassNameCompletionContributor.addAllClasses(parameters, result, new Consumer() { + @Override + public void consume(LookupElement element) { + if (!inheritors.alreadyProcessed(element)) { + result.addElement(element); } - }); + } + }); } } From e0928037401a9d4c60e11db2fb7b7bf0ac86de9c Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 19:20:41 +0100 Subject: [PATCH 31/95] class names on lowercase prefix in groovy --- .../completion/GroovyCompletionContributor.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index e6da371005cb..c0f7b302a637 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -25,8 +25,12 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.patterns.*; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.patterns.PsiElementPattern; +import com.intellij.patterns.StandardPatterns; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.filters.types.AssignableFromFilter; @@ -37,7 +41,6 @@ import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; @@ -45,14 +48,9 @@ import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier; import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; @@ -62,8 +60,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAc import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyElementPattern; -import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyPatterns; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -462,7 +458,7 @@ public class GroovyCompletionContributor extends CompletionContributor { }); final String s = result.getPrefixMatcher().getPrefix(); - if (!StringUtil.isEmpty(s) && Character.isUpperCase(s.charAt(0))) { + if (NameUtil.useMinusculeHumpMatcher || !StringUtil.isEmpty(s) && Character.isUpperCase(s.charAt(0))) { addAllClasses(parameters, result, inheritors); } } From 0ce18b2f8584f85629a1e58e9e5fc306f7e37012 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 19:24:38 +0100 Subject: [PATCH 32/95] debugging the test --- .../codeInsight/daemon/quickFix/CreateFileFix.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java index a1a6705b91b1..cf1b55b7eaeb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java @@ -60,6 +60,13 @@ public class CreateFileFix implements IntentionAction, LocalQuickFix { myDirectory = directory; myText = text; myKey = key; + if (ApplicationManager.getApplication().isUnitTestMode()) { + System.out.println("CreateFileFix.CreateFileFix"); + System.out.println(newFileName); + System.out.println(isDirectory); + System.out.println(FileTypeManager.getInstance().getFileTypeByFileName(newFileName)); + System.out.println(FileTypeManager.getInstance().getFileTypeByFileName(newFileName).isBinary()); + } myIsAvailable = isDirectory || !FileTypeManager.getInstance().getFileTypeByFileName(newFileName).isBinary(); myIsAvailableTimeStamp = System.currentTimeMillis(); } From ac03c93846e3685481dff92417e09e28e4bf8174 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 19:28:23 +0100 Subject: [PATCH 33/95] no debugging of the test --- .../codeInsight/daemon/quickFix/CreateFileFix.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java index cf1b55b7eaeb..a1a6705b91b1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java @@ -60,13 +60,6 @@ public class CreateFileFix implements IntentionAction, LocalQuickFix { myDirectory = directory; myText = text; myKey = key; - if (ApplicationManager.getApplication().isUnitTestMode()) { - System.out.println("CreateFileFix.CreateFileFix"); - System.out.println(newFileName); - System.out.println(isDirectory); - System.out.println(FileTypeManager.getInstance().getFileTypeByFileName(newFileName)); - System.out.println(FileTypeManager.getInstance().getFileTypeByFileName(newFileName).isBinary()); - } myIsAvailable = isDirectory || !FileTypeManager.getInstance().getFileTypeByFileName(newFileName).isBinary(); myIsAvailableTimeStamp = System.currentTimeMillis(); } From 67bd4e30390eb8d094b0db98fadbf6517063a170 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 19:31:18 +0100 Subject: [PATCH 34/95] fix the test --- .../com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java index a1a6705b91b1..29b9586001da 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/CreateFileFix.java @@ -109,7 +109,7 @@ public class CreateFileFix implements IntentionAction, LocalQuickFix { long current = System.currentTimeMillis(); if (ApplicationManager.getApplication().isUnitTestMode() || current - myIsAvailableTimeStamp > REFRESH_INTERVAL) { - myIsAvailable = myDirectory.getVirtualFile().findChild(myNewFileName) == null; + myIsAvailable &= myDirectory.getVirtualFile().findChild(myNewFileName) == null; myIsAvailableTimeStamp = current; } From a39faeffca1d572ffcdc872b6e38cac4073eea43 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 20:32:17 +0100 Subject: [PATCH 35/95] IDEA-65614 "}" symbol is inserted automatically, but is not substituted on manual typing in javadoc comments --- .../codeInsight/editorActions/TypedHandler.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java index 233e06b81695..f0904702d7f0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java @@ -26,7 +26,6 @@ import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; -import com.intellij.lexer.Lexer; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -49,7 +48,6 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; -import com.intellij.psi.templateLanguages.TemplateLanguage; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtilBase; @@ -332,15 +330,8 @@ public class TypedHandler implements TypedActionHandler { HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset); if (iterator.atEnd()) return false; - Language language = iterator.getTokenType().getLanguage(); - final ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(language); - if (definition != null && !(language instanceof TemplateLanguage)) { - final Lexer lexer = definition.createLexer(editor.getProject()); - lexer.start(Character.toString(charTyped)); - final IElementType tokenType = lexer.getTokenType(); - if (tokenType != iterator.getTokenType()) { - return false; - } + if (iterator.getEnd() - iterator.getStart() != 1 || editor.getDocument().getCharsSequence().charAt(iterator.getStart()) != charTyped) { + return false; } BraceMatcher braceMatcher = BraceMatchingUtil.getBraceMatcher(fileType, iterator); From a9c8cd157b8b1040ad90a0557c8d3beac76bdfc9 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 7 Mar 2011 12:44:56 +0100 Subject: [PATCH 36/95] Cleanup --- .../daemon/impl/JavaHighlightInfoTypes.java | 35 ++++++++++ .../daemon/impl/JavaHightlightInfoTypes.java | 43 ------------ .../daemon/impl/PostHighlightingPass.java | 2 +- .../impl/analysis/HighlightVisitorImpl.java | 2 +- .../daemon/AdvHighlightingTest.java | 36 ++++++---- .../daemon/JavadocHighlightingTest.java | 28 +++----- .../daemon/HighlightDisplayKey.java | 69 +++++++++++++------ .../daemon/impl/HighlightInfoType.java | 60 +++++++--------- 8 files changed, 143 insertions(+), 132 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHighlightInfoTypes.java delete mode 100644 java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHightlightInfoTypes.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHighlightInfoTypes.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHighlightInfoTypes.java new file mode 100644 index 000000000000..969fb93946c0 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHighlightInfoTypes.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2009 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; + +import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.editor.SyntaxHighlighterColors; +import com.intellij.openapi.editor.colors.CodeInsightColors; + +/** + * @author anna + * Date: 01-Feb-2008 + */ +public interface JavaHighlightInfoTypes extends HighlightInfoType { + HighlightInfoType UNUSED_IMPORT = new HighlightInfoType.HighlightInfoTypeSeverityByKey( + HighlightDisplayKey.findOrRegister(UnusedImportLocalInspection.SHORT_NAME, UnusedImportLocalInspection.DISPLAY_NAME), + CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES); + + HighlightInfoType JAVA_KEYWORD = new HighlightInfoType.HighlightInfoTypeImpl( + HighlightSeverity.INFORMATION, SyntaxHighlighterColors.KEYWORD); +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHightlightInfoTypes.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHightlightInfoTypes.java deleted file mode 100644 index 45c6431e64ad..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaHightlightInfoTypes.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2000-2009 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. - */ - -/* - * User: anna - * Date: 01-Feb-2008 - */ -package com.intellij.codeInsight.daemon.impl; - -import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection; -import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; -import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection; -import com.intellij.openapi.editor.colors.CodeInsightColors; - -public class JavaHightlightInfoTypes { - - public static final HighlightInfoType UNUSED_IMPORT = new HighlightInfoType.HighlightInfoTypeSeverityByKey( - HighlightDisplayKey.find(UnusedImportLocalInspection.SHORT_NAME) == null ? - HighlightDisplayKey.register(UnusedImportLocalInspection.SHORT_NAME, UnusedImportLocalInspection.DISPLAY_NAME) : HighlightDisplayKey.find(UnusedImportLocalInspection.SHORT_NAME), CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES); - public static final HighlightInfoType JAVADOC_WRONG_REF = new HighlightInfoType.HighlightInfoTypeSeverityByKey(HighlightDisplayKey.find( - JavaDocReferenceInspection.SHORT_NAME) == null ? - HighlightDisplayKey.register(JavaDocReferenceInspection.SHORT_NAME, JavaDocReferenceInspection.DISPLAY_NAME) : HighlightDisplayKey.find(JavaDocReferenceInspection.SHORT_NAME), CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES); - public static final HighlightInfoType UNCHECKED_WARNING = new HighlightInfoType.HighlightInfoTypeSeverityByKeyAttrBySeverity(HighlightDisplayKey.find( - UncheckedWarningLocalInspection.SHORT_NAME) == null ? - HighlightDisplayKey.register(UncheckedWarningLocalInspection.SHORT_NAME, UncheckedWarningLocalInspection.DISPLAY_NAME, UncheckedWarningLocalInspection.ID) : HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME)); - - private JavaHightlightInfoTypes() { - } -} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java index 961244c467c6..f55cd69e0f69 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java @@ -674,7 +674,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { } private HighlightInfo registerRedundantImport(PsiImportStatementBase importStatement, HighlightDisplayKey unusedImportKey) { - HighlightInfo info = HighlightInfo.createHighlightInfo(JavaHightlightInfoTypes.UNUSED_IMPORT, importStatement, InspectionsBundle.message("unused.import.statement")); + HighlightInfo info = HighlightInfo.createHighlightInfo(JavaHighlightInfoTypes.UNUSED_IMPORT, importStatement, InspectionsBundle.message("unused.import.statement")); QuickFixAction.registerQuickFixAction(info, new OptimizeImportsFix(), unusedImportKey); QuickFixAction.registerQuickFixAction(info, new EnableOptimizeImportsOnTheFlyFix(), unusedImportKey); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 7ca8e460bdac..5770530e592f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -533,7 +533,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalVoidType(keyword)); if (PsiTreeUtil.getParentOfType(keyword, PsiDocTagValue.class) != null) { - myHolder.add(HighlightInfo.createHighlightInfo(HighlightInfoType.JAVA_KEYWORD, keyword, null)); + myHolder.add(HighlightInfo.createHighlightInfo(JavaHighlightInfoTypes.JAVA_KEYWORD, keyword, null)); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java index 6b2196793939..3d9e95cfcdcd 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AdvHighlightingTest.java @@ -79,21 +79,21 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { public void testImportDefaultPackage2() throws Exception { doTest(BASE_PATH+"/importDefaultPackage/x/ImportOnDemandUsage.java", BASE_PATH+"/importDefaultPackage", false, false); } public void testScopeBased() throws Exception { - NamedScope xscope = new NamedScope("xxx", new PatternPackageSet("x..*", PatternPackageSet.SCOPE_SOURCE, null)); - NamedScope utilscope = new NamedScope("util", new PatternPackageSet("java.util.*", PatternPackageSet.SCOPE_LIBRARY, null)); + NamedScope xScope = new NamedScope("xxx", new PatternPackageSet("x..*", PatternPackageSet.SCOPE_SOURCE, null)); + NamedScope utilScope = new NamedScope("util", new PatternPackageSet("java.util.*", PatternPackageSet.SCOPE_LIBRARY, null)); NamedScopeManager scopeManager = NamedScopeManager.getInstance(getProject()); - scopeManager.addScope(xscope); - scopeManager.addScope(utilscope); + scopeManager.addScope(xScope); + scopeManager.addScope(utilScope); EditorColorsManager manager = EditorColorsManager.getInstance(); EditorColorsScheme scheme = (EditorColorsScheme)manager.getGlobalScheme().clone(); manager.addColorsScheme(scheme); EditorColorsManager.getInstance().setGlobalScheme(scheme); - TextAttributesKey xKey = ColorAndFontOptions.getScopeTextAttributeKey(xscope.getName()); + TextAttributesKey xKey = ColorAndFontOptions.getScopeTextAttributeKey(xScope.getName()); TextAttributes xAttributes = new TextAttributes(Color.cyan, Color.darkGray, Color.blue, EffectType.BOXED, Font.ITALIC); scheme.setAttributes(xKey, xAttributes); - TextAttributesKey utilKey = ColorAndFontOptions.getScopeTextAttributeKey(utilscope.getName()); + TextAttributesKey utilKey = ColorAndFontOptions.getScopeTextAttributeKey(utilScope.getName()); TextAttributes utilAttributes = new TextAttributes(Color.gray, Color.magenta, Color.orange, EffectType.STRIKEOUT, Font.BOLD); scheme.setAttributes(utilKey, utilAttributes); @@ -105,21 +105,21 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { } } public void testSharedScopeBased() throws Exception { - NamedScope xscope = new NamedScope("xxx", new PatternPackageSet("x..*", PatternPackageSet.SCOPE_ANY, null)); - NamedScope utilscope = new NamedScope("util", new PatternPackageSet("java.util.*", PatternPackageSet.SCOPE_LIBRARY, null)); + NamedScope xScope = new NamedScope("xxx", new PatternPackageSet("x..*", PatternPackageSet.SCOPE_ANY, null)); + NamedScope utilScope = new NamedScope("util", new PatternPackageSet("java.util.*", PatternPackageSet.SCOPE_LIBRARY, null)); NamedScopesHolder scopeManager = DependencyValidationManager.getInstance(getProject()); - scopeManager.addScope(xscope); - scopeManager.addScope(utilscope); + scopeManager.addScope(xScope); + scopeManager.addScope(utilScope); EditorColorsManager manager = EditorColorsManager.getInstance(); EditorColorsScheme scheme = (EditorColorsScheme)manager.getGlobalScheme().clone(); manager.addColorsScheme(scheme); EditorColorsManager.getInstance().setGlobalScheme(scheme); - TextAttributesKey xKey = ColorAndFontOptions.getScopeTextAttributeKey(xscope.getName()); + TextAttributesKey xKey = ColorAndFontOptions.getScopeTextAttributeKey(xScope.getName()); TextAttributes xAttributes = new TextAttributes(Color.cyan, Color.darkGray, Color.blue, null, Font.ITALIC); scheme.setAttributes(xKey, xAttributes); - TextAttributesKey utilKey = ColorAndFontOptions.getScopeTextAttributeKey(utilscope.getName()); + TextAttributesKey utilKey = ColorAndFontOptions.getScopeTextAttributeKey(utilScope.getName()); TextAttributes utilAttributes = new TextAttributes(Color.gray, Color.magenta, Color.orange, EffectType.STRIKEOUT, Font.BOLD); scheme.setAttributes(utilKey, utilAttributes); @@ -158,6 +158,7 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { } }); + assert root != null; configureByExistingFile(root.findFileByRelativePath("moduleJava5/com/Java5.java")); Collection infos = highlightErrors(); assertEmpty(infos); @@ -168,6 +169,7 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { VirtualFile root = LocalFileSystem.getInstance().findFileByIoFile(new File(path)); loadAllModulesUnder(root); + assert root != null; configureByExistingFile(root.findFileByRelativePath("client/src/BugTest.java")); Collection infos = highlightErrors(); assertEmpty(infos); @@ -178,12 +180,18 @@ public class AdvHighlightingTest extends DaemonAnalyzerTestCase { VirtualFile root = LocalFileSystem.getInstance().findFileByIoFile(new File(path)); loadAllModulesUnder(root); + assert root != null; configureByExistingFile(root.findFileByRelativePath("src/ppp/SomeClass.java")); PsiField field = ((PsiJavaFile)myFile).getClasses()[0].findFieldByName("f", false); + assert field != null; PsiClass aClass = ((PsiClassType)field.getType()).resolve(); + assert aClass != null; assertEquals("ppp.BadClass", aClass.getQualifiedName()); //lies in source - assertEquals(myFile.getVirtualFile().getParent(), aClass.getContainingFile().getVirtualFile().getParent()); + final VirtualFile vFile1 = myFile.getVirtualFile(); + final VirtualFile vFile2 = aClass.getContainingFile().getVirtualFile(); + assert vFile1 != null; + assert vFile2 != null; + assertEquals(vFile1.getParent(), vFile2.getParent()); } - } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java index 765ac83ce899..5dc0bd3c99dd 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java @@ -4,8 +4,6 @@ import com.intellij.JavaTestUtil; import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.pom.java.LanguageLevel; @@ -47,9 +45,7 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } - public void testInlineTagAsDescription() throws Exception { - doTest(); - } + public void testInlineTagAsDescription() throws Exception { doTest(); } public void testParam0() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } public void testParam1() throws Exception { doTest(); } @@ -62,8 +58,8 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testSee3() throws Exception { doTest(); } public void testSee4() throws Exception { doTest(); } public void testSee5() throws Exception { doTest(); } - public void testSee6() throws Exception {doTest();} - public void testSeeConstants() throws Exception { doTest();} + public void testSee6() throws Exception { doTest(); } + public void testSeeConstants() throws Exception { doTest(); } public void testReturn0() throws Exception { doTest(); } public void testException0() throws Exception { doTest(); } public void testException1() throws Exception { doTest(); } @@ -73,7 +69,7 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testMultipleThrows() throws Exception { doTest(); } public void testInheritJavaDoc() throws Exception {doTestWithLangLevel(LanguageLevel.JDK_1_3);} public void testLink0() throws Exception { doTest(); } - public void testLinkFromInnerClassToSelfMethod() throws Exception {doTest();} + public void testLinkFromInnerClassToSelfMethod() throws Exception { doTest(); } public void testValueBadReference() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } public void testValueGoodReference() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } @@ -83,20 +79,18 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testValueNotOnStaticField() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } public void testValueOnNotInitializedField() throws Exception { doTestWithLangLevel(LanguageLevel.HIGHEST); } - public void testUnknownInlineTag() throws Exception {doTest();} - public void testUnknownTags() throws Exception {doTest();} + public void testUnknownInlineTag() throws Exception { doTest(); } + public void testUnknownTags() throws Exception { doTest(); } - public void testBadCharacters() throws Exception {doTest();} + public void testBadCharacters() throws Exception { doTest(); } - public void testVararg() throws Exception {doTest();} + public void testVararg() throws Exception { doTest(); } - public void testInnerClassReferenceInSignature() throws Exception {doTest();} + public void testInnerClassReferenceInSignature() throws Exception { doTest(); } - public void testBadReference() throws Exception{ - doTest(); - } + public void testBadReference() throws Exception { doTest(); } - public void testMissingReturnDescription() throws Exception {doTest();} + public void testMissingReturnDescription() throws Exception { doTest(); } private void doTestWithLangLevel(final LanguageLevel langLevel) throws Exception { LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(langLevel); diff --git a/platform/lang-api/src/com/intellij/codeInsight/daemon/HighlightDisplayKey.java b/platform/lang-api/src/com/intellij/codeInsight/daemon/HighlightDisplayKey.java index 3ccad92eb7c5..9f7d7212ce2c 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/daemon/HighlightDisplayKey.java +++ b/platform/lang-api/src/com/intellij/codeInsight/daemon/HighlightDisplayKey.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInsight.daemon; import com.intellij.openapi.diagnostic.Logger; @@ -36,11 +35,12 @@ public class HighlightDisplayKey { private final String myName; private final String myID; - public static HighlightDisplayKey find(@NonNls @NotNull String name){ + public static HighlightDisplayKey find(@NonNls @NotNull final String name) { return ourNameToKeyMap.get(name); } - public static HighlightDisplayKey findById(@NonNls @NotNull String id){ + @Nullable + public static HighlightDisplayKey findById(@NonNls @NotNull final String id) { HighlightDisplayKey key = ourIdToKeyMap.get(id); if (key != null) return key; key = ourNameToKeyMap.get(id); @@ -49,7 +49,7 @@ public class HighlightDisplayKey { } @Nullable - public static HighlightDisplayKey register(@NonNls @NotNull String name) { + public static HighlightDisplayKey register(@NonNls @NotNull final String name) { if (find(name) != null) { LOG.info("Key with name \'" + name + "\' already registered"); return null; @@ -58,7 +58,14 @@ public class HighlightDisplayKey { } @Nullable - public static HighlightDisplayKey register(@NonNls @NotNull String name, @NotNull String displayName, @NotNull @NonNls String id){ + public static HighlightDisplayKey register(@NonNls @NotNull final String name, @NotNull final String displayName) { + return register(name, displayName, name); + } + + @Nullable + public static HighlightDisplayKey register(@NonNls @NotNull final String name, + @NotNull final String displayName, + @NotNull @NonNls final String id) { if (find(name) != null) { LOG.info("Key with name \'" + name + "\' already registered"); return null; @@ -69,19 +76,49 @@ public class HighlightDisplayKey { } @Nullable - public static HighlightDisplayKey register(@NonNls @NotNull String name, @NotNull String displayName) { - return register(name, displayName, name); + public static HighlightDisplayKey register(@NonNls @NotNull final String name, + @NonNls @NotNull final String displayName, + @NonNls @NotNull final String id, + @NonNls @Nullable final String alternativeID) { + final HighlightDisplayKey key = register(name, displayName, id); + if (alternativeID != null) { + ourKeyToAlternativeIDMap.put(key, alternativeID); + } + return key; } - public static String getDisplayNameByKey(@Nullable HighlightDisplayKey key){ + @NotNull + public static HighlightDisplayKey findOrRegister(@NonNls @NotNull String name, @NotNull final String displayName) { + return findOrRegister(name, displayName, null); + } + + @NotNull + public static HighlightDisplayKey findOrRegister(@NonNls @NotNull final String name, + @NotNull final String displayName, + @NonNls @Nullable final String id) { + HighlightDisplayKey key = find(name); + if (key == null) { + key = register(name, displayName, id != null ? id : name); + assert key != null : name; + } + return key; + } + + @Nullable + public static String getDisplayNameByKey(@Nullable HighlightDisplayKey key) { return key == null ? null : ourKeyToDisplayNameMap.get(key); } - private HighlightDisplayKey(@NotNull String name) { + public static String getAlternativeID(@NotNull HighlightDisplayKey key) { + return ourKeyToAlternativeIDMap.get(key); + } + + + private HighlightDisplayKey(@NonNls @NotNull final String name) { this(name, name); } - public HighlightDisplayKey(@NonNls @NotNull final String name, @NotNull @NonNls final String ID) { + public HighlightDisplayKey(@NonNls @NotNull final String name, @NonNls @NotNull final String ID) { myName = name; myID = ID; ourNameToKeyMap.put(myName, this); @@ -97,16 +134,4 @@ public class HighlightDisplayKey { public String getID(){ return myID; } - - public static HighlightDisplayKey register(@NotNull String shortName, @NotNull String displayName, @NotNull String id, String alternativeID) { - final HighlightDisplayKey key = register(shortName, displayName, id); - if (alternativeID != null) { - ourKeyToAlternativeIDMap.put(key, alternativeID); - } - return key; - } - - public static String getAlternativeID(@NotNull HighlightDisplayKey key) { - return ourKeyToAlternativeIDMap.get(key); - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoType.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoType.java index ca4781c001ff..295a460f0ab1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoType.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoType.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.codeInsight.daemon.impl; import com.intellij.codeHighlighting.HighlightDisplayLevel; @@ -22,7 +21,6 @@ import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.SyntaxHighlighterColors; import com.intellij.openapi.editor.colors.CodeInsightColors; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.util.Comparing; @@ -42,34 +40,36 @@ public interface HighlightInfoType { @NonNls String UNUSED_SYMBOL_ID = "UnusedDeclaration"; @NonNls String DEPRECATION_SHORT_NAME = "Deprecation"; - @NonNls String DEPRECATION_ID = "deprecation"; @NonNls String DEPRECATION_DISPLAY_NAME = InspectionsBundle.message("inspection.deprecated.display.name"); + @NonNls String DEPRECATION_ID = "deprecation"; + + HighlightInfoType ERROR = new HighlightInfoTypeImpl(HighlightSeverity.ERROR, CodeInsightColors.ERRORS_ATTRIBUTES); + HighlightInfoType WARNING = new HighlightInfoTypeImpl(HighlightSeverity.WARNING, CodeInsightColors.WARNINGS_ATTRIBUTES); + /** @deprecated use {@link #WEAK_WARNING} instead */ + HighlightInfoType INFO = new HighlightInfoTypeImpl(HighlightSeverity.INFO, CodeInsightColors.INFO_ATTRIBUTES); + HighlightInfoType WEAK_WARNING = new HighlightInfoTypeImpl(HighlightSeverity.WEAK_WARNING, CodeInsightColors.WEAK_WARNING_ATTRIBUTES); + HighlightInfoType INFORMATION = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.INFORMATION_ATTRIBUTES); HighlightInfoType WRONG_REF = new HighlightInfoTypeImpl(HighlightSeverity.ERROR, CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES); - HighlightInfoType ERROR = new HighlightInfoTypeImpl(HighlightSeverity.ERROR, CodeInsightColors.ERRORS_ATTRIBUTES); - HighlightInfoType GENERIC_WARNINGS_OR_ERRORS_FROM_SERVER = new HighlightInfoTypeImpl(HighlightSeverity.GENERIC_SERVER_ERROR_OR_WARNING, CodeInsightColors.GENERIC_SERVER_ERROR_OR_WARNING); + HighlightInfoType GENERIC_WARNINGS_OR_ERRORS_FROM_SERVER = new HighlightInfoTypeImpl( + HighlightSeverity.GENERIC_SERVER_ERROR_OR_WARNING, CodeInsightColors.GENERIC_SERVER_ERROR_OR_WARNING); HighlightInfoType DUPLICATE_FROM_SERVER = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.DUPLICATE_FROM_SERVER); - HighlightInfoType UNUSED_SYMBOL = new HighlightInfoTypeSeverityByKey(HighlightDisplayKey.find(UNUSED_SYMBOL_SHORT_NAME) == null ? - HighlightDisplayKey.register(UNUSED_SYMBOL_SHORT_NAME, - UNUSED_SYMBOL_DISPLAY_NAME, - UNUSED_SYMBOL_ID) : HighlightDisplayKey.find(UNUSED_SYMBOL_SHORT_NAME), - CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES); - + HighlightInfoType UNUSED_SYMBOL = new HighlightInfoTypeSeverityByKey( + HighlightDisplayKey.findOrRegister(UNUSED_SYMBOL_SHORT_NAME, UNUSED_SYMBOL_DISPLAY_NAME, UNUSED_SYMBOL_ID), + CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES); HighlightInfoType DEPRECATED = new HighlightInfoTypeSeverityByKey( - HighlightDisplayKey.find(DEPRECATION_SHORT_NAME) == null ? HighlightDisplayKey - .register(DEPRECATION_SHORT_NAME, DEPRECATION_DISPLAY_NAME, DEPRECATION_ID) : HighlightDisplayKey.find(DEPRECATION_SHORT_NAME), + HighlightDisplayKey.findOrRegister(DEPRECATION_SHORT_NAME, DEPRECATION_DISPLAY_NAME, DEPRECATION_ID), CodeInsightColors.DEPRECATED_ATTRIBUTES); HighlightInfoType LOCAL_VARIABLE = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.LOCAL_VARIABLE_ATTRIBUTES); HighlightInfoType INSTANCE_FIELD = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.INSTANCE_FIELD_ATTRIBUTES); HighlightInfoType STATIC_FIELD = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.STATIC_FIELD_ATTRIBUTES); HighlightInfoType PARAMETER = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.PARAMETER_ATTRIBUTES); - // t.o.d.o attributes depend on the t.o.d.o text - HighlightInfoType TODO = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, null); + HighlightInfoType TODO = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, null); // t.o.d.o attributes depend on the t.o.d.o text HighlightInfoType METHOD_CALL = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.METHOD_CALL_ATTRIBUTES); HighlightInfoType METHOD_DECLARATION = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.METHOD_DECLARATION_ATTRIBUTES); HighlightInfoType CONSTRUCTOR_CALL = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.CONSTRUCTOR_CALL_ATTRIBUTES); @@ -84,21 +84,11 @@ public interface HighlightInfoType { HighlightInfoType REASSIGNED_LOCAL_VARIABLE = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.REASSIGNED_LOCAL_VARIABLE_ATTRIBUTES); HighlightInfoType REASSIGNED_PARAMETER = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.REASSIGNED_PARAMETER_ATTRIBUTES); HighlightInfoType IMPLICIT_ANONYMOUS_CLASS_PARAMETER = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.IMPLICIT_ANONYMOUS_CLASS_PARAMETER_ATTRIBUTES); + HighlightInfoType UNHANDLED_EXCEPTION = new HighlightInfoTypeImpl(HighlightSeverity.ERROR, CodeInsightColors.ERRORS_ATTRIBUTES); - HighlightInfoType WARNING = new HighlightInfoTypeImpl(HighlightSeverity.WARNING, CodeInsightColors.WARNINGS_ATTRIBUTES); - /** - * use #WEAK_WARNING instead - */ - @Deprecated - HighlightInfoType INFO = new HighlightInfoTypeImpl(HighlightSeverity.INFO, CodeInsightColors.INFO_ATTRIBUTES); - HighlightInfoType WEAK_WARNING = new HighlightInfoTypeImpl(HighlightSeverity.WEAK_WARNING, CodeInsightColors.WEAK_WARNING_ATTRIBUTES); - HighlightInfoType INFORMATION = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, CodeInsightColors.INFORMATION_ATTRIBUTES); HighlightSeverity INJECTED_FRAGMENT_SEVERITY = new HighlightSeverity("INJECTED_FRAGMENT_SEVERITY", HighlightSeverity.INFORMATION.myVal-1); HighlightInfoType INJECTED_LANGUAGE_FRAGMENT = new HighlightInfoTypeImpl(INJECTED_FRAGMENT_SEVERITY, CodeInsightColors.INFORMATION_ATTRIBUTES); - HighlightInfoType UNHANDLED_EXCEPTION = new HighlightInfoTypeImpl(HighlightSeverity.ERROR, CodeInsightColors.ERRORS_ATTRIBUTES); - HighlightInfoType JAVA_KEYWORD = new HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, SyntaxHighlighterColors.KEYWORD); - @NotNull HighlightSeverity getSeverity(PsiElement psiElement); @@ -199,8 +189,7 @@ public interface HighlightInfoType { } class HighlightInfoTypeSeverityByKeyAttrBySeverity implements HighlightInfoType { - static final Logger LOG = Logger.getInstance( - "#com.intellij.codeInsight.daemon.impl.HighlightInfoType.HighlightInfoTypeSeverityByKeyAttrBySeverity"); + static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.HighlightInfoType.HighlightInfoTypeSeverityByKeyAttrBySeverity"); private final HighlightDisplayKey mySeverityKey; @@ -210,9 +199,10 @@ public interface HighlightInfoType { @NotNull public HighlightSeverity getSeverity(final PsiElement psiElement) { - HighlightDisplayLevel level = psiElement != null ? InspectionProjectProfileManager.getInstance(psiElement.getProject()).getInspectionProfile().getErrorLevel(mySeverityKey, - psiElement) : ((InspectionProfile)InspectionProfileManager.getInstance().getRootProfile()).getErrorLevel(mySeverityKey, - psiElement); + InspectionProfile profile = psiElement == null + ? (InspectionProfile)InspectionProfileManager.getInstance().getRootProfile() + : InspectionProjectProfileManager.getInstance(psiElement.getProject()).getInspectionProfile(); + HighlightDisplayLevel level = profile.getErrorLevel(mySeverityKey, psiElement); LOG.assertTrue(level != HighlightDisplayLevel.DO_NOT_SHOW); return level.getSeverity(); } @@ -224,14 +214,16 @@ public interface HighlightInfoType { ? infoType.getAttributesKey() : severity == HighlightSeverity.ERROR ? CodeInsightColors.ERRORS_ATTRIBUTES - : severity == HighlightSeverity.WARNING ? CodeInsightColors.WARNINGS_ATTRIBUTES - : severity == HighlightSeverity.WEAK_WARNING ? CodeInsightColors.WEAK_WARNING_ATTRIBUTES : CodeInsightColors.INFO_ATTRIBUTES; + : severity == HighlightSeverity.WARNING + ? CodeInsightColors.WARNINGS_ATTRIBUTES + : severity == HighlightSeverity.WEAK_WARNING + ? CodeInsightColors.WEAK_WARNING_ATTRIBUTES + : CodeInsightColors.INFO_ATTRIBUTES; } @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { return "HighlightInfoTypeSeverityByKeyAttrBySeverity[severity=" + mySeverityKey + "]"; - } } } From 20b933ac87f2449412a2dcc2c434eef93df0a08f Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 7 Mar 2011 17:20:33 +0100 Subject: [PATCH 37/95] IDEA-66266 (add/remove modifier quick fix to work on explicit ones only) --- .../daemon/impl/quickfix/ModifierFix.java | 8 +++++--- .../quickFix/modifier/before33.java | 12 ++++++++++++ .../quickFix/modifier/before34.java | 9 +++++++++ .../quickFix/modifier/before35.java | 16 ++++++++++++++++ .../quickFix/modifier/before36.java | 13 +++++++++++++ .../daemon/quickFix/ModifierTest.java | 1 - 6 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before33.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before34.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before35.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before36.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java index 3b9f9633b698..df081d7e7cb0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java @@ -54,6 +54,7 @@ public class ModifierFix extends IntentionAndQuickFixAction { myShouldHave = shouldHave; myShowContainingClass = showContainingClass; } + public ModifierFix(@NotNull PsiModifierListOwner owner, @Modifier @NotNull String modifier, boolean shouldHave, boolean showContainingClass) { this(owner.getModifierList(), modifier, shouldHave, showContainingClass); if (owner instanceof PsiVariable) { @@ -79,8 +80,9 @@ public class ModifierFix extends IntentionAndQuickFixAction { else if (parent instanceof PsiClassInitializer) { PsiClass containingClass = ((PsiClassInitializer)parent).getContainingClass(); String className = containingClass instanceof PsiAnonymousClass - ? QuickFixBundle.message("anonymous.class.presentation", ((PsiAnonymousClass)containingClass).getBaseClassType().getPresentableText()) - : containingClass.getName(); + ? QuickFixBundle.message("anonymous.class.presentation", + ((PsiAnonymousClass)containingClass).getBaseClassType().getPresentableText()) + : containingClass != null ? containingClass.getName() : "unknown"; name = QuickFixBundle.message("class.initializer.presentation", className); } } @@ -99,7 +101,7 @@ public class ModifierFix extends IntentionAndQuickFixAction { return myModifierList != null && myModifierList.isValid() && myModifierList.getManager().isInProject(myModifierList) && - myModifierList.hasModifierProperty(myModifier) != myShouldHave && + myModifierList.hasExplicitModifier(myModifier) != myShouldHave && (myVariable == null || myVariable.isValid()); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before33.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before33.java new file mode 100644 index 000000000000..a032ae65d80c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before33.java @@ -0,0 +1,12 @@ +// "Make 'e' not final" "false" + +class C { + static { + try { + throw new Exception(); + } + catch (RuntimeException | IOException e) { + e = null; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before34.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before34.java new file mode 100644 index 000000000000..4aca069684c6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before34.java @@ -0,0 +1,9 @@ +// "Make 'r' not final" "false" + +class C { + void m() throws Exception { + try (AutoCloseable r = null) { + r = null; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before35.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before35.java new file mode 100644 index 000000000000..1bee6da0d391 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before35.java @@ -0,0 +1,16 @@ +// "Make 'e' final" "false" + +class C { + static { + try { + throw new Exception(); + } + catch (RuntimeException | IOException e) { + new Runnable() { + public void run() { + System.out.println(e); + } + }.run(); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before36.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before36.java new file mode 100644 index 000000000000..04c4cdd30653 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier/before36.java @@ -0,0 +1,13 @@ +// "Make 'r' final" "false" + +class C { + void m() throws Exception { + try (AutoCloseable r = null) { + new Runnable() { + public void run() { + System.out.println(r); + } + }.run(); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ModifierTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ModifierTest.java index 0100ec65de47..c0eaeb8c1352 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ModifierTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ModifierTest.java @@ -8,4 +8,3 @@ public class ModifierTest extends LightQuickFixTestCase { return "/codeInsight/daemonCodeAnalyzer/quickFix/modifier"; } } - From c3b799c246fec8676644af5db5f26f46fe923288 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 7 Mar 2011 22:00:06 +0100 Subject: [PATCH 38/95] IDEA-66081 (resolve methods in javadoc by signatures) --- .../javaDoc/JavaDocReferenceInspection.java | 109 ++++++------ .../javadoc/PsiDocMethodOrFieldRef.java | 168 +++++++++--------- .../javaDoc/resolve/pkg/See0.java | 15 ++ .../javaDoc/resolve/pkg/See1.java | 16 ++ .../javaDoc/resolve/pkg/See2.java | 13 ++ .../daemon/JavadocResolveTest.java | 37 ++++ .../intellij/psi/util/MethodSignature.java | 25 ++- .../psi/util/MethodSignatureUtil.java | 44 +++-- 8 files changed, 259 insertions(+), 168 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java index af46d0c795d8..77b76a3b4f26 100644 --- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java @@ -48,12 +48,10 @@ import java.util.*; public class JavaDocReferenceInspection extends BaseLocalInspectionTool { @NonNls public static final String SHORT_NAME = "JavadocReference"; - public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.javadoc.ref.display.name"); - private static ProblemDescriptor createDescriptor(@NotNull PsiElement element, String template, InspectionManager manager, boolean onTheFly) { - return manager.createProblemDescriptor(element, template, onTheFly, (LocalQuickFix [])null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); + return manager.createProblemDescriptor(element, template, onTheFly, null, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL); } @Nullable @@ -66,9 +64,14 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { return checkMember(field, manager, isOnTheFly); } + @Nullable + public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { + return checkMember(aClass, manager, isOnTheFly); + } + @Nullable private ProblemDescriptor[] checkMember(final PsiDocCommentOwner docCommentOwner, final InspectionManager manager, final boolean isOnTheFly) { - ArrayList problems = new ArrayList(); + final ArrayList problems = new ArrayList(); final PsiDocComment docComment = docCommentOwner.getDocComment(); if (docComment == null) return null; @@ -77,26 +80,20 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { for (PsiJavaCodeReferenceElement reference : references) { final List classesToImport = new ImportClassFix(reference).getClassesToImport(); final PsiElement referenceNameElement = reference.getReferenceNameElement(); - problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference, cannotResolveSymbolMessage("" + reference.getText() + ""), - !isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport), ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, - isOnTheFly)); + problems.add(manager.createProblemDescriptor(referenceNameElement != null ? referenceNameElement : reference, + cannotResolveSymbolMessage("" + reference.getText() + ""), + !isOnTheFly || classesToImport.isEmpty() ? null : new AddImportFix(classesToImport), + ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, isOnTheFly)); } - return problems.isEmpty() - ? null - : problems.toArray(new ProblemDescriptor[problems.size()]); + return problems.isEmpty() ? null : problems.toArray(new ProblemDescriptor[problems.size()]); } - @Nullable - public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { - return checkMember(aClass, manager, isOnTheFly); - } - - private PsiElementVisitor getVisitor(final Set references, final PsiElement context, final ArrayList problems, - final InspectionManager manager, final boolean onTheFly) { + final InspectionManager manager, + final boolean onTheFly) { return new JavaElementVisitor() { @Override public void visitReferenceExpression(PsiReferenceExpression expression) { visitElement(expression); @@ -137,58 +134,56 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { }; } - public static void visitRefInDocTag(final PsiDocTag tag, final JavadocManager manager, final PsiElement context, ArrayList problems, - InspectionManager inspectionManager, - boolean onTheFly) { + public static void visitRefInDocTag(final PsiDocTag tag, + final JavadocManager manager, + final PsiElement context, + final ArrayList problems, + final InspectionManager inspectionManager, + final boolean onTheFly) { final String tagName = tag.getName(); - PsiDocTagValue value = tag.getValueElement(); + final PsiDocTagValue value = tag.getValueElement(); if (value == null) return; final JavadocTagInfo info = manager.getTagInfo(tagName); if (info != null && !info.isValidInContext(context)) return; - String message = info == null || !info.isInline() ? null : info.checkTagValue(value); + final String message = info == null || !info.isInline() ? null : info.checkTagValue(value); if (message != null){ problems.add(createDescriptor(value, message, inspectionManager, onTheFly)); } + final PsiReference reference = value.getReference(); - if (reference != null) { - PsiElement element = reference.resolve(); - if (element == null) { - final int textOffset = value.getTextOffset(); + if (reference == null) return; + final PsiElement element = reference.resolve(); + if (element != null) return; + final int textOffset = value.getTextOffset(); + if (textOffset == value.getTextRange().getEndOffset()) return; + final PsiDocTagValue valueElement = tag.getValueElement(); + if (valueElement == null) return; - if (textOffset != value.getTextRange().getEndOffset()) { - final PsiDocTagValue valueElement = tag.getValueElement(); - if (valueElement != null) { - final CharSequence paramName = - value.getContainingFile().getViewProvider().getContents().subSequence(textOffset, value.getTextRange().getEndOffset()); - @NonNls String params = "" + paramName + ""; - - final List fixes = new ArrayList(); - if (onTheFly && "param".equals(tagName)) { - final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class); - if (commentOwner instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)commentOwner; - final PsiParameter[] parameters = method.getParameterList().getParameters(); - final PsiDocTag[] tags = tag.getContainingComment().getTags(); - final Set unboundParams = new HashSet(); - for (PsiParameter parameter : parameters) { - if (!JavaDocLocalInspection.isFound(tags, parameter)) { - unboundParams.add(parameter.getName()); - } - } - if (!unboundParams.isEmpty()) { - fixes.add(new RenameReferenceQuickFix(unboundParams)); - } - } - } - fixes.add(new RemoveTagFix(tagName, paramName, tag)); - - problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params), - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly, - fixes.toArray(new LocalQuickFix[fixes.size()]))); + final CharSequence paramName = value.getContainingFile().getViewProvider().getContents().subSequence(textOffset, value.getTextRange().getEndOffset()); + final String params = "" + paramName + ""; + final List fixes = new ArrayList(); + if (onTheFly && "param".equals(tagName)) { + final PsiDocCommentOwner commentOwner = PsiTreeUtil.getParentOfType(tag, PsiDocCommentOwner.class); + if (commentOwner instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)commentOwner; + final PsiParameter[] parameters = method.getParameterList().getParameters(); + final PsiDocTag[] tags = tag.getContainingComment().getTags(); + final Set unboundParams = new HashSet(); + for (PsiParameter parameter : parameters) { + if (!JavaDocLocalInspection.isFound(tags, parameter)) { + unboundParams.add(parameter.getName()); } } + if (!unboundParams.isEmpty()) { + fixes.add(new RenameReferenceQuickFix(unboundParams)); + } } } + fixes.add(new RemoveTagFix(tagName, paramName, tag)); + + problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params), + ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly, + fixes.toArray(new LocalQuickFix[fixes.size()]))); } private static String cannotResolveSymbolMessage(String params) { @@ -197,7 +192,7 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool { @NotNull public String getDisplayName() { - return DISPLAY_NAME; + return InspectionsBundle.message("inspection.javadoc.ref.display.name"); } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java b/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java index b528198bb493..e4416a428200 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java @@ -15,8 +15,8 @@ */ package com.intellij.psi.impl.source.javadoc; +import com.google.common.collect.Lists; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.source.Constants; @@ -29,9 +29,9 @@ import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.scope.processor.FilterScopeProcessor; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; @@ -85,8 +85,6 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo @Nullable private PsiReference getReferenceInScope(PsiElement scope, PsiElement element) { final String name = element.getText(); - - final String[] signature = getSignature(); if (signature == null) { @@ -97,49 +95,44 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo } } - final PsiMethod[] methods = getAllMethods(scope, this); - - nextMethod: - for (PsiMethod method : methods) { - if (!method.getName().equals(name)) continue; - - if (signature == null) { - return new MyReference(method); - } - else { - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != signature.length) continue; - for (int j = 0; j < parameters.length; j++) { - PsiParameter parameter = parameters[j]; - PsiType type1 = TypeConversionUtil.erasure(parameter.getType()); - String type2 = signature[j]; - if (!Comparing.strEqual(type1.getPresentableText(), type2) && !Comparing.strEqual(type1.getCanonicalText(), type2)) { - String shortName = ""; - PsiClass psiClass = PsiUtil.resolveClassInType(type1); - while (psiClass != null) { - shortName = psiClass.getName() + (shortName.length() > 0 ? "." + shortName : ""); - psiClass = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class); - } - if (!Comparing.strEqual(shortName, type2)) { - continue nextMethod; - } - } + final MethodSignature methodSignature; + if (signature != null) { + final List types = Lists.newArrayListWithCapacity(signature.length); + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory(); + for (String s : signature) { + try { + types.add(elementFactory.createTypeFromText(s, scope)); + } + catch (IncorrectOperationException e) { + types.add(PsiType.NULL); } - - return new MyReference(method) { - @NotNull - public PsiElement[] getVariants() { - final List lst = new ArrayList(); - for (PsiMethod method : methods) { - if (name.equals(method.getName())) { - lst.add(method); - } - } - return lst.toArray(new PsiMethod[lst.size()]); - } - }; } + methodSignature = MethodSignatureUtil.createMethodSignature(name, types.toArray(new PsiType[types.size()]), + PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); } + else { + methodSignature = MethodSignatureUtil.createMethodSignature(name, PsiType.EMPTY_ARRAY, + PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY); + } + + final PsiMethod[] methods = getAllMethods(scope, this); + for (PsiMethod method : methods) { + if (!method.getName().equals(name) || + !MethodSignatureUtil.areSignaturesErasureEqual(methodSignature, method.getSignature(PsiSubstitutor.EMPTY))) continue; + return new MyReference(method) { + @NotNull + public PsiElement[] getVariants() { + final List lst = new ArrayList(); + for (PsiMethod method : methods) { + if (name.equals(method.getName())) { + lst.add(method); + } + } + return lst.toArray(new PsiMethod[lst.size()]); + } + }; + } + return null; } @@ -157,34 +150,30 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo public int getTextOffset() { final PsiElement element = getNameElement(); - - if (element != null) { - return element.getTextRange().getStartOffset(); - } - - return getTextRange().getEndOffset(); + return element != null ? element.getTextRange().getStartOffset() : getTextRange().getEndOffset(); } + @Nullable public PsiElement getNameElement() { final ASTNode sharp = findChildByType(DOC_TAG_VALUE_SHARP_TOKEN); - if (sharp == null) return null; - return SourceTreeToPsiMap.treeElementToPsi(sharp).getNextSibling(); + return sharp != null ? SourceTreeToPsiMap.treeToPsiNotNull(sharp).getNextSibling() : null; } - + @Nullable public String[] getSignature() { - PsiElement element = getNameElement().getNextSibling(); + PsiElement element = getNameElement(); + if (element == null) return null; + element = element.getNextSibling(); while (element != null && !(element instanceof PsiDocTagValue)) { element = element.getNextSibling(); } - if (element == null) return null; List types = new ArrayList(); for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { if (child.getNode().getElementType() == DOC_TYPE_HOLDER) { - final String[] typeStrings = child.getText().split("[, ]"); //avoid param types list parsing hmm mathod(paramType1, paramType2, ...) -> typeElement1, identifier2, ... + final String[] typeStrings = child.getText().split("[, ]"); //avoid param types list parsing hmm method(paramType1, paramType2, ...) -> typeElement1, identifier2, ... if (typeStrings != null) { for (String type : typeStrings) { if (type.length() > 0) { @@ -224,14 +213,14 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo } public class MyReference implements PsiJavaReference { - private final PsiElement myReferencee; + private final PsiElement myReferredElement; - public MyReference(PsiElement referencee) { - myReferencee = referencee; + public MyReference(PsiElement referredElement) { + myReferredElement = referredElement; } public PsiElement resolve() { - return myReferencee; + return myReferredElement; } public void processVariants(PsiScopeProcessor processor) { @@ -244,12 +233,14 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo @NotNull public JavaResolveResult advancedResolve(boolean incompleteCode) { - return myReferencee == null ? JavaResolveResult.EMPTY : new CandidateInfo(myReferencee, PsiSubstitutor.EMPTY); + return myReferredElement == null ? JavaResolveResult.EMPTY + : new CandidateInfo(myReferredElement, PsiSubstitutor.EMPTY); } @NotNull public JavaResolveResult[] multiResolve(boolean incompleteCode) { - return myReferencee == null ? JavaResolveResult.EMPTY_ARRAY : new JavaResolveResult[]{new CandidateInfo(myReferencee, PsiSubstitutor.EMPTY)}; + return myReferredElement == null ? JavaResolveResult.EMPTY_ARRAY + : new JavaResolveResult[]{new CandidateInfo(myReferredElement, PsiSubstitutor.EMPTY)}; } @NotNull @@ -269,21 +260,26 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo @NotNull public String getCanonicalText() { - return getNameElement().getText(); + final PsiElement nameElement = getNameElement(); + assert nameElement != null; + return nameElement.getText(); } public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { - final PsiElement element = getNameElement(); - final ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(element); + final PsiElement nameElement = getNameElement(); + assert nameElement != null; + final ASTNode treeElement = SourceTreeToPsiMap.psiToTreeNotNull(nameElement); final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(treeElement); - LeafElement newToken = Factory.createSingleLeafElement(DOC_TAG_VALUE_TOKEN, newElementName, charTableByTree, getManager()); - ((CompositeElement)treeElement.getTreeParent()).replaceChildInternal(SourceTreeToPsiMap.psiElementToTree(element), newToken); - return SourceTreeToPsiMap.treeElementToPsi(newToken); + final LeafElement newToken = Factory.createSingleLeafElement(DOC_TAG_VALUE_TOKEN, newElementName, charTableByTree, getManager()); + ((CompositeElement)treeElement.getTreeParent()).replaceChildInternal(SourceTreeToPsiMap.psiToTreeNotNull(nameElement), newToken); + return SourceTreeToPsiMap.treeToPsiNotNull(newToken); } public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { if (isReferenceTo(element)) return PsiDocMethodOrFieldRef.this; - final String name = getNameElement().getText(); + final PsiElement nameElement = getNameElement(); + assert nameElement != null; + final String name = nameElement.getText(); final String newName; final PsiMethod method; @@ -305,15 +301,16 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo throw new IncorrectOperationException(); } - - if (getFirstChild().getNode().getElementType() == ElementType.DOC_REFERENCE_HOLDER) { - PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement) getFirstChild().getFirstChild(); + final PsiElement child = getFirstChild(); + if (containingClass != null && child != null && child.getNode().getElementType() == ElementType.DOC_REFERENCE_HOLDER) { + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement) child.getFirstChild(); + assert referenceElement != null; referenceElement.bindToElement(containingClass); } else { - if (!PsiTreeUtil.isAncestor(containingClass, PsiDocMethodOrFieldRef.this, true)) { - final PsiReferenceExpression ref = - JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory().createReferenceExpression(containingClass); + if (containingClass != null && !PsiTreeUtil.isAncestor(containingClass, PsiDocMethodOrFieldRef.this, true)) { + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory(); + final PsiReferenceExpression ref = elementFactory.createReferenceExpression(containingClass); addAfter(ref, null); } } @@ -352,10 +349,11 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo } public PsiElement bindToText(PsiClass containingClass, StringBuffer newText) { - PsiComment comment = - JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory().createCommentFromText(newText.toString(), null); + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(containingClass.getProject()).getElementFactory(); + PsiComment comment = elementFactory.createCommentFromText(newText.toString(), null); PsiElement tag = PsiTreeUtil.getChildOfType(comment, PsiDocTag.class); PsiElement ref = PsiTreeUtil.getChildOfType(tag, PsiDocMethodOrFieldRef.class); + assert ref != null : newText; return replace(ref); } @@ -366,20 +364,20 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo public TextRange getRangeInElement() { final ASTNode sharp = findChildByType(DOC_TAG_VALUE_SHARP_TOKEN); if (sharp == null) return new TextRange(0, getTextLength()); - final PsiElement nextSibling = SourceTreeToPsiMap.treeElementToPsi(sharp).getNextSibling(); - if(nextSibling != null){ + final PsiElement nextSibling = SourceTreeToPsiMap.treeToPsiNotNull(sharp).getNextSibling(); + if (nextSibling != null) { final int startOffset = nextSibling.getTextRange().getStartOffset() - getTextRange().getStartOffset(); int endOffset = nextSibling.getTextRange().getEndOffset() - getTextRange().getStartOffset(); final PsiElement nextParSibling = nextSibling.getNextSibling(); - if(nextParSibling != null && "(".equals(nextParSibling.getText())){ - endOffset ++; + if (nextParSibling != null && "(".equals(nextParSibling.getText())) { + endOffset++; PsiElement nextElement = nextParSibling.getNextSibling(); - if(nextElement != null && SourceTreeToPsiMap.psiElementToTree(nextElement).getElementType() == DOC_TAG_VALUE_TOKEN){ + if (nextElement != null && SourceTreeToPsiMap.psiToTreeNotNull(nextElement).getElementType() == DOC_TAG_VALUE_TOKEN) { endOffset += nextElement.getTextLength(); nextElement = nextElement.getNextSibling(); } - if(nextElement != null && ")".equals(nextElement.getText())){ - endOffset ++; + if (nextElement != null && ")".equals(nextElement.getText())) { + endOffset++; } } return new TextRange(startOffset, endOffset); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java new file mode 100644 index 000000000000..5b7edc9ba85d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See0.java @@ -0,0 +1,15 @@ +package pkg; + +/** + * @see #method(pkg.B0.C[]) + * @see #method(B0.C[]) + * @see #method(B0.C...) + */ +class A0 { + public void method(B0.C[] c) { } +} + +class B0 { + class C { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java new file mode 100644 index 000000000000..24d1dae563da --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See1.java @@ -0,0 +1,16 @@ +package pkg; + +/** + * @see #method(B1.C) + * @see #method(B1.C[][]) + * @see #method(B1.C..) + * @see #method(B1.C[) + */ +class A1 { + public void method(B1.C[] c) { } +} + +class B1 { + class C { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java new file mode 100644 index 000000000000..e3d607e09b70 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/resolve/pkg/See2.java @@ -0,0 +1,13 @@ +package pkg; + +import java.util.List; + +/** + * @see #method(java.util.List) + * @see #method(java.util.List) + * @see #method(java.util.List) + * @see #method(java.util.List) + */ +class A2 { + public void method(List list) { } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java new file mode 100644 index 000000000000..6b2be0270645 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocResolveTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2011 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; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; +import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection; + +public class JavadocResolveTest extends DaemonAnalyzerTestCase { + private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/javaDoc/resolve"; + + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{new JavaDocLocalInspection(), new JavaDocReferenceInspection()}; + } + + public void testSee0() throws Exception { doTest(); } + public void testSee1() throws Exception { doTest(); } + public void testSee2() throws Exception { doTest(); } + + private void doTest() throws Exception { + doTest(BASE_PATH + "/pkg/" + getTestName(false) + ".java", BASE_PATH, false, false); + } +} diff --git a/java/openapi/src/com/intellij/psi/util/MethodSignature.java b/java/openapi/src/com/intellij/psi/util/MethodSignature.java index 8700d3ba3285..0e7496398166 100644 --- a/java/openapi/src/com/intellij/psi/util/MethodSignature.java +++ b/java/openapi/src/com/intellij/psi/util/MethodSignature.java @@ -23,16 +23,23 @@ import org.jetbrains.annotations.NotNull; /** * @author cdr */ - public interface MethodSignature { MethodSignature[] EMPTY_ARRAY = new MethodSignature[0]; - @NotNull PsiSubstitutor getSubstitutor(); - @NotNull String getName(); - /** - * already substituted - */ - @NotNull PsiType[] getParameterTypes(); - @NotNull PsiTypeParameter[] getTypeParameters(); - boolean isRaw(); + @NotNull + PsiSubstitutor getSubstitutor(); + + @NotNull + String getName(); + + /** + * @return array of parameter types (already substituted) + */ + @NotNull + PsiType[] getParameterTypes(); + + @NotNull + PsiTypeParameter[] getTypeParameters(); + + boolean isRaw(); } diff --git a/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java b/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java index 73318fb601a5..5a70a6862181 100644 --- a/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java +++ b/java/openapi/src/com/intellij/psi/util/MethodSignatureUtil.java @@ -29,6 +29,8 @@ import java.util.Set; public class MethodSignatureUtil { + private MethodSignatureUtil() { } + public static final TObjectHashingStrategy METHOD_BASED_HASHING_STRATEGY = new TObjectHashingStrategy() { public int computeHashCode(final MethodSignatureBackedByPsiMethod signature) { @@ -40,9 +42,6 @@ public class MethodSignatureUtil { } }; - private MethodSignatureUtil() { - } - public static MethodSignature createMethodSignature(@NonNls @NotNull String name, @Nullable PsiParameterList parameterTypes, @Nullable PsiTypeParameterList typeParameterList, @@ -154,10 +153,12 @@ public class MethodSignatureUtil { return null; } + @Nullable public static PsiMethod findMethodBySignature(final PsiClass aClass, PsiMethod pattenMethod, boolean checkBases) { return findMethodBySignature(aClass, pattenMethod.getSignature(PsiSubstitutor.EMPTY), checkBases); } + @Nullable public static PsiMethod findMethodBySignature(final PsiClass aClass, MethodSignature methodSignature, boolean checkBases) { List> pairs = aClass.findMethodsAndTheirSubstitutorsByName(methodSignature.getName(), checkBases); for (Pair pair : pairs) { @@ -181,13 +182,17 @@ public class MethodSignatureUtil { return null; } + @Nullable public static PsiMethod findMethodBySuperMethod(final PsiClass aClass, PsiMethod method, final boolean checkBases) { List> pairs = aClass.findMethodsAndTheirSubstitutorsByName(method.getName(), checkBases); for (Pair pair : pairs) { PsiMethod candidate = pair.first; PsiSubstitutor substitutor = pair.second; MethodSignature candidateSignature = candidate.getSignature(substitutor); - PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(method.getContainingClass(), candidate.getContainingClass(), substitutor); + final PsiClass methodClass = method.getContainingClass(); + final PsiClass candidateClass = candidate.getContainingClass(); + if (methodClass == null || candidateClass == null) continue; + PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(methodClass, candidateClass, substitutor); if (superSubstitutor == null) continue; MethodSignature superSignature = method.getSignature(superSubstitutor); if (isSubsignature(superSignature, candidateSignature)) return candidate; @@ -206,41 +211,47 @@ public class MethodSignatureUtil { } public static boolean areParametersErasureEqual(PsiMethod method1, PsiMethod method2) { - return METHOD_PARAMETERS_ERASURE_EQUALITY.equals(method1.getSignature(PsiSubstitutor.EMPTY), - method2.getSignature(PsiSubstitutor.EMPTY)); + return areSignaturesErasureEqual(method1.getSignature(PsiSubstitutor.EMPTY), method2.getSignature(PsiSubstitutor.EMPTY)); + } + + public static boolean areSignaturesErasureEqual(MethodSignature signature1, MethodSignature signature2) { + return METHOD_PARAMETERS_ERASURE_EQUALITY.equals(signature1, signature2); } /** - * @param methodSignature - * @param superMethodSignature + * @param methodSignature method signature + * @param superMethodSignature super method signature * @return null if signatures do not match */ + @Nullable public static PsiSubstitutor getSuperMethodSignatureSubstitutor(MethodSignature methodSignature, MethodSignature superMethodSignature) { PsiSubstitutor result = getSuperMethodSignatureSubstitutorImpl(methodSignature, superMethodSignature); if (result == null) return null; - PsiTypeParameter[] methoTypeParameters = methodSignature.getTypeParameters(); + PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters(); PsiTypeParameter[] superTypeParameters = superMethodSignature.getTypeParameters(); PsiSubstitutor methodSubstitutor = methodSignature.getSubstitutor(); //check bounds - for (int i = 0; i < methoTypeParameters.length; i++) { - PsiTypeParameter methoTypeParameter = methoTypeParameters[i]; + for (int i = 0; i < methodTypeParameters.length; i++) { + PsiTypeParameter methodTypeParameter = methodTypeParameters[i]; PsiTypeParameter superTypeParameter = superTypeParameters[i]; - final Set methoSupers = new HashSet(); - for (PsiClassType methoSuper : methoTypeParameter.getSuperTypes()) { - methoSupers.add(methodSubstitutor.substitute(methoSuper)); + final Set methodSupers = new HashSet(); + for (PsiClassType methodSuper : methodTypeParameter.getSuperTypes()) { + methodSupers.add(methodSubstitutor.substitute(methodSuper)); } final Set superSupers = new HashSet(); for (PsiClassType superSuper : superTypeParameter.getSuperTypes()) { - superSupers.add(methodSubstitutor.substitute(PsiUtil.captureToplevelWildcards(result.substitute(superSuper), methoTypeParameter))); + superSupers.add(methodSubstitutor.substitute(PsiUtil.captureToplevelWildcards(result.substitute(superSuper), methodTypeParameter))); } - if (!methoSupers.equals(superSupers)) return null; + if (!methodSupers.equals(superSupers)) return null; } + return result; } + @Nullable private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl(MethodSignature methodSignature, MethodSignature superSignature) { // normalize generic method declarations: correlate type parameters // todo: correlate type params by name? @@ -336,5 +347,4 @@ public class MethodSignatureUtil { } return true; } - } From e85c8e76790a6ccbf5958d300b580339692d8c41 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 7 Mar 2011 23:21:50 +0100 Subject: [PATCH 39/95] dump threads in case of long completion --- .../codeInsight/completion/CompletionAutoPopupTestCase.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy index 42b0ce7f8a65..7ddc6eb88ff5 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy +++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy @@ -65,6 +65,7 @@ abstract class CompletionAutoPopupTestCase extends LightCodeInsightFixtureTestCa } Thread.sleep(10) } + printThreadDump() fail("Too long completion") } From 74c59d68589228695793153958bfcc07ee32c96a Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Mon, 7 Mar 2011 10:37:01 +0300 Subject: [PATCH 40/95] always complete methods with parentheses --- .../lang/completion/GroovyInsertHandler.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java index c8cbac520a5c..f56ad775fe74 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java @@ -29,16 +29,9 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; -import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrSwitchStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; @@ -73,14 +66,16 @@ public class GroovyInsertHandler implements InsertHandler { CaretModel caretModel = editor.getCaretModel(); int offset = context.getStartOffset() + method.getName().length(); PsiFile file = PsiDocumentManager.getInstance(method.getProject()).getPsiFile(document); + assert file != null; PsiElement elementAt = file.findElementAt(context.getStartOffset()); - PsiElement parent = elementAt != null ? elementAt.getParent() : null; + assert elementAt != null; + PsiElement parent = elementAt.getParent(); if (parent instanceof GrReferenceExpression && ((GrReferenceExpression)parent).getDotTokenType() == GroovyElementTypes.mMEMBER_POINTER) { return; } - if (parent instanceof GrAnnotationNameValuePair || parent.getParent() instanceof GrAnnotationNameValuePair) { + if (parent instanceof GrAnnotationNameValuePair || parent != null && parent.getParent() instanceof GrAnnotationNameValuePair) { document.insertString(offset, " = "); caretModel.moveToOffset(offset + 3); return; @@ -102,10 +97,13 @@ public class GroovyInsertHandler implements InsertHandler { PsiDocumentManager docManager = PsiDocumentManager.getInstance(method.getProject()); docManager.commitDocument(document); + /* + //always use parentheses + PsiFile psiFile = docManager.getPsiFile(document); if (method.getParameterList().getParametersCount() > 0 && isExpressionStatement(psiFile, context.getStartOffset())) { return; - } + }*/ new MethodParenthesesHandler(method, true).handleInsert(context, item); return; @@ -122,7 +120,9 @@ public class GroovyInsertHandler implements InsertHandler { Editor editor = context.getEditor(); Document document = editor.getDocument(); PsiFile file = PsiDocumentManager.getInstance(clazz.getProject()).getPsiFile(document); + assert file != null; PsiElement elementAt = file.findElementAt(context.getStartOffset()); + assert elementAt != null; CaretModel caretModel = editor.getCaretModel(); int offset = context.getStartOffset() + elementAt.getTextLength(); @@ -153,6 +153,7 @@ public class GroovyInsertHandler implements InsertHandler { addTailType(item).processTail(context.getEditor(), context.getTailOffset()); } + /* private static boolean isExpressionStatement(PsiFile psiFile, int offset) { PsiElement elementAt = psiFile.findElementAt(offset); if (elementAt == null) return false; @@ -170,6 +171,7 @@ public class GroovyInsertHandler implements InsertHandler { } return true; } + */ private static void handleOverwrite(final int offset, final Document document) { final CharSequence sequence = document.getCharsSequence(); From 4409f2e56af2e55915e0f22bb2d2ae5a42cf1ded Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Tue, 8 Mar 2011 11:14:28 +0300 Subject: [PATCH 41/95] tests --- .../groovy/completion/GroovyClassNameCompletionTest.groovy | 4 ++-- .../plugins/groovy/completion/GroovyCompletionTest.groovy | 2 +- .../groovy/completion/ArrayLikeAccessForList_after.groovy | 2 +- .../groovy/completion/ArrayLikeAccessForMap_after.groovy | 2 +- .../ClosureDefaultParameterInEachMethod_after.groovy | 2 +- .../testdata/groovy/completion/EachMethodForList_after.groovy | 2 +- .../groovy/completion/InjectMethodForCollection_after.groovy | 2 +- .../completion/InstanceofHelpsDetermineType_after.groovy | 2 +- plugins/groovy/testdata/groovy/dsl/CompleteMethod_after.gdsl | 2 +- .../groovy/testdata/groovy/dsl/CompleteProperty_after.gdsl | 2 +- .../testdata/groovy/dsl/DelegateToArgument2_after.groovy | 2 +- .../testdata/groovy/dsl/DelegateToArgument_after.groovy | 2 +- .../testdata/groovy/dsl/DelegateToThrowable_after.groovy | 2 +- .../groovy/dsl/transform/BindableTransform_after.groovy | 2 +- .../groovy/dsl/transform/DelegateAnnotation_after.groovy | 2 +- .../groovy/dsl/transform/VetoableTransform_after.groovy | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy index b1d72f4266a6..6ab8b945c9d5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy @@ -123,7 +123,7 @@ class Foo { myFixture.checkResult """import static Foo.abcmethod1 def foo() { - abcmethod1 + abcmethod1() }""" } @@ -140,7 +140,7 @@ class Foo { myFixture.checkResult """import foo.Foo def foo() { - Foo.abcmethod + Foo.abcmethod() }""" } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 6fca0e0eabf4..76df8dd40eed 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -487,7 +487,7 @@ form""" myFixture.completeBasic() myFixture.checkResult """import static java.lang.String.format -format""" +format()""" } public void testImportAsterisk() { diff --git a/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList_after.groovy b/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList_after.groovy index 1b4068d5673c..e5f06e0fea48 100644 --- a/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList_after.groovy +++ b/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForList_after.groovy @@ -1,4 +1,4 @@ def foo() { List list=['a', 'b'] - list[0].substring + list[0].substring() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForMap_after.groovy b/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForMap_after.groovy index 4f225e2cdff4..90f20ad5f46e 100644 --- a/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForMap_after.groovy +++ b/plugins/groovy/testdata/groovy/completion/ArrayLikeAccessForMap_after.groovy @@ -1,4 +1,4 @@ def foo() { map=[1:'a', 3:'b', 2:'c'] - map[2].substring + map[2].substring() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/ClosureDefaultParameterInEachMethod_after.groovy b/plugins/groovy/testdata/groovy/completion/ClosureDefaultParameterInEachMethod_after.groovy index dbb37d2a22ad..ebfa4d86c902 100644 --- a/plugins/groovy/testdata/groovy/completion/ClosureDefaultParameterInEachMethod_after.groovy +++ b/plugins/groovy/testdata/groovy/completion/ClosureDefaultParameterInEachMethod_after.groovy @@ -1,4 +1,4 @@ list=['a', 'b'] list.each{ - it.substring + it.substring() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/EachMethodForList_after.groovy b/plugins/groovy/testdata/groovy/completion/EachMethodForList_after.groovy index 0654bd4c87d5..dc5c8a65e5c9 100644 --- a/plugins/groovy/testdata/groovy/completion/EachMethodForList_after.groovy +++ b/plugins/groovy/testdata/groovy/completion/EachMethodForList_after.groovy @@ -1,5 +1,5 @@ List list=['1', '2', '3'] list.each{ it-> - it.substring + it.substring() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/InjectMethodForCollection_after.groovy b/plugins/groovy/testdata/groovy/completion/InjectMethodForCollection_after.groovy index f62e8c9767db..a76bbb7ff7fe 100644 --- a/plugins/groovy/testdata/groovy/completion/InjectMethodForCollection_after.groovy +++ b/plugins/groovy/testdata/groovy/completion/InjectMethodForCollection_after.groovy @@ -1,5 +1,5 @@ List list=['a', 'b', 'c'] list.inject(2){ value, item-> - item.substring + item.substring() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineType_after.groovy b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineType_after.groovy index 9c4596406b52..1949bba36189 100644 --- a/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineType_after.groovy +++ b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineType_after.groovy @@ -2,7 +2,7 @@ public class Parent { def foo(o) { if (o instanceof String) { - o.substring + o.substring() } } diff --git a/plugins/groovy/testdata/groovy/dsl/CompleteMethod_after.gdsl b/plugins/groovy/testdata/groovy/dsl/CompleteMethod_after.gdsl index 9e7599eac9c6..a0eabb8f4134 100644 --- a/plugins/groovy/testdata/groovy/dsl/CompleteMethod_after.gdsl +++ b/plugins/groovy/testdata/groovy/dsl/CompleteMethod_after.gdsl @@ -1,5 +1,5 @@ def ctx = context(filetypes : ["unknown"]) contributor([ctx]) { - method + method() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/CompleteProperty_after.gdsl b/plugins/groovy/testdata/groovy/dsl/CompleteProperty_after.gdsl index bfd1d8033686..d3b00b065857 100644 --- a/plugins/groovy/testdata/groovy/dsl/CompleteProperty_after.gdsl +++ b/plugins/groovy/testdata/groovy/dsl/CompleteProperty_after.gdsl @@ -1,5 +1,5 @@ def ctx = context(filetypes : ["unknown"]) contributor([ctx]) { - findClass + findClass() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/DelegateToArgument2_after.groovy b/plugins/groovy/testdata/groovy/dsl/DelegateToArgument2_after.groovy index 3b3970e2cb0e..df00af3672ac 100644 --- a/plugins/groovy/testdata/groovy/dsl/DelegateToArgument2_after.groovy +++ b/plugins/groovy/testdata/groovy/dsl/DelegateToArgument2_after.groovy @@ -10,5 +10,5 @@ class Runner { def runner = new Runner() runner.boo new MyDelegate(), { - saySomething + saySomething() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/DelegateToArgument_after.groovy b/plugins/groovy/testdata/groovy/dsl/DelegateToArgument_after.groovy index 642d7d89b14f..ddc2cfb45a0b 100644 --- a/plugins/groovy/testdata/groovy/dsl/DelegateToArgument_after.groovy +++ b/plugins/groovy/testdata/groovy/dsl/DelegateToArgument_after.groovy @@ -13,5 +13,5 @@ class Runner { def runner = new Runner() runner.boo(new MyDelegate()) { - saySomething + saySomething() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/DelegateToThrowable_after.groovy b/plugins/groovy/testdata/groovy/dsl/DelegateToThrowable_after.groovy index 119fcc250b70..2cc741907560 100644 --- a/plugins/groovy/testdata/groovy/dsl/DelegateToThrowable_after.groovy +++ b/plugins/groovy/testdata/groovy/dsl/DelegateToThrowable_after.groovy @@ -1,3 +1,3 @@ def foo() { - "".initCause + "".initCause() } \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/transform/BindableTransform_after.groovy b/plugins/groovy/testdata/groovy/dsl/transform/BindableTransform_after.groovy index 988d22ca9120..386ac0bf593f 100644 --- a/plugins/groovy/testdata/groovy/dsl/transform/BindableTransform_after.groovy +++ b/plugins/groovy/testdata/groovy/dsl/transform/BindableTransform_after.groovy @@ -6,4 +6,4 @@ class MyBean { def bean = new MyBean() -bean.firePropertyChange \ No newline at end of file +bean.firePropertyChange() \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/transform/DelegateAnnotation_after.groovy b/plugins/groovy/testdata/groovy/dsl/transform/DelegateAnnotation_after.groovy index f4df12c746b2..685101bd59fa 100644 --- a/plugins/groovy/testdata/groovy/dsl/transform/DelegateAnnotation_after.groovy +++ b/plugins/groovy/testdata/groovy/dsl/transform/DelegateAnnotation_after.groovy @@ -12,4 +12,4 @@ def gr8conf = new Event(title: "GR8 Conference", when: df.parse("2009/05/18")) -gr8conf.before \ No newline at end of file +gr8conf.before() \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/transform/VetoableTransform_after.groovy b/plugins/groovy/testdata/groovy/dsl/transform/VetoableTransform_after.groovy index 8610d6331944..a2294ccbf53a 100644 --- a/plugins/groovy/testdata/groovy/dsl/transform/VetoableTransform_after.groovy +++ b/plugins/groovy/testdata/groovy/dsl/transform/VetoableTransform_after.groovy @@ -6,4 +6,4 @@ class MyBean { def bean = new MyBean() -bean.fireVetoableChange \ No newline at end of file +bean.fireVetoableChange() \ No newline at end of file From ca4decf447d3213074cbd3263f8c56c7e85ee73a Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Tue, 8 Mar 2011 11:27:31 +0300 Subject: [PATCH 42/95] IDEA-65998 Groovy: Introduce Variable intention should work on application statement. (Method call without brackets) --- .../lang/completion/GroovyInsertHandler.java | 20 --------- .../plugins/groovy/lang/psi/util/PsiUtil.java | 23 ++++++++-- .../introduce/GrIntroduceHandlerBase.java | 45 ++++++++++--------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java index f56ad775fe74..d3c280db6494 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyInsertHandler.java @@ -153,26 +153,6 @@ public class GroovyInsertHandler implements InsertHandler { addTailType(item).processTail(context.getEditor(), context.getTailOffset()); } - /* - private static boolean isExpressionStatement(PsiFile psiFile, int offset) { - PsiElement elementAt = psiFile.findElementAt(offset); - if (elementAt == null) return false; - GrExpression expr = PsiTreeUtil.getParentOfType(elementAt, GrExpression.class); - if (expr == null) return false; - final PsiElement parent = expr.getParent(); - if (parent instanceof GrControlFlowOwner) return true; - if (parent instanceof GrExpression || - parent instanceof GrArgumentList || - parent instanceof GrReturnStatement || - parent instanceof GrAssertStatement || - parent instanceof GrThrowStatement || - parent instanceof GrSwitchStatement) { - return false; - } - return true; - } - */ - private static void handleOverwrite(final int offset, final Document document) { final CharSequence sequence = document.getCharsSequence(); int i = offset; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 24b735fc2784..428e1930836e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -50,14 +50,14 @@ import org.jetbrains.plugins.groovy.lang.psi.*; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrTopLevelDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; @@ -1097,4 +1097,19 @@ public class PsiUtil { } return qualifier == null; } + + public static boolean isExpressionStatement(GrExpression expr) { + final PsiElement parent = expr.getParent(); + if (parent instanceof GrControlFlowOwner) return true; + if (parent instanceof GrExpression || + parent instanceof GrArgumentList || + parent instanceof GrReturnStatement || + parent instanceof GrAssertStatement || + parent instanceof GrThrowStatement || + parent instanceof GrSwitchStatement) { + return false; + } + return true; + } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java index 02005c549138..976e2880edef 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java @@ -89,22 +89,31 @@ public abstract class GrIntroduceHandlerBase Date: Mon, 7 Mar 2011 15:36:02 +0100 Subject: [PATCH 43/95] diamonds: do not pay attention to param names for static factory --- java/openapi/src/com/intellij/psi/PsiDiamondType.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/openapi/src/com/intellij/psi/PsiDiamondType.java b/java/openapi/src/com/intellij/psi/PsiDiamondType.java index 5b1488918a12..74a9aefdf80f 100644 --- a/java/openapi/src/com/intellij/psi/PsiDiamondType.java +++ b/java/openapi/src/com/intellij/psi/PsiDiamondType.java @@ -187,9 +187,10 @@ public class PsiDiamondType extends PsiType { } else { buf.append("(").append(StringUtil.join(constructor.getParameterList().getParameters(), new Function() { + int myIdx = 0; @Override public String fun(PsiParameter psiParameter) { - return psiParameter.getType().getCanonicalText() + " " + psiParameter.getName(); + return psiParameter.getType().getCanonicalText() + " p" + myIdx++; } }, ",")).append(")"); } From b5303937f99d05bd3d2670828fd2467ca2d0fea6 Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 7 Mar 2011 15:37:15 +0100 Subject: [PATCH 44/95] diamonds: do not warn about broken inference for raw types (IDEA-66132) --- .../impl/analysis/GenericsHighlightUtil.java | 46 +++++++++++++++++-- .../advHighlighting7/DiamondMisc.java | 1 + 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index d81969add235..5d5401bbbac2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -33,6 +33,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.*; +import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; @@ -115,11 +116,14 @@ public class GenericsHighlightUtil { if (!typeParameterListOwner.hasTypeParameters()) { return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], "Diamond operator is not applicable for non-parameterized types"); } - inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes(); - final String errorMessage = inferenceResult.getErrorMessage(); + final PsiType expectedType = detectExpectedType(referenceParameterList); + if (!(expectedType instanceof PsiClassType && ((PsiClassType)expectedType).isRaw())) { + inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes(); + final String errorMessage = inferenceResult.getErrorMessage(); if (errorMessage != null) { - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], errorMessage); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], errorMessage); } + } } } @@ -175,6 +179,42 @@ public class GenericsHighlightUtil { return null; } + private static PsiType detectExpectedType(PsiReferenceParameterList referenceParameterList) { + final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class); + LOG.assertTrue(newExpression != null); + final PsiElement parent = newExpression.getParent(); + PsiType expectedType = null; + if (parent instanceof PsiVariable && newExpression.equals(((PsiVariable)parent).getInitializer())) { + expectedType = ((PsiVariable)parent).getType(); + } + else if (parent instanceof PsiAssignmentExpression && newExpression.equals(((PsiAssignmentExpression)parent).getRExpression())) { + expectedType = ((PsiAssignmentExpression)parent).getLExpression().getType(); + } + else if (parent instanceof PsiReturnStatement) { + PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); + if (method != null) { + expectedType = method.getReturnType(); + } + } + else if (parent instanceof PsiExpressionList) { + final PsiElement pParent = parent.getParent(); + if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) { + final PsiMethod method = ((PsiCallExpression)pParent).resolveMethod(); + if (method != null) { + final PsiExpression[] expressions = ((PsiCallExpression)pParent).getArgumentList().getExpressions(); + final int idx = ArrayUtil.find(expressions, newExpression); + if (idx > -1) { + final PsiParameterList parameterList = method.getParameterList(); + if (idx < parameterList.getParametersCount()) { + expectedType = parameterList.getParameters()[idx].getType(); + } + } + } + } + } + return expectedType; + } + @Nullable private static HighlightInfo checkTypeParameterWithinItsBound(final PsiTypeParameter classParameter, final PsiSubstitutor substitutor, diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java index 1258a5350bf8..cd7fc761fea1 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java @@ -3,6 +3,7 @@ import java.util.List; class Test { List queue = new ArrayList<>(); + ArrayList l = new ArrayList<>(8); } class DD { From 7a2f03d06bd7425f6da1d25cd29cd49caa43e442 Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 7 Mar 2011 16:03:14 +0100 Subject: [PATCH 45/95] do not try to generify according to failed diamond inference --- .../deductive/resolver/BindingFactory.java | 19 +++++++++++-------- .../typeCook/t152/after/Test.1.items | 2 ++ .../typeCook/t152/after/Test.items | 2 ++ .../refactoring/typeCook/t152/after/test.java | 6 ++++++ .../typeCook/t152/before/test.java | 6 ++++++ .../intellij/refactoring/TypeCookTest.java | 4 ++++ 6 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 java/java-tests/testData/refactoring/typeCook/t152/after/Test.1.items create mode 100644 java/java-tests/testData/refactoring/typeCook/t152/after/Test.items create mode 100644 java/java-tests/testData/refactoring/typeCook/t152/after/test.java create mode 100644 java/java-tests/testData/refactoring/typeCook/t152/before/test.java diff --git a/java/java-impl/src/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java b/java/java-impl/src/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java index b2ca2440fb44..922869ef2622 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java +++ b/java/java-impl/src/com/intellij/refactoring/typeCook/deductive/resolver/BindingFactory.java @@ -203,8 +203,10 @@ public class BindingFactory { return null; } - b3.myBindings.put(i, type); - b3.myCyclic = type instanceof PsiTypeVariable; + if (type != PsiType.NULL) { + b3.myBindings.put(i, type); + b3.myCyclic = type instanceof PsiTypeVariable; + } } break; @@ -216,8 +218,10 @@ public class BindingFactory { return null; } - b3.myBindings.put(i, type); - b3.myCyclic = type instanceof PsiTypeVariable; + if (type != PsiType.NULL) { + b3.myBindings.put(i, type); + b3.myCyclic = type instanceof PsiTypeVariable; + } } break; @@ -234,12 +238,11 @@ public class BindingFactory { return null; } - if (type == null) { - return null; + if (type != PsiType.NULL) { + b3.myBindings.put(i, type); + b3.myCyclic = type instanceof PsiTypeVariable; } - b3.myBindings.put(i, type); - b3.myCyclic = type instanceof PsiTypeVariable; } } } diff --git a/java/java-tests/testData/refactoring/typeCook/t152/after/Test.1.items b/java/java-tests/testData/refactoring/typeCook/t152/after/Test.1.items new file mode 100644 index 000000000000..a8f3261e48c0 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/t152/after/Test.1.items @@ -0,0 +1,2 @@ +java.util.ArrayList\nPsiField:l +java.util.ArrayList\nnew diff --git a/java/java-tests/testData/refactoring/typeCook/t152/after/Test.items b/java/java-tests/testData/refactoring/typeCook/t152/after/Test.items new file mode 100644 index 000000000000..a8f3261e48c0 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/t152/after/Test.items @@ -0,0 +1,2 @@ +java.util.ArrayList\nPsiField:l +java.util.ArrayList\nnew diff --git a/java/java-tests/testData/refactoring/typeCook/t152/after/test.java b/java/java-tests/testData/refactoring/typeCook/t152/after/test.java new file mode 100644 index 000000000000..41aa81d718e7 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/t152/after/test.java @@ -0,0 +1,6 @@ +import java.util.ArrayList; + +class Test +{ + ArrayList l = new ArrayList<>(8); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/typeCook/t152/before/test.java b/java/java-tests/testData/refactoring/typeCook/t152/before/test.java new file mode 100644 index 000000000000..41aa81d718e7 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/t152/before/test.java @@ -0,0 +1,6 @@ +import java.util.ArrayList; + +class Test +{ + ArrayList l = new ArrayList<>(8); +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java b/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java index 9fea974ce682..a27d64bdceb8 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java @@ -648,6 +648,10 @@ public class TypeCookTest extends MultiFileTestCase { start(); } + public void testT152() throws Exception { + start(); + } + public void start() throws Exception { start(false); } From afd90a6695f8ec47ec41444ba65eac8a46e67ab1 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 8 Mar 2011 11:25:19 +0100 Subject: [PATCH 46/95] replace diamond with type on inline when after inline diamond won't be inferred (IDEA-66142) --- .../intellij/refactoring/util/InlineUtil.java | 42 ++++++++++++++++++- .../inlineLocal/NewExpressionWithDiamond.java | 9 ++++ .../NewExpressionWithDiamond.java.after | 8 ++++ .../NewExpressionWithPreservedDiamond.java | 9 ++++ ...wExpressionWithPreservedDiamond.java.after | 8 ++++ .../refactoring/inline/InlineLocalTest.java | 8 ++++ .../src/com/intellij/psi/PsiDiamondType.java | 34 +++++++++++++-- 7 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java create mode 100644 java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java.after create mode 100644 java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java create mode 100644 java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java b/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java index ca2ac72bb928..a605ca4a8125 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java @@ -53,7 +53,7 @@ public class InlineUtil { initializer = RefactoringUtil.convertInitializerToNormalExpression(initializer, varType); ChangeContextUtil.encodeContextInfo(initializer, false); - PsiExpression expr = (PsiExpression)ref.replace(initializer); + PsiExpression expr = (PsiExpression)replaceDiamondWithInferredTypesIfNeeded(initializer, ref); PsiType exprType = expr.getType(); if (exprType != null && (!varType.equals(exprType) && varType instanceof PsiPrimitiveType || !TypeConversionUtil.isAssignable(varType, exprType))) { @@ -315,6 +315,46 @@ public class InlineUtil { }); } + private static PsiElement replaceDiamondWithInferredTypesIfNeeded(PsiExpression initializer, PsiElement ref) { + if (initializer instanceof PsiNewExpression) { + final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)initializer).getClassOrAnonymousClassReference(); + if (classReference != null) { + final PsiReferenceParameterList parameterList = classReference.getParameterList(); + if (parameterList != null) { + final PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements(); + if (typeParameterElements.length == 1) { + final PsiType type = typeParameterElements[0].getType(); + if (type instanceof PsiDiamondType) { + final PsiDiamondType.DiamondInferenceResult inferenceResult = ((PsiDiamondType)type).resolveInferredTypes(); + if (inferenceResult.getErrorMessage() == null) { + final PsiElement copy = ref.copy(); + final PsiElement parent = ref.replace(initializer); + final PsiDiamondType.DiamondInferenceResult result = PsiDiamondType.resolveInferredTypes((PsiNewExpression)initializer, parent); + ref = parent.replace(copy); + if (!result.equals(inferenceResult)) { + final String inferredTypeText = StringUtil.join(inferenceResult.getTypes(), + new Function() { + @Override + public String fun(PsiType psiType) { + return psiType.getCanonicalText(); + } + }, ", "); + final PsiExpressionList argumentList = ((PsiNewExpression)initializer).getArgumentList(); + if (argumentList != null) { + final PsiExpression expression = JavaPsiFacade.getElementFactory(initializer.getProject()) + .createExpressionFromText("new " + classReference.getReferenceName() + "<" + inferredTypeText + ">" + argumentList.getText(), initializer); + return ref.replace(expression); + } + } + } + } + } + } + } + } + return ref.replace(initializer); + } + public enum TailCallType { None, Simple, Return } diff --git a/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java new file mode 100644 index 000000000000..b5630a408bbd --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java @@ -0,0 +1,9 @@ +import java.util.*; + +class Test { + + void foo(){ + Map map = new HashMap<>(); + System.out.println(map); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java.after b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java.after new file mode 100644 index 000000000000..2b1d4fde39fe --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithDiamond.java.after @@ -0,0 +1,8 @@ +import java.util.*; + +class Test { + + void foo(){ + System.out.println(new HashMap()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java new file mode 100644 index 000000000000..786d23a2e7f7 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java @@ -0,0 +1,9 @@ +import java.util.*; + +class Test { + + void foo(){ + Map map = new HashMap<>(); + Map map1 = map; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java.after b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java.after new file mode 100644 index 000000000000..eb76943ecdac --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/NewExpressionWithPreservedDiamond.java.after @@ -0,0 +1,8 @@ +import java.util.*; + +class Test { + + void foo(){ + Map map1 = new HashMap<>(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java index adf2b4571e95..c0e4cb1784b3 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -70,6 +70,14 @@ public class InlineLocalTest extends LightCodeInsightTestCase { doTest(false); } + public void testNewExpressionWithDiamond() throws Exception { + doTest(false); + } + + public void testNewExpressionWithPreservedDiamond() throws Exception { + doTest(false); + } + public void testAugmentedAssignment() throws Exception { String exception = null; try { diff --git a/java/openapi/src/com/intellij/psi/PsiDiamondType.java b/java/openapi/src/com/intellij/psi/PsiDiamondType.java index 74a9aefdf80f..35f49ac799d2 100644 --- a/java/openapi/src/com/intellij/psi/PsiDiamondType.java +++ b/java/openapi/src/com/intellij/psi/PsiDiamondType.java @@ -18,11 +18,13 @@ package com.intellij.psi; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -97,6 +99,11 @@ public class PsiDiamondType extends PsiType { } public static DiamondInferenceResult resolveInferredTypes(PsiNewExpression newExpression) { + return resolveInferredTypes(newExpression, newExpression); + } + + public static DiamondInferenceResult resolveInferredTypes(PsiNewExpression newExpression, + PsiElement context) { final PsiClass psiClass = findClass(newExpression); if (psiClass == null) return DiamondInferenceResult.NULL_RESULT; final PsiExpressionList argumentList = newExpression.getArgumentList(); @@ -107,7 +114,7 @@ public class PsiDiamondType extends PsiType { if (staticFactory == null) { return DiamondInferenceResult.NULL_RESULT; } - final PsiSubstitutor inferredSubstitutor = inferTypeParametersForStaticFactory(staticFactory, newExpression); + final PsiSubstitutor inferredSubstitutor = inferTypeParametersForStaticFactory(staticFactory, newExpression, context); final PsiTypeParameter[] parameters = staticFactory.getTypeParameters(); final PsiTypeParameter[] classParameters = psiClass.getTypeParameters(); final PsiJavaCodeReferenceElement classOrAnonymousClassReference = newExpression.getClassOrAnonymousClassReference(); @@ -210,14 +217,15 @@ public class PsiDiamondType extends PsiType { private static PsiSubstitutor inferTypeParametersForStaticFactory(@NotNull PsiMethod staticFactoryMethod, - PsiNewExpression expression) { + PsiNewExpression expression, + PsiElement parent) { final JavaPsiFacade facade = JavaPsiFacade.getInstance(staticFactoryMethod.getProject()); final PsiResolveHelper resolveHelper = facade.getResolveHelper(); final PsiParameter[] parameters = staticFactoryMethod.getParameterList().getParameters(); final PsiExpressionList argumentList = expression.getArgumentList(); final PsiExpression[] expressions = argumentList.getExpressions(); return resolveHelper - .inferTypeArguments(staticFactoryMethod.getTypeParameters(), parameters, expressions, PsiSubstitutor.EMPTY, expression, false); + .inferTypeArguments(staticFactoryMethod.getTypeParameters(), parameters, expressions, PsiSubstitutor.EMPTY, parent, false); } public static class DiamondInferenceResult { @@ -301,6 +309,26 @@ public class PsiDiamondType extends PsiType { } }); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DiamondInferenceResult that = (DiamondInferenceResult)o; + + if (myErrorMessage != null ? !myErrorMessage.equals(that.myErrorMessage) : that.myErrorMessage != null) return false; + if (!myInferredTypes.equals(that.myInferredTypes)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myInferredTypes.hashCode(); + result = 31 * result + (myErrorMessage != null ? myErrorMessage.hashCode() : 0); + return result; + } } public static boolean hasDefaultConstructor(@NotNull final PsiClass psiClass) { From 31812655f7e194a3d6f48957daf49e5d8137d81d Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 13:04:12 +0100 Subject: [PATCH 47/95] test warmup --- .../plugins/groovy/completion/GroovyAutoPopupTest.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index f373c397a78f..7be3e79ba8f9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -35,6 +35,7 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { return xx } """) + edt { myFixture.doHighlighting() } type 'x' assert !lookup.focused } From 64d8bb5389b0dcbb0c6bd92c7da78f8d3b63c8ef Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 13:04:23 +0100 Subject: [PATCH 48/95] cache gdsl member providers --- .../plugins/groovy/dsl/ExtensibleCustomMembersGenerator.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/ExtensibleCustomMembersGenerator.groovy b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/ExtensibleCustomMembersGenerator.groovy index 2e995b575176..2dea0670b083 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/ExtensibleCustomMembersGenerator.groovy +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/ExtensibleCustomMembersGenerator.groovy @@ -8,6 +8,7 @@ import org.jetbrains.plugins.groovy.dsl.dsltop.GdslMembersProvider * @author peter, ilyas */ public class ExtensibleCustomMembersGenerator extends CustomMembersGenerator { + final def memberProviders = GdslMembersProvider.EP_NAME.getExtensions() public ExtensibleCustomMembersGenerator(GroovyClassDescriptor descriptor, PsiType type) { super(descriptor, type) @@ -17,7 +18,7 @@ public class ExtensibleCustomMembersGenerator extends CustomMembersGenerator { final def newArgs = constructNewArgs(args) // Get other DSL methods from extensions - for (d in GdslMembersProvider.EP_NAME.getExtensions()) { + for (d in memberProviders) { final def variants = d.metaClass.respondsTo(d, name, newArgs) if (variants.size() == 1) { return d.invokeMethod(name, newArgs) From 0fbbc0830c5454eb49a1dcf4195c22a1599e5dab Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 8 Mar 2011 13:43:30 +0100 Subject: [PATCH 49/95] do not invoke dialogs from write action ( IDEA-66321) --- .../codeInspection/i18n/I18nInspection.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java index ef40d05531d6..510abd5cb1f7 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/I18nInspection.java @@ -29,6 +29,7 @@ import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.BaseLocalInspectionTool; import com.intellij.ide.util.TreeClassChooser; import com.intellij.ide.util.TreeClassChooserFactory; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.Extensions; @@ -373,14 +374,20 @@ public class I18nInspection extends BaseLocalInspectionTool { } public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { - List exprList = new ArrayList(); - for (SmartPsiElementPointer ptr : pointers) { - PsiExpression expr = ptr.getElement(); - if (expr != null && expr.isValid()) { - exprList.add(expr); + final Runnable runnable = new Runnable() { + public void run() { + List exprList = new ArrayList(); + for (SmartPsiElementPointer ptr : pointers) { + PsiExpression expr = ptr.getElement(); + if (expr != null && expr.isValid()) { + exprList.add(expr); + } + } + new IntroduceConstantHandler().invoke(project, exprList.toArray(new PsiExpression[exprList.size()])); } - } - new IntroduceConstantHandler().invoke(project, exprList.toArray(new PsiExpression[exprList.size()])); + }; + //do it later because it is invoked from write action + ApplicationManager.getApplication().invokeLater(runnable); } @NotNull From e474af0f75a263937425c74c4815fd9c9681a463 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 8 Mar 2011 14:23:42 +0100 Subject: [PATCH 50/95] clarify description --- .../src/inspectionDescriptions/FinalStaticMethod.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html index eab6a5cd037e..d78ba0deaec8 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html @@ -1,9 +1,11 @@ -This inspection reports methods -declared final and static. -As static methods cannot be meaningfully overridden, declaring them -final is redundant. +This inspection reports methods declared final and static. +When a static method is overridden in a subclass it can still be +accessed via the super class, making a final declaration not very necessary. +Declaring a static method final +does prevent subclasses from defining a static method with the same +signature.

Powered by InspectionGadgets From 6955640b755e694d014ef3f34606038f6d998e9d Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 8 Mar 2011 14:24:03 +0100 Subject: [PATCH 51/95] cleanup --- .../siyeh/ig/classlayout/FinalClassInspection.java | 10 +++++++--- .../ig/classlayout/FinalPrivateMethodInspection.java | 11 ++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java index b0dfe1f80e50..3e1964c810eb 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,26 +26,30 @@ import org.jetbrains.annotations.NotNull; public class FinalClassInspection extends BaseInspection { + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message("final.class.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "final.class.problem.descriptor"); } + @Override public BaseInspectionVisitor buildVisitor() { - return new FinalStaticMethodVisitor(); + return new FinalStaticClassVisitor(); } + @Override public InspectionGadgetsFix buildFix(Object... infos) { return new RemoveModifierFix((String)infos[0]); } - private static class FinalStaticMethodVisitor + private static class FinalStaticClassVisitor extends BaseInspectionVisitor { @Override public void visitClass(@NotNull PsiClass aClass) { diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java index 0c5e1732208b..bd1d801a5906 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,31 +26,36 @@ import org.jetbrains.annotations.NotNull; public class FinalPrivateMethodInspection extends BaseInspection { + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "final.private.method.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "final.private.method.problem.descriptor"); } + @Override public boolean isEnabledByDefault() { return true; } + @Override public BaseInspectionVisitor buildVisitor() { - return new FinalStaticMethodVisitor(); + return new FinalPrivateMethodVisitor(); } + @Override public InspectionGadgetsFix buildFix(Object... infos) { return new RemoveModifierFix((String) infos[0]); } - private static class FinalStaticMethodVisitor + private static class FinalPrivateMethodVisitor extends BaseInspectionVisitor { @Override public void visitMethod(@NotNull PsiMethod method) { From 4415017c1fb5aa06818c97ce0efae84d8c338e97 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 8 Mar 2011 15:04:02 +0100 Subject: [PATCH 52/95] IDEA-35002 (Inspection "Integer multiplication or shift implicitly cast to long" shall have an option to ignore constant expression) --- .../siyeh/InspectionGadgetsBundle.properties | 1 + ...plicationImplicitCastToLongInspection.java | 43 +++++++++++++++---- .../siyeh/ig/psiutils/ExpressionUtils.java | 6 +-- ...tegerMultiplicationImplicitCastToLong.html | 3 ++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index cbc743a98150..0ebd1bf80841 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1474,6 +1474,7 @@ notify.without.corresponding.wait.display.name='notify()' without corresponding notify.without.corresponding.wait.problem.descriptor=Call to #ref without corresponding wait() #loc integer.multiplication.implicit.cast.to.long.display.name=Integer multiplication or shift implicitly cast to long integer.multiplication.implicit.cast.to.long.problem.descriptor=#ref: integer multiplication or shift implicitly cast to long #loc +integer.multiplication.implicit.cast.to.long.option=Ignore compile time constant expressions which do not overflow wait.or.await.without.timeout.display.name='wait()' or 'await()' without timeout wait.or.await.without.timeout.problem.descriptor=#ref without timeout #loc boolean.field.always.negated.display.name=Boolean field always negated on read diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/IntegerMultiplicationImplicitCastToLongInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/IntegerMultiplicationImplicitCastToLongInspection.java index 6e024b362cc6..9c1ba2ba268e 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/IntegerMultiplicationImplicitCastToLongInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/IntegerMultiplicationImplicitCastToLongInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2006-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,19 @@ */ package com.siyeh.ig.numeric; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.ConstantEvaluationOverflowException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.ExpectedTypeUtils; +import com.siyeh.ig.psiutils.ExpressionUtils; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import javax.swing.*; import java.util.HashSet; import java.util.Set; @@ -30,7 +35,8 @@ public class IntegerMultiplicationImplicitCastToLongInspection extends BaseInspection { /** @noinspection StaticCollection*/ - private static final Set s_typesToCheck = new HashSet(10); + @NonNls + private static final Set s_typesToCheck = new HashSet(4); static { s_typesToCheck.add("int"); s_typesToCheck.add("short"); @@ -38,23 +44,36 @@ public class IntegerMultiplicationImplicitCastToLongInspection extends s_typesToCheck.add("char"); } + @SuppressWarnings({"PublicField"}) + public boolean ignoreNonOverflowingCompileTimeConstants = true; + + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "integer.multiplication.implicit.cast.to.long.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "integer.multiplication.implicit.cast.to.long.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( + "integer.multiplication.implicit.cast.to.long.option"), + this, "ignoreNonOverflowingCompileTimeConstants"); + } + + @Override public BaseInspectionVisitor buildVisitor() { return new IntegerMultiplicationImplicitlyCastToLongVisitor(); } - private static class IntegerMultiplicationImplicitlyCastToLongVisitor + private class IntegerMultiplicationImplicitlyCastToLongVisitor extends BaseInspectionVisitor { @Override public void visitBinaryExpression( @@ -90,10 +109,19 @@ public class IntegerMultiplicationImplicitCastToLongInspection extends if (!contextType.equals(PsiType.LONG)) { return; } + try { + final Object result = + ExpressionUtils.computeConstantExpression(expression, + true); + if (ignoreNonOverflowingCompileTimeConstants && + result != null) { + return; + } + } catch (ConstantEvaluationOverflowException ignore) {} registerError(expression); } - private static PsiExpression getContainingExpression( + private PsiExpression getContainingExpression( PsiExpression expression) { final PsiElement parent = expression.getParent(); if (parent instanceof PsiBinaryExpression || @@ -105,15 +133,12 @@ public class IntegerMultiplicationImplicitCastToLongInspection extends return expression; } - private static boolean isNonLongInteger(PsiType type) { + private boolean isNonLongInteger(PsiType type) { if (type == null) { return false; } final String text = type.getCanonicalText(); - if (text == null) { - return false; - } - return s_typesToCheck.contains(text); + return text != null && s_typesToCheck.contains(text); } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionUtils.java index 1f02c89ce512..4663d4a85e31 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionUtils.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2010 Bas Leijdekkers + * Copyright 2005-2011 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ public class ExpressionUtils { public static Object computeConstantExpression( @Nullable PsiExpression expression, - boolean throwExceptionOnOverflow) { + boolean throwConstantEvaluationOverflowException) { if (expression == null) { return null; } @@ -43,7 +43,7 @@ public class ExpressionUtils { final PsiConstantEvaluationHelper constantEvaluationHelper = psiFacade.getConstantEvaluationHelper(); return constantEvaluationHelper.computeConstantExpression(expression, - throwExceptionOnOverflow); + throwConstantEvaluationOverflowException); } public static boolean isConstant(PsiField field) { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerMultiplicationImplicitCastToLong.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerMultiplicationImplicitCastToLong.html index 4bd07563ca71..b8f997c55025 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerMultiplicationImplicitCastToLong.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerMultiplicationImplicitCastToLong.html @@ -4,6 +4,9 @@ This inspection reports integer multiplication or left shift which are implicitly cast to long. Such multiplication is often an error, as overflow truncation may occur unexpectedly.

+Use the checkbox below to ignore compile time constant expressions which evaluate to +a non-overflowing value. +

Powered by InspectionGadgets \ No newline at end of file From def7a5d45f0958866322867190f223a51d1c939e Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 13:21:57 +0100 Subject: [PATCH 53/95] a graceful way out of EA-24989 (assertion that the lookup is already disposed) --- .../com/intellij/codeInsight/lookup/impl/LookupImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 69897372505b..dea175e6d233 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 @@ -1058,12 +1058,13 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { super.hide(); Disposer.dispose(this); + + assert myDisposed; } catch (Throwable e) { LOG.error(e); } - assert myDisposed; if (fireCanceled) { fireLookupCanceled(explicitly); @@ -1081,7 +1082,10 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { public void dispose() { assert ApplicationManager.getApplication().isDispatchThread(); assert myHidden; - assert !myDisposed : disposeTrace; + if (myDisposed) { + LOG.error(disposeTrace); + return; + } Disposer.dispose(myProcessIcon); Disposer.dispose(myHintAlarm); From 7409e6618595254a435333397ce4b7bd0fa33565 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 13:26:32 +0100 Subject: [PATCH 54/95] one more graceful way out of EA-24989 (assertion that the lookup is already disposed) --- .../codeInsight/lookup/impl/LookupImpl.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 dea175e6d233..33b214f78711 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 @@ -1051,20 +1051,22 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { } private void doHide(final boolean fireCanceled, final boolean explicitly) { - assert !myDisposed : disposeTrace; - myHidden = true; + if (myDisposed) { + LOG.error(disposeTrace); + } else { + myHidden = true; - try { - super.hide(); + try { + super.hide(); - Disposer.dispose(this); + Disposer.dispose(this); - assert myDisposed; + assert myDisposed; + } + catch (Throwable e) { + LOG.error(e); + } } - catch (Throwable e) { - LOG.error(e); - } - if (fireCanceled) { fireLookupCanceled(explicitly); From 17b88c65c0b7f4b5076f30d74b992826ddb030a6 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 13:45:13 +0100 Subject: [PATCH 55/95] phase-based autopopup invocation --- .../completion/CompletionPhase.java | 94 +++++++++- .../CompletionAutoPopupHandler.java | 173 +----------------- 2 files changed, 98 insertions(+), 169 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java index 4f10c015cddf..62dfb6dc8815 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java @@ -16,20 +16,25 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; +import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.CaretModel; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.*; +import com.intellij.openapi.fileEditor.FileEditorManagerAdapter; +import com.intellij.openapi.fileEditor.FileEditorManagerEvent; +import com.intellij.openapi.fileEditor.FileEditorManagerListener; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.ui.HintListener; import com.intellij.ui.LightweightHint; +import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.EventObject; /** @@ -204,8 +209,89 @@ public abstract class CompletionPhase implements Disposable { } } public static class EmptyAutoPopup extends CompletionPhase { + private final Editor editor; + private final Project project; + private final EditorMouseAdapter mouseListener; + private final CaretListener caretListener; + private final DocumentAdapter documentListener; + private final PropertyChangeListener lookupListener; + private boolean changeGuard = false; + public EmptyAutoPopup(CompletionProgressIndicator indicator) { super(indicator); + this.editor = indicator.getEditor(); + this.project = indicator.getProject(); + MessageBusConnection connection = project.getMessageBus().connect(this); + connection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { + @Override + public void selectionChanged(FileEditorManagerEvent event) { + stopAutoPopup(); + } + }); + + mouseListener = new EditorMouseAdapter() { + @Override + public void mouseClicked(EditorMouseEvent e) { + stopAutoPopup(); + } + }; + + caretListener = new CaretListener() { + @Override + public void caretPositionChanged(CaretEvent e) { + if (!changeGuard) { + stopAutoPopup(); + } + } + }; + editor.getSelectionModel().addSelectionListener(new SelectionListener() { + @Override + public void selectionChanged(SelectionEvent e) { + stopAutoPopup(); + } + }); + documentListener = new DocumentAdapter() { + @Override + public void documentChanged(DocumentEvent e) { + if (!changeGuard) { + stopAutoPopup(); + } + } + }; + lookupListener = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + stopAutoPopup(); + } + }; + + editor.addEditorMouseListener(mouseListener); + editor.getCaretModel().addCaretListener(caretListener); + editor.getDocument().addDocumentListener(documentListener); + LookupManager.getInstance(project).addPropertyChangeListener(lookupListener); + } + + @Override + public void dispose() { + editor.removeEditorMouseListener(mouseListener); + editor.getCaretModel().removeCaretListener(caretListener); + editor.getDocument().removeDocumentListener(documentListener); + LookupManager.getInstance(project).removePropertyChangeListener(lookupListener); + } + + public void handleTyping(char c) { + changeGuard = true; + try { + EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, String.valueOf(c), true); + } + finally { + changeGuard = false; + } + + } + + private static void stopAutoPopup() { + CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); } @Override 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 89757366fe0a..7fe8aea71fea 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -19,38 +19,22 @@ import com.intellij.codeInsight.AutoPopupController; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; import com.intellij.codeInsight.completion.CompletionPhase; -import com.intellij.codeInsight.completion.CompletionProgressIndicator; import com.intellij.codeInsight.completion.CompletionType; import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; -import com.intellij.codeInsight.lookup.Lookup; -import com.intellij.codeInsight.lookup.LookupAdapter; -import com.intellij.codeInsight.lookup.LookupEvent; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorModificationUtil; -import com.intellij.openapi.editor.event.*; import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.FileEditorManagerAdapter; -import com.intellij.openapi.fileEditor.FileEditorManagerEvent; -import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Key; import com.intellij.psi.PsiFile; -import com.intellij.util.messages.MessageBusConnection; -import org.jetbrains.annotations.Nullable; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; /** * @author peter */ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { - private static final Key STATE_KEY = Key.create("AutopopupSTATE_KEY"); public static volatile boolean ourTestingAutopopup = false; @Override @@ -59,15 +43,9 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { Editor editor, PsiFile file, FileType fileType) { - final AutoPopupState state = getAutoPopupState(editor); - if (state != null && LookupManager.getActiveLookup(editor) == null) { - state.changeGuard = true; - try { - EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(editor, String.valueOf(c), true); - } - finally { - state.changeGuard = false; - } + CompletionPhase phase = CompletionServiceImpl.getCompletionPhase(); + if (phase instanceof CompletionPhase.EmptyAutoPopup) { + ((CompletionPhase.EmptyAutoPopup)phase).handleTyping(c); return Result.STOP; } @@ -78,12 +56,14 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { public Result checkAutoPopup(char charTyped, final Project project, final Editor editor, final PsiFile file) { if (!CodeInsightSettings.getInstance().AUTO_POPUP_COMPLETION_LOOKUP) return Result.CONTINUE; - if (!Character.isLetter(charTyped) && charTyped != '_') { - finishAutopopupCompletion(editor, false); + if (LookupManager.getActiveLookup(editor) != null) { return Result.CONTINUE; } - if (getAutoPopupState(editor) != null || LookupManager.getActiveLookup(editor) != null) { + if (!Character.isLetter(charTyped) && charTyped != '_') { + if (CompletionServiceImpl.isPhase(CompletionPhase.EmptyAutoPopup.class)) { + CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); + } return Result.CONTINUE; } @@ -94,17 +74,6 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { return Result.CONTINUE; } - - /* - if (!CompletionProgressIndicator.showHintAutopopup()) { - final CharSequence text = editor.getDocument().getCharsSequence(); - final int offset = editor.getSelectionModel().hasSelection() ? editor.getSelectionModel().getSelectionEnd() : editor.getCaretModel().getOffset(); - if (text.length() > offset && Character.isUnicodeIdentifierPart(text.charAt(offset))) { - return Result.CONTINUE; - } - } - */ - final boolean isMainEditor = FileEditorManager.getInstance(project).getSelectedTextEditor() == editor; final CompletionPhase.AutoPopupAlarm phase = new CompletionPhase.AutoPopupAlarm(); @@ -129,132 +98,6 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { public static void invokeAutoPopupCompletion(Project project, final Editor editor) { new CodeCompletionHandlerBase(CompletionType.BASIC, false, true).invokeCompletion(project, editor, 0, false); - - final AutoPopupState state = new AutoPopupState(project, editor); - editor.putUserData(STATE_KEY, state); - - final Lookup lookup = LookupManager.getActiveLookup(editor); - if (lookup != null) { - lookup.addLookupListener(new LookupAdapter() { - @Override - public void itemSelected(LookupEvent event) { - final AutoPopupState state = getAutoPopupState(editor); - if (state != null) { - state.stopAutoPopup(); - } - } - - @Override - public void lookupCanceled(LookupEvent event) { - final AutoPopupState state = getAutoPopupState(editor); - if (event.isCanceledExplicitly() && state != null) { - state.stopAutoPopup(); - } - } - }); - } } - @Nullable - private static AutoPopupState getAutoPopupState(Editor editor) { - return editor.getUserData(STATE_KEY); - } - - private static void finishAutopopupCompletion(Editor editor, boolean neglectLookup) { - final AutoPopupState state = getAutoPopupState(editor); - if (state == null || state.changeGuard) { - return; - } - - if (!neglectLookup && LookupManager.getActiveLookup(editor) != null) { //the events during visible lookup period are handled separately - return; - } - - final CompletionProgressIndicator currentCompletion = CompletionServiceImpl.getCompletionService().getCurrentCompletion(); - if (CompletionServiceImpl.isPhase(CompletionPhase.AutoPopupAlarm.class, CompletionPhase.EmptyAutoPopup.class, CompletionPhase.PossiblyDisturbingAutoPopup.class)) { - CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); - assert currentCompletion == null; - } else { - if (currentCompletion != null) { - currentCompletion.closeAndFinish(true); - } - CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass()); - } - - state.stopAutoPopup(); - } - - - private static class AutoPopupState { - final Editor editor; - final Project project; - final MessageBusConnection connection; - final EditorMouseAdapter mouseListener; - final CaretListener caretListener; - final DocumentAdapter documentListener; - final PropertyChangeListener lookupListener; - boolean changeGuard = false; - - private AutoPopupState(final Project project, final Editor editor) { - this.editor = editor; - this.project = project; - connection = project.getMessageBus().connect(); - connection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() { - @Override - public void selectionChanged(FileEditorManagerEvent event) { - finishAutopopupCompletion(editor, false); - } - }); - - mouseListener = new EditorMouseAdapter() { - @Override - public void mouseClicked(EditorMouseEvent e) { - finishAutopopupCompletion(editor, false); - } - }; - - caretListener = new CaretListener() { - @Override - public void caretPositionChanged(CaretEvent e) { - finishAutopopupCompletion(editor, false); - } - }; - editor.getSelectionModel().addSelectionListener(new SelectionListener() { - @Override - public void selectionChanged(SelectionEvent e) { - finishAutopopupCompletion(editor, false); - } - }); - documentListener = new DocumentAdapter() { - @Override - public void documentChanged(DocumentEvent e) { - finishAutopopupCompletion(editor, false); - } - }; - lookupListener = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getNewValue() != null) { - finishAutopopupCompletion(editor, true); - } - } - }; - - editor.addEditorMouseListener(mouseListener); - editor.getCaretModel().addCaretListener(caretListener); - editor.getDocument().addDocumentListener(documentListener); - LookupManager.getInstance(project).addPropertyChangeListener(lookupListener); - } - - void stopAutoPopup() { - connection.disconnect(); - editor.removeEditorMouseListener(mouseListener); - editor.getCaretModel().removeCaretListener(caretListener); - editor.getDocument().removeDocumentListener(documentListener); - LookupManager.getInstance(project).removePropertyChangeListener(lookupListener); - - editor.putUserData(STATE_KEY, null); - } - - } } From 8a80c2db08834e5043526e0e9d5e450f1695f091 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 14:14:35 +0100 Subject: [PATCH 56/95] remove smartUpdateShift --- .../ide/highlighter/custom/AbstractCustomLexer.java | 5 ----- .../ide/highlighter/custom/tokens/IdentifierParser.java | 4 ---- .../ide/highlighter/custom/tokens/KeywordParser.java | 6 ------ .../ide/highlighter/custom/tokens/NumberParser.java | 4 ---- .../ide/highlighter/custom/tokens/PrefixedTokenParser.java | 4 ---- .../ide/highlighter/custom/tokens/PunctuationParser.java | 5 ----- .../intellij/ide/highlighter/custom/tokens/TokenParser.java | 2 -- .../ide/highlighter/custom/tokens/WhitespaceParser.java | 4 ---- 8 files changed, 34 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java index b0607907da73..5ec0ecbe4d4d 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/AbstractCustomLexer.java @@ -38,11 +38,6 @@ public class AbstractCustomLexer extends LexerBase { public AbstractCustomLexer(List tokenParsers) { myTokenParsers = tokenParsers.toArray(new TokenParser[tokenParsers.size()]); - - int smartUpdateShift = 0; - for (TokenParser tokenParser : myTokenParsers) { - smartUpdateShift = Math.max(smartUpdateShift, tokenParser.getSmartUpdateShift()); - } } public void start(CharSequence buffer, int startOffset, int endOffset, int initialState) { diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java index 4d95522f8a23..697c8f046f1f 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/IdentifierParser.java @@ -41,8 +41,4 @@ public class IdentifierParser extends TokenParser { private boolean isIdentifierPart(final char c) { return Character.isJavaIdentifierPart(c) || c == '-'; } - - public int getSmartUpdateShift() { - return 0; - } } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java index 42ff77c5cf82..59290c53214a 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java @@ -31,7 +31,6 @@ import java.util.Set; public class KeywordParser extends TokenParser { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.highlighter.custom.tokens.KeywordParser"); private final HashSet[] myKeywordSets = new HashSet[CustomHighlighterTokenType.KEYWORD_TYPE_COUNT]; - private final int mySmartUpdateShift; private final boolean myIgnoreCase; private final BitSet myFirstCharacters = new BitSet(); private final BitSet myCharacters = new BitSet(); @@ -66,7 +65,6 @@ public class KeywordParser extends TokenParser { } } } - mySmartUpdateShift = maxLength; } private HashSet getKeywordSet(Set keywordSet) { @@ -116,8 +114,4 @@ public class KeywordParser extends TokenParser { } return null; } - - public int getSmartUpdateShift() { - return mySmartUpdateShift; - } } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java index 9441bdd8f2f3..90cbd8c1747a 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/NumberParser.java @@ -69,10 +69,6 @@ public final class NumberParser extends TokenParser { return true; } - public int getSmartUpdateShift() { - return 2; // if previous character was a dec point - } - static boolean isDigit(char c) { return c >= '0' && c <= '9'; } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java index 67fc1bc59899..2bdc1972a3c2 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PrefixedTokenParser.java @@ -42,9 +42,5 @@ public abstract class PrefixedTokenParser extends TokenParser { return true; } - public int getSmartUpdateShift() { - return myPrefix.length; - } - protected abstract int getTokenEnd(int position); } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java index 1f54ff2acfb3..eaf94955e49b 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/PunctuationParser.java @@ -31,9 +31,4 @@ public class PunctuationParser extends TokenParser { } return false; } - - @Override - public int getSmartUpdateShift() { - return 0; - } } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java index 29d67158953b..e28ddd48f1ad 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/TokenParser.java @@ -37,6 +37,4 @@ public abstract class TokenParser { } public abstract boolean hasToken(int position); - - public abstract int getSmartUpdateShift(); } diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java index acd250f869fe..2da63cfe42a4 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/WhitespaceParser.java @@ -31,8 +31,4 @@ public class WhitespaceParser extends TokenParser { myTokenInfo.updateData(start, position, CustomHighlighterTokenType.WHITESPACE); return true; } - - public int getSmartUpdateShift() { - return 0; - } } From 162a8094a4ca549111a348e09533007cc1faa2ef Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 14:19:46 +0100 Subject: [PATCH 57/95] generify --- .../custom/CustomFileTypeLexer.java | 5 +-- .../custom/tokens/KeywordParser.java | 45 +++++++++---------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java index 23d7d2fee9e0..79731c9373cf 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/CustomFileTypeLexer.java @@ -20,8 +20,8 @@ import com.intellij.ide.highlighter.custom.tokens.*; import com.intellij.psi.CustomHighlighterTokenType; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Set; /** * @author dsl @@ -41,8 +41,7 @@ public final class CustomFileTypeLexer extends AbstractCustomLexer { MultilineCommentParser.create(table.getStartComment(), table.getEndComment()); final NumberParser numberParser = new NumberParser(table.getNumPostfixChars(), table.isIgnoreCase()); final HexNumberParser hexNumberParser = HexNumberParser.create(table.getHexPrefix()); - final KeywordParser keywordParser = new KeywordParser( - new Set[]{table.getKeywords1(), table.getKeywords2(), table.getKeywords3(), table.getKeywords4()}, + final KeywordParser keywordParser = new KeywordParser(Arrays.asList(table.getKeywords1(), table.getKeywords2(), table.getKeywords3(), table.getKeywords4()), table.isIgnoreCase()); final IdentifierParser identifierParser = new IdentifierParser(); diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java index 59290c53214a..d3c20bdf8b79 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java @@ -20,37 +20,33 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.CustomHighlighterTokenType; import com.intellij.psi.tree.IElementType; -import java.util.BitSet; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; +import java.util.*; /** * @author dsl */ public class KeywordParser extends TokenParser { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.highlighter.custom.tokens.KeywordParser"); - private final HashSet[] myKeywordSets = new HashSet[CustomHighlighterTokenType.KEYWORD_TYPE_COUNT]; + private final List> myKeywordSets = new ArrayList>(); private final boolean myIgnoreCase; private final BitSet myFirstCharacters = new BitSet(); private final BitSet myCharacters = new BitSet(); - public KeywordParser(Set[] keywordSets, boolean ignoreCase) { - LOG.assertTrue(keywordSets.length == myKeywordSets.length); + public KeywordParser(List> keywordSets, boolean ignoreCase) { + LOG.assertTrue(keywordSets.size() == CustomHighlighterTokenType.KEYWORD_TYPE_COUNT); myIgnoreCase = ignoreCase; int maxLength = 0; - for (int i = 0; i < keywordSets.length; i++) { - Set keywordSet = keywordSets[i]; - myKeywordSets[i] = getKeywordSet(keywordSet); - for (Iterator iterator = keywordSet.iterator(); iterator.hasNext();) { - String s = (String) iterator.next(); + for (Set keywordSet : keywordSets) { + myKeywordSets.add(getKeywordSet(keywordSet)); + for (String s : keywordSet) { maxLength = Math.max(maxLength, s.length()); final char firstChar = s.charAt(0); if (ignoreCase) { myFirstCharacters.set(Character.toUpperCase(firstChar), Character.toUpperCase(firstChar) + 1); myFirstCharacters.set(Character.toLowerCase(firstChar), Character.toLowerCase(firstChar) + 1); - } else { + } + else { myFirstCharacters.set(firstChar, firstChar + 1); } for (int j = 0; j < s.length(); j++) { @@ -67,17 +63,16 @@ public class KeywordParser extends TokenParser { } } - private HashSet getKeywordSet(Set keywordSet) { + private Set getKeywordSet(Set keywordSet) { if (!myIgnoreCase) { - return new HashSet(keywordSet); - } else { - final HashSet result = new HashSet(); - for (Iterator iterator = keywordSet.iterator(); iterator.hasNext();) { - String s = (String) iterator.next(); - result.add(s.toUpperCase()); - } - return result; + return new HashSet(keywordSet); } + + final Set result = new HashSet(); + for (String s : keywordSet) { + result.add(s.toUpperCase()); + } + return result; } @@ -94,8 +89,8 @@ public class KeywordParser extends TokenParser { final String keyword = myBuffer.subSequence(start, position).toString(); String testKeyword = myIgnoreCase ? keyword.toUpperCase() : keyword; - for (int i = 0; i < myKeywordSets.length; i++) { - HashSet keywordSet = myKeywordSets[i]; + for (int i = 0; i < myKeywordSets.size(); i++) { + Set keywordSet = myKeywordSets.get(i); if (keywordSet.contains(testKeyword)) { myTokenInfo.updateData(start, position, getToken(i)); return true; @@ -112,6 +107,6 @@ public class KeywordParser extends TokenParser { case 2: return CustomHighlighterTokenType.KEYWORD_3; case 3: return CustomHighlighterTokenType.KEYWORD_4; } - return null; + throw new AssertionError(keywordSetIndex); } } From 78f1753db4be5c75c32e717d6ac0aec2703c19e6 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 15:13:17 +0100 Subject: [PATCH 58/95] don't run several ad animators for one lookup --- .../codeInsight/lookup/impl/Advertiser.java | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java index ca1ad95dd20f..b25adc97b8e3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/Advertiser.java @@ -78,6 +78,26 @@ public class Advertiser implements Disposable { public Advertiser(Disposable parentDisposable) { Disposer.register(parentDisposable, this); + int interCycleGap = 4000; + Animator animator = new Animator("completion ad", ourScrollingResolution, 800, true, interCycleGap, -1) { + @Override + public void paintNow(float frame, float totalFrames, float cycle) { + int adCount = getTexts().size(); + if (adCount <= 1) { + myCurrentItem = myScrollingOffset = 0; + myComponent.repaint(); + return; + } + + myScrollingOffset = ((int)frame + 1) % ourScrollingResolution; + if (myScrollingOffset == 0) { + myCurrentItem = (myCurrentItem + 1) % adCount; + } + myComponent.paintImmediately(0, 0, myComponent.getWidth(), myComponent.getHeight()); + } + }; + animator.resume(); + Disposer.register(this, animator); } private synchronized List getTexts() { @@ -86,8 +106,6 @@ public class Advertiser implements Disposable { public synchronized void clearAdvertisements() { myTexts.clear(); - myCurrentItem = 0; - myScrollingOffset = 0; } private static Font adFont() { @@ -98,22 +116,9 @@ public class Advertiser implements Disposable { public synchronized void addAdvertisement(@NotNull String text) { myTexts.add(text); if (myTexts.size() == 2) { - if (!myComponent.isShowing()) { + if (!myComponent.isShowing()) { myCurrentItem = -1; } - int interCycleGap = 4000; - Animator animator = new Animator("completion ad", ourScrollingResolution, 800, true, interCycleGap, -1) { - @Override - public void paintNow(float frame, float totalFrames, float cycle) { - myScrollingOffset = (int)frame; - if (myScrollingOffset == 0) { - myCurrentItem = (myCurrentItem + 1) % getTexts().size(); - } - myComponent.paintImmediately(0, 0, myComponent.getWidth(), myComponent.getHeight()); - } - }; - animator.resume(); - Disposer.register(this, animator); } } From 98a17031769c33fc371852de20b251e73a1b0f07 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 8 Mar 2011 15:36:00 +0100 Subject: [PATCH 59/95] IDEA-65109 (Public method is not exposed via an interface should have option to only work if the class implements an interface) --- .../siyeh/InspectionGadgetsBundle.properties | 1 + ...MethodNotExposedInInterfaceInspection.java | 34 +++++++++++++++++-- .../PublicMethodNotExposedInInterface.html | 3 ++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 0ebd1bf80841..6b2ec4f92f53 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -34,6 +34,7 @@ concrete.class.method.parameter.display.name=Method parameter of concrete class concrete.class.method.parameter.problem.descriptor=Parameter ''{0}'' of concrete class #ref #loc public.method.not.in.interface.display.name='public' method not exposed in interface public.method.not.in.interface.problem.descriptor='public' method #ref() is not exposed via an interface #loc +public.method.not.in.interface.option=Ignore if the containing class does not implement a non-library interface static.variable.of.concrete.class.display.name=Static field of concrete class static.variable.of.concrete.class.problem.descriptor=Static field ''{0}'' of concrete class #ref #loc incompatible.mask.operation.display.name=Incompatible bitwise mask operation diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java index 7a71eb61609a..8efcd56a7861 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.siyeh.ig.abstraction; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; @@ -22,12 +23,18 @@ import com.intellij.psi.PsiModifier; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.LibraryUtil; import com.siyeh.ig.psiutils.TestUtils; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + public class PublicMethodNotExposedInInterfaceInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) + public boolean onlyWarnIfContainingClassImplementsAnInterface = false; + @Override @NotNull public String getDisplayName() { @@ -42,12 +49,19 @@ public class PublicMethodNotExposedInInterfaceInspection "public.method.not.in.interface.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( + "public.method.not.in.interface.option"), + this, "onlyWarnIfContainingClassImplementsAnInterface"); + } + @Override public BaseInspectionVisitor buildVisitor() { return new PublicMethodNotExposedInInterface(); } - private static class PublicMethodNotExposedInInterface + private class PublicMethodNotExposedInInterface extends BaseInspectionVisitor { @Override public void visitMethod(@NotNull PsiMethod method) { @@ -75,6 +89,20 @@ public class PublicMethodNotExposedInInterfaceInspection if (!containingClass.hasModifierProperty(PsiModifier.PUBLIC)) { return; } + if (onlyWarnIfContainingClassImplementsAnInterface) { + final PsiClass[] superClasses = containingClass.getSupers(); + boolean implementsInterface = false; + for (PsiClass superClass : superClasses) { + if (superClass.isInterface() && + !LibraryUtil.classIsInLibrary(superClass)) { + implementsInterface = true; + break; + } + } + if (!implementsInterface) { + return; + } + } if (exposedInInterface(method)) { return; } @@ -84,7 +112,7 @@ public class PublicMethodNotExposedInInterfaceInspection registerMethodError(method); } - private static boolean exposedInInterface(PsiMethod method) { + private boolean exposedInInterface(PsiMethod method) { final PsiMethod[] superMethods = method.findSuperMethods(); for(final PsiMethod superMethod : superMethods) { final PsiClass superClass = superMethod.getContainingClass(); diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html index 1e7218036af1..84311308b45d 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html @@ -4,6 +4,9 @@ This inspection reports public methods in classes which are not exposed as in interface. Exposing all public methods via interface is important for maintaining loose coupling, and may be necessary for certain component-based programming styles.

+Use the checkbox below to ignore methods of which the containing class does not +implement a non-library interface. +

Powered by InspectionGadgets \ No newline at end of file From 8c9a400531e362f26430832d00575914fc7f2785 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 8 Mar 2011 15:48:46 +0100 Subject: [PATCH 60/95] IDEA-66327 (please inaccurate developers - trim whitespaces from new class names) --- .../actions/CreateFileFromTemplateDialog.java | 5 +- .../CreateTemplateInPackageAction.java | 46 +++++++++---------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java index 287cd7a1b320..52a24daa378a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java @@ -58,7 +58,10 @@ public class CreateFileFromTemplateDialog extends DialogWrapper { } private String getEnteredName() { - return getNameField().getText(); + final JTextField nameField = getNameField(); + final String text = nameField.getText().trim(); + nameField.setText(text); + return text; } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateTemplateInPackageAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateTemplateInPackageAction.java index ab3495b150f2..3a70bde9807a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateTemplateInPackageAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateTemplateInPackageAction.java @@ -36,11 +36,11 @@ import javax.swing.*; * @author peter */ public abstract class CreateTemplateInPackageAction extends CreateFromTemplateAction { - private final boolean myinSourceOnly; + private final boolean myInSourceOnly; protected CreateTemplateInPackageAction(String text, String description, Icon icon, boolean inSourceOnly) { super(text, description, icon); - myinSourceOnly = inSourceOnly; + myInSourceOnly = inSourceOnly; } @Override @@ -65,7 +65,7 @@ public abstract class CreateTemplateInPackageAction extend return false; } - if (!myinSourceOnly) { + if (!myInSourceOnly) { return true; } @@ -82,9 +82,9 @@ public abstract class CreateTemplateInPackageAction extend protected abstract boolean checkPackageExists(PsiDirectory directory); @Nullable - private T checkOrCreate(String newName, PsiDirectory directory, String templateName, boolean check) throws IncorrectOperationException { - PsiDirectory dir = directory; - String className = newName; + private T checkOrCreate(String newName, PsiDirectory directory, String templateName, boolean check) throws IncorrectOperationException { + PsiDirectory dir = directory; + String className = newName; final String extension = StringUtil.getShortName(templateName); if (StringUtil.isNotEmpty(extension)) { @@ -92,33 +92,33 @@ public abstract class CreateTemplateInPackageAction extend } if (className.contains(".")) { - String[] names = className.split("\\."); + String[] names = className.split("\\."); - for (int i = 0; i < names.length - 1; i++) { - String name = names[i]; - PsiDirectory subDir = dir.findSubdirectory(name); + for (int i = 0; i < names.length - 1; i++) { + String name = names[i]; + PsiDirectory subDir = dir.findSubdirectory(name); - if (subDir == null) { - if (check) { - dir.checkCreateSubdirectory(name); - return null; - } + if (subDir == null) { + if (check) { + dir.checkCreateSubdirectory(name); + return null; + } - subDir = dir.createSubdirectory(name); - } + subDir = dir.createSubdirectory(name); + } - dir = subDir; - } + dir = subDir; + } - className = names[names.length - 1]; - } + className = names[names.length - 1]; + } if (check) { doCheckCreate(dir, className, templateName); return null; } - return doCreate(dir, className, templateName); - } + return doCreate(dir, className, templateName); + } protected abstract void doCheckCreate(PsiDirectory dir, String className, String templateName) throws IncorrectOperationException; From ccdc3a5bcb239846a053abbe39d71564fa4047b1 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 8 Mar 2011 16:22:42 +0100 Subject: [PATCH 61/95] diamond: replace wildcards with corresponding bound when inference (IDEA-66124) --- .../advHighlighting7/DiamondMisc.java | 21 +++++++++++++++++++ .../src/com/intellij/psi/PsiDiamondType.java | 14 ++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java index cd7fc761fea1..b7398235bd51 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/DiamondMisc.java @@ -74,3 +74,24 @@ class NonParameterized { new NonParameterized<>(); } } + + +interface I { + T m(); +} + +class FI1 { + I i1 = new I<>() { + @Override + public String m() { + return null; + } + }; + + I i2 = new I<>() { + @Override + public Object m() { + return null; + } + }; +} \ No newline at end of file diff --git a/java/openapi/src/com/intellij/psi/PsiDiamondType.java b/java/openapi/src/com/intellij/psi/PsiDiamondType.java index 35f49ac799d2..351e44998530 100644 --- a/java/openapi/src/com/intellij/psi/PsiDiamondType.java +++ b/java/openapi/src/com/intellij/psi/PsiDiamondType.java @@ -119,7 +119,7 @@ public class PsiDiamondType extends PsiType { final PsiTypeParameter[] classParameters = psiClass.getTypeParameters(); final PsiJavaCodeReferenceElement classOrAnonymousClassReference = newExpression.getClassOrAnonymousClassReference(); LOG.assertTrue(classOrAnonymousClassReference != null); - final DiamondInferenceResult result = new DiamondInferenceResult(classOrAnonymousClassReference.getReferenceName() + "<>"); + final DiamondInferenceResult result = new DiamondInferenceResult(classOrAnonymousClassReference.getReferenceName() + "<>", newExpression.getProject()); for (PsiTypeParameter parameter : parameters) { for (PsiTypeParameter classParameter : classParameters) { if (Comparing.strEqual(classParameter.getName(), parameter.getName())) { @@ -245,12 +245,14 @@ public class PsiDiamondType extends PsiType { private String myErrorMessage; private String myNewExpressionPresentableText; + private Project myProject; public DiamondInferenceResult() { } - public DiamondInferenceResult(String expressionPresentableText) { + public DiamondInferenceResult(String expressionPresentableText, Project project) { myNewExpressionPresentableText = expressionPresentableText; + myProject = project; } public PsiType[] getTypes() { @@ -272,7 +274,13 @@ public class PsiDiamondType extends PsiType { myErrorMessage = "Cannot infer type arguments for " + myNewExpressionPresentableText + " because type " + psiType.getPresentableText() + " inferred is not allowed in current context"; } else { - myInferredTypes.add(psiType); + if (psiType instanceof PsiWildcardType) { + final PsiType bound = ((PsiWildcardType)psiType).getBound(); + myInferredTypes.add(bound != null ? bound : PsiType.getJavaLangObject(PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject))); + } + else { + myInferredTypes.add(psiType); + } } } From 675a660b14df6148d6c0a4a1329c34631a325fad Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 8 Mar 2011 16:46:25 +0100 Subject: [PATCH 62/95] replace explicit with diamond: do not leave incorrect psi (IDEA-66114 ) --- .../ExplicitTypeCanBeDiamondInspection.java | 11 +++++++++-- .../quickFix/Simplify2DiamondInspectionsTest.java | 11 ----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java index 6cf445dd6a69..9acf65d1b2f7 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java @@ -18,6 +18,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.intention.HighPriorityAction; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -109,6 +110,7 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT } private static class ReplaceWithDiamondFix implements LocalQuickFix, HighPriorityAction { + public static final Logger LOG = Logger.getInstance("#" + ReplaceWithDiamondFix.class.getName()); @NotNull @Override public String getName() { @@ -126,8 +128,13 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT final PsiElement psiElement = descriptor.getPsiElement(); if (psiElement instanceof PsiReferenceParameterList) { if (!CodeInsightUtilBase.prepareFileForWrite(psiElement.getContainingFile())) return; - final PsiTypeElement[] parameterElements = ((PsiReferenceParameterList)psiElement).getTypeParameterElements(); - psiElement.deleteChildRange(parameterElements[0], parameterElements[parameterElements.length - 1]); + final PsiNewExpression expression = + (PsiNewExpression)JavaPsiFacade.getElementFactory(project).createExpressionFromText("new a<>()", psiElement); + final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); + LOG.assertTrue(classReference != null); + final PsiReferenceParameterList parameterList = classReference.getParameterList(); + LOG.assertTrue(parameterList != null); + psiElement.replace(parameterList); } } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Simplify2DiamondInspectionsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Simplify2DiamondInspectionsTest.java index 8667fdfcd617..76136b5fb8ef 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Simplify2DiamondInspectionsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Simplify2DiamondInspectionsTest.java @@ -17,17 +17,6 @@ package com.intellij.codeInsight.daemon.quickFix; import com.intellij.codeInspection.ExplicitTypeCanBeDiamondInspection; import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.accessStaticViaInstance.AccessStaticViaInstance; -import com.intellij.codeInspection.deprecation.DeprecationInspection; -import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; -import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection; -import com.intellij.codeInspection.sillyAssignment.SillyAssignmentInspection; -import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; -import com.intellij.codeInspection.unneededThrows.RedundantThrowsDeclaration; -import com.intellij.codeInspection.unusedParameters.UnusedParametersInspection; -import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; //todo test3 should be checked if it compiles - as now javac infers Object instead of String?! From f0db1be49c8ee27a2f404c9303c550f6b3c27438 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 8 Mar 2011 17:43:12 +0100 Subject: [PATCH 63/95] diamond: replace wildcards with corresponding bound when inference (IDEA-66124) --- .../ExplicitTypeCanBeDiamondInspection.java | 12 +++++---- .../src/com/intellij/psi/PsiDiamondType.java | 25 +++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java index 9acf65d1b2f7..45f39ce69bb8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java @@ -27,6 +27,8 @@ import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * User: anna * Date: 1/28/11 @@ -77,13 +79,13 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT if (typeElements.length == 1 && typeElements[0].getType() instanceof PsiDiamondType) return; final PsiDiamondType.DiamondInferenceResult inferenceResult = PsiDiamondType.resolveInferredTypes(expression); if (inferenceResult.getErrorMessage() == null) { - final PsiType[] types = inferenceResult.getTypes(); + final List types = inferenceResult.getInferredTypes(); final PsiType[] typeArguments = parameterList.getTypeArguments(); - if (types.length == typeArguments.length) { + if (types.size() == typeArguments.length) { for (int i = 0, typeArgumentsLength = typeArguments.length; i < typeArgumentsLength; i++) { PsiType typeArgument = typeArguments[i]; - if (types[i] instanceof PsiWildcardType) { - final PsiWildcardType wildcardType = (PsiWildcardType)types[i]; + if (types.get(i) instanceof PsiWildcardType) { + final PsiWildcardType wildcardType = (PsiWildcardType)types.get(i); final PsiType bound = wildcardType.getBound(); if (bound != null) { if (wildcardType.isExtends()) { @@ -93,7 +95,7 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT } } } - if (!typeArgument.equals(types[i])) { + if (!typeArgument.equals(types.get(i))) { return; } } diff --git a/java/openapi/src/com/intellij/psi/PsiDiamondType.java b/java/openapi/src/com/intellij/psi/PsiDiamondType.java index 351e44998530..0abeb3a0134f 100644 --- a/java/openapi/src/com/intellij/psi/PsiDiamondType.java +++ b/java/openapi/src/com/intellij/psi/PsiDiamondType.java @@ -259,7 +259,22 @@ public class PsiDiamondType extends PsiType { if (myErrorMessage != null) { return NULL_TYPES; } - return myInferredTypes.toArray(new PsiType[myInferredTypes.size()]); + final PsiType[] result = new PsiType[myInferredTypes.size()]; + for (int i = 0, myInferredTypesSize = myInferredTypes.size(); i < myInferredTypesSize; i++) { + PsiType inferredType = myInferredTypes.get(i); + if (inferredType instanceof PsiWildcardType) { + final PsiType bound = ((PsiWildcardType)inferredType).getBound(); + result[i] = bound != null ? bound : PsiType.getJavaLangObject(PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject)); + } + else { + result[i] = inferredType; + } + } + return result; + } + + public List getInferredTypes() { + return myInferredTypes; } public String getErrorMessage() { @@ -274,13 +289,7 @@ public class PsiDiamondType extends PsiType { myErrorMessage = "Cannot infer type arguments for " + myNewExpressionPresentableText + " because type " + psiType.getPresentableText() + " inferred is not allowed in current context"; } else { - if (psiType instanceof PsiWildcardType) { - final PsiType bound = ((PsiWildcardType)psiType).getBound(); - myInferredTypes.add(bound != null ? bound : PsiType.getJavaLangObject(PsiManager.getInstance(myProject), GlobalSearchScope.allScope(myProject))); - } - else { - myInferredTypes.add(psiType); - } + myInferredTypes.add(psiType); } } From f15136acf25fc10b71bc8a808c7122e850962ea1 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Tue, 8 Mar 2011 17:55:48 +0100 Subject: [PATCH 64/95] init/shutdown SerializationManager for stubs before/after FileBasedIndex --- .../psi/stubs/SerializationManagerImpl.java | 20 ++++++++++++++++++- .../intellij/psi/stubs/StubUpdatingIndex.java | 7 +------ .../util/indexing/FileBasedIndex.java | 3 ++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/platform/lang-api/src/com/intellij/psi/stubs/SerializationManagerImpl.java b/platform/lang-api/src/com/intellij/psi/stubs/SerializationManagerImpl.java index eb627af84818..528c752ebfe6 100644 --- a/platform/lang-api/src/com/intellij/psi/stubs/SerializationManagerImpl.java +++ b/platform/lang-api/src/com/intellij/psi/stubs/SerializationManagerImpl.java @@ -20,6 +20,7 @@ import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.diagnostic.LogUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.util.ShutDownTracker; import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IStubFileElementType; @@ -51,6 +52,7 @@ public class SerializationManagerImpl extends SerializationManager implements Ap private final AtomicBoolean myNameStorageCrashed = new AtomicBoolean(false); private final File myFile = new File(PathManager.getIndexRoot(), "rep.names"); private boolean mySerializersLoaded = false; + private final AtomicBoolean myShutdownPerformed = new AtomicBoolean(false); public SerializationManagerImpl() { myFile.getParentFile().mkdirs(); @@ -63,7 +65,14 @@ public class SerializationManagerImpl extends SerializationManager implements Ap repairNameStorage(); // need this in order for myNameStorage not to be null myNameStorageCrashed.set(true); } - registerSerializer(PsiFileStubImpl.TYPE); + finally { + registerSerializer(PsiFileStubImpl.TYPE); + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + public void run() { + performShutdown(); + } + }); + } } public boolean isNameStorageCorrupted() { @@ -230,8 +239,17 @@ public class SerializationManagerImpl extends SerializationManager implements Ap } public void disposeComponent() { + performShutdown(); + } + + private void performShutdown() { + if (!myShutdownPerformed.compareAndSet(false, true)) { + return; // already shut down + } + LOG.info("START StubSerializationManager SHUTDOWN"); try { myNameStorage.close(); + LOG.info("END StubSerializationManager SHUTDOWN"); } catch (IOException e) { LOG.error(e); diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index c2a3e2d99284..a8215c2f9987 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -407,12 +407,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi super.dispose(); } finally { - try { - getStubIndex().dispose(); - } - finally { - ((SerializationManagerImpl)SerializationManager.getInstance()).disposeComponent(); - } + getStubIndex().dispose(); } } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index 617340445c6d..d63296b3277b 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -57,6 +57,7 @@ import com.intellij.psi.impl.PsiDocumentTransactionListener; import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.search.EverythingGlobalScope; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.stubs.SerializationManager; import com.intellij.util.ArrayUtil; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; @@ -132,7 +133,7 @@ public class FileBasedIndex implements ApplicationComponent { boolean acceptInput(VirtualFile file); } - public FileBasedIndex(final VirtualFileManagerEx vfManager, FileDocumentManager fdm, MessageBus bus) throws IOException { + public FileBasedIndex(final VirtualFileManagerEx vfManager, FileDocumentManager fdm, MessageBus bus, SerializationManager sm /*need this parameter to ensure component dependency*/) throws IOException { myVfManager = vfManager; myFileDocumentManager = fdm; myIsUnitTestMode = ApplicationManager.getApplication().isUnitTestMode(); From 24b5e9a888c163a9e5dc1af22d42882c7771d466 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 16:48:23 +0100 Subject: [PATCH 65/95] by default execute typed handler when finishing completion by a character --- .../completion/JavaAwareCompletionData.java | 4 +++- .../completion/JavaClassNameInsertHandler.java | 4 ---- .../completion/JavaCompletionUtil.java | 9 +++++---- .../completion/JavaMethodCallElement.java | 1 + .../completion/SmartCompletionDecorator.java | 11 +++++++---- .../normal/SpaceAfterLookupString_after.java | 2 +- .../codeInsight/completion/InsertionContext.java | 5 +++-- .../completion/CodeCompletionHandlerBase.java | 15 +++++++++------ .../codeInsight/completion/CompletionUtil.java | 3 ++- .../completion/TemplateInsertHandler.java | 2 +- .../codeInsight/lookup/impl/TypedHandler.java | 1 + .../codeInsight/template/impl/TemplateState.java | 2 +- 12 files changed, 34 insertions(+), 25 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java index ae8c9070c875..4fa3bb4f4eb8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java @@ -87,13 +87,15 @@ public class JavaAwareCompletionData extends CompletionData{ ret.setInsertHandler(new InsertHandler() { @Override public void handleInsert(InsertionContext context, LookupElement item) { + if (context.shouldAddCompletionChar()) { + return; + } TailType type = analyzeItem(item.getObject(), context.getFile().findElementAt(context.getStartOffset())); if (type == TailType.NONE) { type = tailType; } //new DefaultInsertHandler().handleInsert(context, item); if (type != TailType.NONE) { - context.setAddCompletionChar(false); type.processTail(context.getEditor(), context.getTailOffset()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java index c42019456461..4c7c656b3b08 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -44,10 +44,6 @@ class JavaClassNameInsertHandler implements InsertHandler implements Type final PsiType type = method.getReturnType(); if (context.getCompletionChar() == '!' && type != null && PsiType.BOOLEAN.isAssignableFrom(type)) { + context.setAddCompletionChar(false); context.commitDocument(); final int offset = context.getOffset(refStart); final PsiMethodCallExpression methodCall = PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiMethodCallExpression.class, false); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java index ef32d2520c77..9bd06caa047a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.codeInsight.lookup.TailTypeDecorator; @@ -52,10 +53,12 @@ public class SmartCompletionDecorator extends TailTypeDecorator { } protected TailType computeTailType(InsertionContext context) { - final TailType defType = LookupItem.getDefaultTailType(context.getCompletionChar()); - if (defType != null) { - context.setAddCompletionChar(false); - return defType; + if (context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { + return TailType.SMART_COMPLETION; + } + + if (LookupItem.getDefaultTailType(context.getCompletionChar()) != null) { + return null; } LookupElement delegate = getDelegate(); diff --git a/java/java-tests/testData/codeInsight/completion/normal/SpaceAfterLookupString_after.java b/java/java-tests/testData/codeInsight/completion/normal/SpaceAfterLookupString_after.java index 61c3e21af605..13d4c7a2afe0 100644 --- a/java/java-tests/testData/codeInsight/completion/normal/SpaceAfterLookupString_after.java +++ b/java/java-tests/testData/codeInsight/completion/normal/SpaceAfterLookupString_after.java @@ -3,7 +3,7 @@ class Foo { { String abc; String abcdef; - abc d + abc d } } \ No newline at end of file diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java b/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java index d5c1627795b2..1a793de71178 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java +++ b/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java @@ -36,17 +36,18 @@ public class InsertionContext { private final PsiFile myFile; private final Editor myEditor; private Runnable myLaterRunnable; - private boolean myAddCompletionChar = true; + private boolean myAddCompletionChar; public InsertionContext(final OffsetMap offsetMap, final char completionChar, final LookupElement[] elements, @NotNull final PsiFile file, - @NotNull final Editor editor) { + @NotNull final Editor editor, final boolean addCompletionChar) { myOffsetMap = offsetMap; myCompletionChar = completionChar; myElements = elements; myFile = file; myEditor = editor; setTailOffset(editor.getCaretModel().getOffset()); + myAddCompletionChar = addCompletionChar; } public void setTailOffset(final int offset) { 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 4a55ff85d4be..5e2ea8902ae3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -18,12 +18,12 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.CodeInsightActionHandler; import com.intellij.codeInsight.CodeInsightSettings; -import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.impl.CompletionServiceImpl; import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler; import com.intellij.codeInsight.lookup.*; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.DataManager; import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; @@ -37,6 +37,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -545,7 +546,9 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { final Editor editor = indicator.getEditor(); final PsiFile file = indicator.getParameters().getOriginalFile(); - final InsertionContext context = new InsertionContext(indicator.getOffsetMap(), completionChar, items.toArray(new LookupElement[items.size()]), file, editor); + final InsertionContext context = new InsertionContext(indicator.getOffsetMap(), completionChar, items.toArray(new LookupElement[items.size()]), file, editor, + completionChar != Lookup.AUTO_INSERT_SELECT_CHAR && completionChar != Lookup.REPLACE_SELECT_CHAR && + completionChar != Lookup.NORMAL_SELECT_CHAR && completionChar != Lookup.COMPLETE_STATEMENT_SELECT_CHAR); ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { final int idEndOffset = indicator.getIdentifierEndOffset(); @@ -563,10 +566,10 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { final int tailOffset = context.getTailOffset(); if (tailOffset >= 0) { - if (context.shouldAddCompletionChar() && - completionChar != Lookup.AUTO_INSERT_SELECT_CHAR && completionChar != Lookup.REPLACE_SELECT_CHAR && - completionChar != Lookup.NORMAL_SELECT_CHAR && completionChar != Lookup.COMPLETE_STATEMENT_SELECT_CHAR) { - TailType.insertChar(editor, tailOffset, completionChar); + if (context.shouldAddCompletionChar()) { + editor.getCaretModel().moveToOffset(tailOffset); + EditorActionManager.getInstance().getTypedAction().getHandler().execute(editor, completionChar, DataManager.getInstance() + .getDataContext(editor.getContentComponent())); } } else { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionUtil.java index bf8f691202e8..967be3f5a7a2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionUtil.java @@ -175,7 +175,8 @@ public class CompletionUtil { private static InsertionContext newContext(InsertionContext oldContext, LookupElement forElement) { final Editor editor = oldContext.getEditor(); - return new InsertionContext(new OffsetMap(editor.getDocument()), Lookup.AUTO_INSERT_SELECT_CHAR, new LookupElement[]{forElement}, oldContext.getFile(), editor); + return new InsertionContext(new OffsetMap(editor.getDocument()), Lookup.AUTO_INSERT_SELECT_CHAR, new LookupElement[]{forElement}, oldContext.getFile(), editor, + oldContext.shouldAddCompletionChar()); } public static InsertionContext newContext(InsertionContext oldContext, LookupElement forElement, int startOffset, int tailOffset) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java index 977adac61580..d763a7c574c0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java @@ -85,7 +85,7 @@ public abstract class TemplateInsertHandler implements InsertHandler { final PsiFile psiFile = context.getFile(); InsertionContext newContext = - new InsertionContext(offsetMap, context.getCompletionChar(), LookupElement.EMPTY_ARRAY, psiFile, editor); + new InsertionContext(offsetMap, context.getCompletionChar(), LookupElement.EMPTY_ARRAY, psiFile, editor, context.shouldAddCompletionChar()); populateInsertMap(psiFile, offsetMap); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java index 4dcab26920a2..370c39f68bc3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java @@ -82,6 +82,7 @@ public class TypedHandler implements TypedActionHandler { if (result == CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP && lookup.isFocused()) { LookupElement item = lookup.getCurrentItem(); if (item != null){ + inside = false; FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_FINISH_BY_DOT_ETC); lookup.finishLookup(charTyped); return; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 7457d7e91936..7916e843bebd 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -520,7 +520,7 @@ public class TemplateState implements Disposable { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); final OffsetMap offsetMap = new OffsetMap(myDocument); - final InsertionContext context = new InsertionContext(offsetMap, (char)0, elements, psiFile, myEditor); + final InsertionContext context = new InsertionContext(offsetMap, (char)0, elements, psiFile, myEditor, false); context.setTailOffset(myEditor.getCaretModel().getOffset()); offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, context.getTailOffset() - item.getLookupString().length()); offsetMap.addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, context.getTailOffset()); From 435b14a0ada643c1ab3a2401b29244e7de99ef24 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 16:58:48 +0100 Subject: [PATCH 66/95] finishing completion with [ (IDEA-40461) --- .../completion/DefaultInsertHandler.java | 1 - .../codeInsight/completion/JavaCharFilter.java | 1 + .../completion/normal/ClassSquareBracket.java | 6 ++++++ .../completion/normal/ClassSquareBracket_after.java | 6 ++++++ .../completion/normal/MethodSquareBracket.java | 9 +++++++++ .../normal/MethodSquareBracket_after.java | 9 +++++++++ .../completion/normal/PrimitiveSquareBracket.java | 5 +++++ .../normal/PrimitiveSquareBracket_after.java | 5 +++++ .../completion/normal/VariableSquareBracket.java | 7 +++++++ .../normal/VariableSquareBracket_after.java | 7 +++++++ .../completion/NormalCompletionTest.groovy | 13 ++++++------- 11 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket_after.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket_after.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket_after.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/DefaultInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/DefaultInsertHandler.java index 6949e1cc1bb1..f8d6812dde2a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/DefaultInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/DefaultInsertHandler.java @@ -210,7 +210,6 @@ public class DefaultInsertHandler extends TemplateInsertHandler implements Clone case '<': case '>': case '\"': - case '[': return TailType.createSimpleTailType(completionChar); } final TailType attr = item.getTailType(); return attr == TailType.UNKNOWN ? TailType.NONE : attr; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java index 6f6d83d35ced..d4005d636361 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java @@ -59,6 +59,7 @@ public class JavaCharFilter extends CharFilter { } } if (c == '.' && isWithinLiteral(lookup)) return Result.ADD_TO_PREFIX; + if (c == '[') return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP; if (c == '#' && PsiTreeUtil.getParentOfType(lookup.getPsiElement(), PsiDocComment.class) != null) { final LookupElement item = lookup.getCurrentItem(); diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket.java b/java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket.java new file mode 100644 index 000000000000..89fff3a6c574 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket.java @@ -0,0 +1,6 @@ +class AbcdClass {} +class AbcdeClass {} + +class Foo { + Abcd +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket_after.java b/java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket_after.java new file mode 100644 index 000000000000..03944aa60a36 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassSquareBracket_after.java @@ -0,0 +1,6 @@ +class AbcdClass {} +class AbcdeClass {} + +class Foo { + AbcdClass[] +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket.java b/java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket.java new file mode 100644 index 000000000000..810337061123 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket.java @@ -0,0 +1,9 @@ +class Foo { + int[] aaaa(int x){} + int[] aaab(){} + + + { + aaa + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket_after.java b/java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket_after.java new file mode 100644 index 000000000000..e563262eb2a6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/MethodSquareBracket_after.java @@ -0,0 +1,9 @@ +class Foo { + int[] aaaa(int x){} + int[] aaab(){} + + + { + aaaa()[] + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket.java b/java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket.java new file mode 100644 index 000000000000..31513c1ce7b9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket.java @@ -0,0 +1,5 @@ +class Foo { + d + + class doz {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket_after.java b/java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket_after.java new file mode 100644 index 000000000000..0be62feb89b1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/PrimitiveSquareBracket_after.java @@ -0,0 +1,5 @@ +class Foo { + double[] + + class doz {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket.java b/java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket.java new file mode 100644 index 000000000000..ebff9d951901 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket.java @@ -0,0 +1,7 @@ +class Foo { + { + int[] aaaa; + int[] aaab; + aa + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket_after.java b/java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket_after.java new file mode 100644 index 000000000000..84538649bbe4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/VariableSquareBracket_after.java @@ -0,0 +1,7 @@ +class Foo { + { + int[] aaaa; + int[] aaab; + aaaa[] + } +} \ 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 753a551e8ec0..4f317556dafa 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -569,13 +569,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { configureByFile(getTestName(false) + ".java"); final int parametersCount = ((PsiMethod)getLookup().getCurrentItem().getObject()).getParameterList().getParametersCount(); assertEquals(0, parametersCount); - new WriteCommandAction.Simple(getProject(), new PsiFile[0]) { - @Override - protected void run() throws Throwable { - getLookup().finishLookup(Lookup.NORMAL_SELECT_CHAR); - } - }.execute().throwException(); - + type '\n' checkResult() } @@ -834,6 +828,11 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testCommaAfterVariable() throws Throwable { doTest(',') } + public void testClassSquareBracket() throws Throwable { doTest('[') } + public void testPrimitiveSquareBracket() throws Throwable { doTest('[') } + public void testVariableSquareBracket() throws Throwable { doTest('[') } + public void testMethodSquareBracket() throws Throwable { doTest('[') } + public void testSuperProtectedMethod() throws Throwable { myFixture.addClass """package foo; public class Bar { From 9c07d653d7d61c0612397487f9fe85ee50c056d7 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 17:59:43 +0100 Subject: [PATCH 67/95] may the autopopup appear on typing in another editor --- .../completion/JavaAutoPopupTest.groovy | 43 ++++++++++++++++++- .../completion/CompletionPhase.java | 5 +-- .../CompletionAutoPopupHandler.java | 5 +++ 3 files changed, 49 insertions(+), 4 deletions(-) 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 5701157ce85b..2b864ed016bc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -17,14 +17,20 @@ package com.intellij.codeInsight.completion import com.intellij.codeInsight.lookup.Lookup import com.intellij.codeInsight.lookup.LookupManager +import com.intellij.ide.DataManager import com.intellij.ide.ui.UISettings import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.EditorFactory +import com.intellij.openapi.editor.actionSystem.EditorActionManager import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.LoadingOrder import com.intellij.openapi.progress.ProgressManager +import com.intellij.psi.PsiFile -/** + /** * @author peter */ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { @@ -572,4 +578,39 @@ public interface Test { assert !lookup } + public void testTypingInAnotherEditor() { + myFixture.configureByText("a.java", "") + type 'c' + assert lookup + + Editor another = null + def wca = new WriteCommandAction.Simple(getProject(), new PsiFile[0]) { + @Override + protected void run() { + for (i in 1..10) { + EditorActionManager.instance.getTypedAction().handler.execute(another, (char) 'x', DataManager.instance.dataContext) + } + } + } + + try { + edt { + lookup.hide() + def file = myFixture.addFileToProject("b.java", "") + another = EditorFactory.instance.createEditor(file.viewProvider.document, project) + wca.execute() + assert another.document.text.startsWith('xxxx') + } + joinAlarm() + joinCompletion() + assert !LookupManager.getActiveLookup(another) + type 'l' + assert lookup + } + finally { + edt { EditorFactory.instance.releaseEditor(another) } + } + + } + } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java index 62dfb6dc8815..50a2418fe7bf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java @@ -209,7 +209,7 @@ public abstract class CompletionPhase implements Disposable { } } public static class EmptyAutoPopup extends CompletionPhase { - private final Editor editor; + public final Editor editor; private final Project project; private final EditorMouseAdapter mouseListener; private final CaretListener caretListener; @@ -287,11 +287,10 @@ public abstract class CompletionPhase implements Disposable { finally { changeGuard = false; } - } private static void stopAutoPopup() { - CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); + CompletionServiceImpl.setCompletionPhase(NoCompletion); } @Override 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 7fe8aea71fea..3070505ae37c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -60,6 +60,11 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { return Result.CONTINUE; } + CompletionPhase oldPhase = CompletionServiceImpl.getCompletionPhase(); + if (oldPhase instanceof CompletionPhase.EmptyAutoPopup && ((CompletionPhase.EmptyAutoPopup)oldPhase).editor != editor) { + CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); + } + if (!Character.isLetter(charTyped) && charTyped != '_') { if (CompletionServiceImpl.isPhase(CompletionPhase.EmptyAutoPopup.class)) { CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); From 16fae492a8da285bef592e4d74e10ca5473a37ff Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 18:07:29 +0100 Subject: [PATCH 68/95] accept class suggestions in java by < --- .../codeInsight/completion/JavaCharFilter.java | 10 +++++----- .../completion/normal/ClassAngleBracket.java | 6 ++++++ .../completion/normal/ClassAngleBracket_after.java | 6 ++++++ .../codeInsight/completion/NormalCompletionTest.groovy | 2 ++ 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java index d4005d636361..db9f107d87df 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java @@ -41,11 +41,11 @@ public class JavaCharFilter extends CharFilter { public Result acceptChar(char c, final int prefixLength, final Lookup lookup) { if (!lookup.isCompletion()) return null; + LookupElement item = lookup.getCurrentItem(); + if (item == null) return null; + if (c == '!') { if (lookup.getPsiFile() instanceof PsiJavaFile) { - final LookupElement item = lookup.getCurrentItem(); - if (item == null) return null; - final Object o = item.getObject(); if (o instanceof PsiVariable) { if (PsiType.BOOLEAN.isAssignableFrom(((PsiVariable)o).getType())) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; @@ -60,10 +60,10 @@ public class JavaCharFilter extends CharFilter { } if (c == '.' && isWithinLiteral(lookup)) return Result.ADD_TO_PREFIX; if (c == '[') return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP; + if (c == '<' && item.getObject() instanceof PsiClass) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; if (c == '#' && PsiTreeUtil.getParentOfType(lookup.getPsiElement(), PsiDocComment.class) != null) { - final LookupElement item = lookup.getCurrentItem(); - if (item != null && item.getObject() instanceof PsiClass) { + if (item.getObject() instanceof PsiClass) { return Result.SELECT_ITEM_AND_FINISH_LOOKUP; } } diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket.java b/java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket.java new file mode 100644 index 000000000000..89fff3a6c574 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket.java @@ -0,0 +1,6 @@ +class AbcdClass {} +class AbcdeClass {} + +class Foo { + Abcd +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket_after.java b/java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket_after.java new file mode 100644 index 000000000000..ab3dc849b411 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassAngleBracket_after.java @@ -0,0 +1,6 @@ +class AbcdClass {} +class AbcdeClass {} + +class Foo { + AbcdClass<> +} \ 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 4f317556dafa..5ba19599a8cc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -828,6 +828,8 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testCommaAfterVariable() throws Throwable { doTest(',') } + public void testClassAngleBracket() throws Throwable { doTest('<') } + public void testClassSquareBracket() throws Throwable { doTest('[') } public void testPrimitiveSquareBracket() throws Throwable { doTest('[') } public void testVariableSquareBracket() throws Throwable { doTest('[') } From 02f113c68e868a073c7d360c7bc19586c3b03c84 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 18:08:48 +0100 Subject: [PATCH 69/95] correct the test --- .../codeInsight/completion/JavaAutoPopupTest.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 2b864ed016bc..d2c1027ab325 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -587,9 +587,7 @@ public interface Test { def wca = new WriteCommandAction.Simple(getProject(), new PsiFile[0]) { @Override protected void run() { - for (i in 1..10) { - EditorActionManager.instance.getTypedAction().handler.execute(another, (char) 'x', DataManager.instance.dataContext) - } + EditorActionManager.instance.getTypedAction().handler.execute(another, (char) 'x', DataManager.instance.dataContext) } } @@ -599,7 +597,7 @@ public interface Test { def file = myFixture.addFileToProject("b.java", "") another = EditorFactory.instance.createEditor(file.viewProvider.document, project) wca.execute() - assert another.document.text.startsWith('xxxx') + assert 'x' == another.document.text } joinAlarm() joinCompletion() From d7e6dca8272bf58bfcbe01c13df44fddf9b9fe42 Mon Sep 17 00:00:00 2001 From: anna Date: Tue, 8 Mar 2011 18:08:13 +0100 Subject: [PATCH 70/95] revert --- .../intellij/refactoring/actions/BaseRefactoringAction.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java index db42a641c67e..0144237af69d 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java +++ b/platform/lang-impl/src/com/intellij/refactoring/actions/BaseRefactoringAction.java @@ -133,9 +133,6 @@ public abstract class BaseRefactoringAction extends AnAction { return; } element = getElementAtCaret(editor, file); - if (element != null) { - languages = new Language[] {element.getLanguage()}; - } } if (element == null || element instanceof SyntheticElement || languages == null) { From 66c2b4fdeef35896b5a5a7791527c2e92c772bb9 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 8 Mar 2011 17:42:00 +0100 Subject: [PATCH 71/95] EA-26007 (NPE in log statement) --- .../src/com/intellij/util/ui/ComboBoxTableCellRenderer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/ui/ComboBoxTableCellRenderer.java b/platform/util/src/com/intellij/util/ui/ComboBoxTableCellRenderer.java index 713bc6258408..279d6fb79399 100644 --- a/platform/util/src/com/intellij/util/ui/ComboBoxTableCellRenderer.java +++ b/platform/util/src/com/intellij/util/ui/ComboBoxTableCellRenderer.java @@ -15,6 +15,7 @@ */ package com.intellij.util.ui; +import com.intellij.openapi.diagnostic.LogUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.ListWithSelection; @@ -57,7 +58,7 @@ public class ComboBoxTableCellRenderer extends JPanel implements TableCellRender boolean hasFocus, int row, int column) { - LOG.assertTrue(value instanceof ListWithSelection, value.getClass().getName()); + LOG.assertTrue(value instanceof ListWithSelection, LogUtil.objectAndClass(value)); final ListWithSelection tags = (ListWithSelection)value; if (tags.getSelection() == null) { tags.selectFirst(); From bc8fd263fa5f7333c49c55b64412432d11a9a3ae Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 8 Mar 2011 18:27:17 +0100 Subject: [PATCH 72/95] EA-26014 (more logging) --- .../psi/impl/SharedPsiElementImplUtil.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/SharedPsiElementImplUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/SharedPsiElementImplUtil.java index 4aaf4f3eccb8..fd628e7b5198 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/SharedPsiElementImplUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/SharedPsiElementImplUtil.java @@ -86,45 +86,47 @@ public class SharedPsiElementImplUtil { @Nullable public static PsiElement getNextSibling(PsiElement element) { - if (element instanceof PsiFile) { - final FileViewProvider viewProvider = ((PsiFile)element).getViewProvider(); - element = viewProvider.getPsi(viewProvider.getBaseLanguage()); - } - PsiElement parent = element.getParent(); + PsiElement parent = getElementParent(element); if (parent == null) return null; - PsiElement[] children = parent.getChildren(); - for (int i = 0; i < children.length; i++) { - PsiElement child = children[i]; - if (child == - element) { //do not use .equals since some smartheads are used to overriding PsiElement.equals e.g. com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatementImpl.equals() - return i < children.length - 1 ? children[i + 1] : null; - } - } - LOG.error("Cannot find element among its parent' children." + - " element: '" + element + "';" + - " parent: '" + parent + "';" + - " children: " + new ArrayList(Arrays.asList(children)) + "; " + - " file:" + element.getContainingFile()); - return null; + + final PsiElement[] children = parent.getChildren(); + final int index = getChildIndex(children, element); + return 0 <= index && index < children.length - 1 ? children[index + 1] : null; } @Nullable public static PsiElement getPrevSibling(PsiElement element) { + PsiElement parent = getElementParent(element); + if (parent == null) return null; + + final PsiElement[] children = parent.getChildren(); + final int index = getChildIndex(children, element); + return index > 0 ? children[index - 1] : null; + } + + @Nullable + private static PsiElement getElementParent(PsiElement element) { if (element instanceof PsiFile) { final FileViewProvider viewProvider = ((PsiFile)element).getViewProvider(); element = viewProvider.getPsi(viewProvider.getBaseLanguage()); } - PsiElement parent = element.getParent(); - if (parent == null) return null; - PsiElement[] children = parent.getChildren(); + if (element == null) return null; + return element.getParent(); + } + + private static int getChildIndex(final PsiElement[] children, final PsiElement child) { for (int i = 0; i < children.length; i++) { - PsiElement child = children[i]; - if (child == - element) { //do not use .equals since some smartheads are used to overriding PsiElement.equals e.g. com.intellij.psi.impl.source.jsp.jspJava.JspxImportStatementImpl.equals() - return i > 0 ? children[i - 1] : null; + PsiElement candidate = children[i]; + // do not use equals() since some smart-heads are used to override it (e.g. JspxImportStatementImpl) + if (candidate == child) { + return i; } } - LOG.assertTrue(false); - return null; + LOG.error("Cannot find element among its parent' children." + + " element: '" + child + "';" + + " parent: '" + child.getParent() + "';" + + " children: " + Arrays.asList(children) + "; " + + " file:" + child.getContainingFile()); + return -1; } } From ef087c602ccbaa4189c77977073ae0c461a6a876 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 8 Mar 2011 19:19:50 +0100 Subject: [PATCH 73/95] EA-26016 (more logging) --- .../psi/impl/source/tree/LeafPsiElement.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LeafPsiElement.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LeafPsiElement.java index 0e873c668cbc..26d4ce96484f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LeafPsiElement.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/LeafPsiElement.java @@ -26,6 +26,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.FileStatus; +import com.intellij.pom.Navigatable; import com.intellij.psi.*; import com.intellij.psi.impl.CheckUtil; import com.intellij.psi.impl.SharedPsiElementImplUtil; @@ -79,10 +80,9 @@ public class LeafPsiElement extends LeafElement implements PsiElement, Navigatio } public PsiFile getContainingFile() { - PsiFile file = SharedImplUtil.getContainingFile(this); - if (file == null || !file.isValid()) { - invalid(); - } + final PsiFile file = SharedImplUtil.getContainingFile(this); + if (file == null || !file.isValid()) invalid(); + //noinspection ConstantConditions return file; } @@ -92,7 +92,15 @@ public class LeafPsiElement extends LeafElement implements PsiElement, Navigatio indicator.checkCanceled(); } - throw new PsiInvalidElementAccessException(this); + final StringBuilder builder = new StringBuilder(); + TreeElement element = this; + while (element != null) { + if (element != this) builder.append(" / "); + builder.append(element.getClass().getName()).append(':').append(element.getElementType()); + element = element.getTreeParent(); + } + + throw new PsiInvalidElementAccessException(this, builder.toString()); } public PsiElement findElementAt(int offset) { @@ -220,7 +228,7 @@ public class LeafPsiElement extends LeafElement implements PsiElement, Navigatio public Project getProject() { final PsiManager manager = getManager(); if (manager == null) invalid(); - + //noinspection ConstantConditions return manager.getProject(); } @@ -246,7 +254,10 @@ public class LeafPsiElement extends LeafElement implements PsiElement, Navigatio } public void navigate(boolean requestFocus) { - EditSourceUtil.getDescriptor(this).navigate(requestFocus); + final Navigatable descriptor = EditSourceUtil.getDescriptor(this); + if (descriptor != null) { + descriptor.navigate(requestFocus); + } } public boolean canNavigate() { From ae03a1e758140efb83485850b34340b234fd69dc Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 19:32:07 +0100 Subject: [PATCH 74/95] java-like pair <> handling in groovy --- .../editorActions/JavaBackspaceHandler.java | 18 +++-- .../editorActions/JavaTypedHandler.java | 45 +++++++----- .../editorActions/JavaTypedHandlerUtil.java | 30 -------- plugins/groovy/src/META-INF/plugin.xml | 3 + .../actions/GroovyBackspaceHandler.java | 50 +++++++++++++ .../editor/actions/GroovyTypedHandler.java | 73 +++++++++++++++++++ .../groovy/lang/GroovyEditingTest.java | 4 + .../groovy/testdata/editing/NoPairLess.groovy | 1 + .../testdata/editing/NoPairLess_after.groovy | 1 + .../PairAngleBracketAfterClassName.groovy | 1 + ...AngleBracketAfterClassNameBackspace.groovy | 1 + ...racketAfterClassNameBackspace_after.groovy | 1 + ...rAngleBracketAfterClassNameOvertype.groovy | 1 + ...BracketAfterClassNameOvertype_after.groovy | 1 + ...airAngleBracketAfterClassName_after.groovy | 1 + 15 files changed, 177 insertions(+), 54 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerUtil.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyBackspaceHandler.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java create mode 100644 plugins/groovy/testdata/editing/NoPairLess.groovy create mode 100644 plugins/groovy/testdata/editing/NoPairLess_after.groovy create mode 100644 plugins/groovy/testdata/editing/PairAngleBracketAfterClassName.groovy create mode 100644 plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace.groovy create mode 100644 plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace_after.groovy create mode 100644 plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype.groovy create mode 100644 plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype_after.groovy create mode 100644 plugins/groovy/testdata/editing/PairAngleBracketAfterClassName_after.groovy diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaBackspaceHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaBackspaceHandler.java index 44e4985af417..2f1c8991a779 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaBackspaceHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaBackspaceHandler.java @@ -22,6 +22,7 @@ import com.intellij.psi.JavaTokenType; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiJavaFile; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtil; public class JavaBackspaceHandler extends BackspaceHandlerDelegate { @@ -43,30 +44,33 @@ public class JavaBackspaceHandler extends BackspaceHandlerDelegate { char c1 = chars.charAt(offset); if (c == '<' && myToDeleteGt) { if (c1 != '>') return true; - handleLTDeletion(editor, offset); + handleLTDeletion(editor, offset, JavaTokenType.LT, JavaTokenType.GT, JavaTypedHandler.INVALID_INSIDE_REFERENCE); return true; } return false; } - private static void handleLTDeletion(final Editor editor, final int offset) { + public static void handleLTDeletion(final Editor editor, + final int offset, + final IElementType lt, + final IElementType gt, final TokenSet invalidInsideReference) { HighlighterIterator iterator = ((EditorEx)editor).getHighlighter().createIterator(offset); - while (iterator.getStart() > 0 && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) { + while (iterator.getStart() > 0 && !invalidInsideReference.contains(iterator.getTokenType())) { iterator.retreat(); } - if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.advance(); + if (invalidInsideReference.contains(iterator.getTokenType())) iterator.advance(); int balance = 0; while (!iterator.atEnd() && balance >= 0) { final IElementType tokenType = iterator.getTokenType(); - if (tokenType == JavaTokenType.LT) { + if (tokenType == lt) { balance++; } - else if (tokenType == JavaTokenType.GT) { + else if (tokenType == gt) { balance--; } - else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) { + else if (invalidInsideReference.contains(tokenType)) { break; } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java index a99e67f228c3..6237cfd6dbd4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandler.java @@ -34,6 +34,7 @@ import com.intellij.psi.filters.position.SuperParentFilter; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.jsp.JspFile; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.Nullable; @@ -42,6 +43,7 @@ import org.jetbrains.annotations.Nullable; * @author yole */ public class JavaTypedHandler extends TypedHandlerDelegate { + static final TokenSet INVALID_INSIDE_REFERENCE = TokenSet.create(JavaTokenType.SEMICOLON, JavaTokenType.LBRACE, JavaTokenType.RBRACE); private boolean myJavaLTTyped; public Result checkAutoPopup(final char charTyped, final Project project, final Editor editor, final PsiFile file) { @@ -106,7 +108,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate { if (file instanceof PsiJavaFile && !(file instanceof JspFile) && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && PsiUtil.isLanguageLevel5OrHigher(file)) { - if (handleJavaGT(editor)) return Result.STOP; + if (handleJavaGT(editor, JavaTokenType.LT, JavaTokenType.GT, INVALID_INSIDE_REFERENCE)) return Result.STOP; } } @@ -144,7 +146,7 @@ public class JavaTypedHandler extends TypedHandlerDelegate { public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) { if (myJavaLTTyped) { myJavaLTTyped = false; - handleAfterJavaLT(editor); + handleAfterJavaLT(editor, JavaTokenType.LT, JavaTokenType.GT, INVALID_INSIDE_REFERENCE); return Result.STOP; } return Result.CONTINUE; @@ -170,7 +172,10 @@ public class JavaTypedHandler extends TypedHandlerDelegate { } //need custom handler, since brace matcher cannot be used - private static boolean handleJavaGT(final Editor editor) { + public static boolean handleJavaGT(final Editor editor, + final IElementType lt, + final IElementType gt, + final TokenSet invalidInsideReference) { if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return false; int offset = editor.getCaretModel().getOffset(); @@ -178,24 +183,23 @@ public class JavaTypedHandler extends TypedHandlerDelegate { if (offset == editor.getDocument().getTextLength()) return false; HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset); - if (iterator.getTokenType() != JavaTokenType.GT) return false; - while (!iterator.atEnd() && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) { + if (iterator.getTokenType() != gt) return false; + while (!iterator.atEnd() && !invalidInsideReference.contains(iterator.getTokenType())) { iterator.advance(); } - if (iterator.atEnd()) return false; - if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.retreat(); + if (!iterator.atEnd() && invalidInsideReference.contains(iterator.getTokenType())) iterator.retreat(); int balance = 0; while (!iterator.atEnd() && balance >= 0) { final IElementType tokenType = iterator.getTokenType(); - if (tokenType == JavaTokenType.LT) { + if (tokenType == lt) { balance--; } - else if (tokenType == JavaTokenType.GT) { + else if (tokenType == gt) { balance++; } - else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) { + else if (invalidInsideReference.contains(tokenType)) { break; } @@ -212,27 +216,30 @@ public class JavaTypedHandler extends TypedHandlerDelegate { } //need custom handler, since brace matcher cannot be used - private static void handleAfterJavaLT(final Editor editor) { + public static void handleAfterJavaLT(final Editor editor, + final IElementType lt, + final IElementType gt, + final TokenSet invalidInsideReference) { if (!CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) return; int offset = editor.getCaretModel().getOffset(); HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset); - while (iterator.getStart() > 0 && !JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) { + while (iterator.getStart() > 0 && !invalidInsideReference.contains(iterator.getTokenType())) { iterator.retreat(); } - if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(iterator.getTokenType())) iterator.advance(); + if (invalidInsideReference.contains(iterator.getTokenType())) iterator.advance(); int balance = 0; while (!iterator.atEnd() && balance >= 0) { final IElementType tokenType = iterator.getTokenType(); - if (tokenType == JavaTokenType.LT) { + if (tokenType == lt) { balance++; } - else if (tokenType == JavaTokenType.GT) { + else if (tokenType == gt) { balance--; } - else if (JavaTypedHandlerUtil.isTokenInvalidInsideReference(tokenType)) { + else if (invalidInsideReference.contains(tokenType)) { break; } @@ -262,7 +269,11 @@ public class JavaTypedHandler extends TypedHandlerDelegate { if (iterator.getStart() > 0) iterator.retreat(); final IElementType tokenType = iterator.getTokenType(); if (tokenType == JavaTokenType.DOT) return true; - if (tokenType == JavaTokenType.IDENTIFIER && iterator.getEnd() == offset) { + return isClassLikeIdentifier(offset, editor, iterator, JavaTokenType.IDENTIFIER); + } + + public static boolean isClassLikeIdentifier(int offset, Editor editor, HighlighterIterator iterator, final IElementType idType) { + if (iterator.getTokenType() == idType && iterator.getEnd() == offset) { final CharSequence chars = editor.getDocument().getCharsSequence(); final char startChar = chars.charAt(iterator.getStart()); if (!Character.isUpperCase(startChar)) return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerUtil.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerUtil.java deleted file mode 100644 index a64ab058d973..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaTypedHandlerUtil.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2000-2009 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.editorActions; - -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.JavaTokenType; - -public class JavaTypedHandlerUtil { - private JavaTypedHandlerUtil() { - } - - public static boolean isTokenInvalidInsideReference(final IElementType tokenType) { - return tokenType == JavaTokenType.SEMICOLON || - tokenType == JavaTokenType.LBRACE || - tokenType == JavaTokenType.RBRACE; - } -} diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 213a58cce51f..132cab787d87 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -162,6 +162,9 @@ + + + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyBackspaceHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyBackspaceHandler.java new file mode 100644 index 000000000000..7d11bfd398ea --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyBackspaceHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2011 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.editor.actions; + +import com.intellij.codeInsight.editorActions.BackspaceHandlerDelegate; +import com.intellij.codeInsight.editorActions.JavaBackspaceHandler; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.PsiFile; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; + +/** + * @author peter + */ +public class GroovyBackspaceHandler extends BackspaceHandlerDelegate { + private boolean myToDeleteGt; + + public void beforeCharDeleted(char c, PsiFile file, Editor editor) { + int offset = editor.getCaretModel().getOffset() - 1; + myToDeleteGt = c =='<' && file instanceof GroovyFile && GroovyTypedHandler.isAfterClassLikeIdentifier(offset, editor); + } + + public boolean charDeleted(final char c, final PsiFile file, final Editor editor) { + int offset = editor.getCaretModel().getOffset(); + final CharSequence chars = editor.getDocument().getCharsSequence(); + if (editor.getDocument().getTextLength() <= offset) return false; //virtual space after end of file + + char c1 = chars.charAt(offset); + if (c == '<' && myToDeleteGt) { + if (c1 != '>') return true; + JavaBackspaceHandler.handleLTDeletion(editor, offset, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, GroovyTypedHandler.INVALID_INSIDE_REFERENCE); + return true; + } + return false; + } + +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java new file mode 100644 index 000000000000..03a2536216e1 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/actions/GroovyTypedHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2011 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.editor.actions; + +import com.intellij.codeInsight.CodeInsightSettings; +import com.intellij.codeInsight.editorActions.JavaTypedHandler; +import com.intellij.codeInsight.editorActions.TypedHandlerDelegate; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.HighlighterIterator; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.TokenSet; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; + +/** + * @author peter + */ +public class GroovyTypedHandler extends TypedHandlerDelegate { + static final TokenSet INVALID_INSIDE_REFERENCE = TokenSet.create(GroovyTokenTypes.mSEMI, GroovyTokenTypes.mLCURLY, GroovyTokenTypes.mRCURLY); + private boolean myJavaLTTyped; + + public Result beforeCharTyped(final char c, final Project project, final Editor editor, final PsiFile file, final FileType fileType) { + int offsetBefore = editor.getCaretModel().getOffset(); + + //important to calculate before inserting charTyped + myJavaLTTyped = '<' == c && + file instanceof GroovyFile && + CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET && + isAfterClassLikeIdentifier(offsetBefore, editor); + + if ('>' == c) { + if (file instanceof GroovyFile && CodeInsightSettings.getInstance().AUTOINSERT_PAIR_BRACKET) { + if (JavaTypedHandler.handleJavaGT(editor, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, INVALID_INSIDE_REFERENCE)) return Result.STOP; + } + } + + return Result.CONTINUE; + } + + public Result charTyped(final char c, final Project project, final Editor editor, final PsiFile file) { + if (myJavaLTTyped) { + myJavaLTTyped = false; + JavaTypedHandler.handleAfterJavaLT(editor, GroovyTokenTypes.mLT, GroovyTokenTypes.mGT, INVALID_INSIDE_REFERENCE); + return Result.STOP; + } + return Result.CONTINUE; + } + + public static boolean isAfterClassLikeIdentifier(final int offset, final Editor editor) { + HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(offset); + if (iterator.atEnd()) return false; + if (iterator.getStart() > 0) iterator.retreat(); + return JavaTypedHandler.isClassLikeIdentifier(offset, editor, iterator, GroovyTokenTypes.mIDENT); + } + + +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyEditingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyEditingTest.java index 40ae35c120fb..b5770b61e56b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyEditingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyEditingTest.java @@ -39,4 +39,8 @@ public class GroovyEditingTest extends LightCodeInsightFixtureTestCase { public void testEnterInMultilineString() throws Throwable { doTest('\n'); } public void testEnterInStringInRefExpr() throws Throwable {doTest('\n');} public void testEnterInGStringInRefExpr() throws Throwable {doTest('\n');} + public void testPairAngleBracketAfterClassName() throws Throwable {doTest('<');} + public void testPairAngleBracketAfterClassNameOvertype() throws Throwable {doTest('>');} + public void testPairAngleBracketAfterClassNameBackspace() throws Throwable {doTest('\b');} + public void testNoPairLess() throws Throwable {doTest('<');} } \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/NoPairLess.groovy b/plugins/groovy/testdata/editing/NoPairLess.groovy new file mode 100644 index 000000000000..f60ce36b31f1 --- /dev/null +++ b/plugins/groovy/testdata/editing/NoPairLess.groovy @@ -0,0 +1 @@ +def foo = x \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/NoPairLess_after.groovy b/plugins/groovy/testdata/editing/NoPairLess_after.groovy new file mode 100644 index 000000000000..80376bf42e00 --- /dev/null +++ b/plugins/groovy/testdata/editing/NoPairLess_after.groovy @@ -0,0 +1 @@ +def foo = x< \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/PairAngleBracketAfterClassName.groovy b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassName.groovy new file mode 100644 index 000000000000..7628dfe04013 --- /dev/null +++ b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassName.groovy @@ -0,0 +1 @@ +Foo \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace.groovy b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace.groovy new file mode 100644 index 000000000000..5afbe77273f9 --- /dev/null +++ b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace.groovy @@ -0,0 +1 @@ +Foo<> \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace_after.groovy b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace_after.groovy new file mode 100644 index 000000000000..7628dfe04013 --- /dev/null +++ b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameBackspace_after.groovy @@ -0,0 +1 @@ +Foo \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype.groovy b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype.groovy new file mode 100644 index 000000000000..ef0ecf36d422 --- /dev/null +++ b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype.groovy @@ -0,0 +1 @@ +Foo> \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype_after.groovy b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype_after.groovy new file mode 100644 index 000000000000..670d4b560190 --- /dev/null +++ b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassNameOvertype_after.groovy @@ -0,0 +1 @@ +Foo \ No newline at end of file diff --git a/plugins/groovy/testdata/editing/PairAngleBracketAfterClassName_after.groovy b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassName_after.groovy new file mode 100644 index 000000000000..5afbe77273f9 --- /dev/null +++ b/plugins/groovy/testdata/editing/PairAngleBracketAfterClassName_after.groovy @@ -0,0 +1 @@ +Foo<> \ No newline at end of file From 925cc2fba6873d7973d918558204e9f8a85551cd Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 19:48:31 +0100 Subject: [PATCH 75/95] [ and < to finish completion in groovy (IDEA-40461) --- .../completion/JavaCharFilter.java | 24 ++++++++------- .../completion/GroovyReferenceCharFilter.java | 11 +++++-- .../completion/GroovyCompletionTest.groovy | 30 +++++++++++++++++++ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java index db9f107d87df..769476ab91d4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java @@ -41,22 +41,24 @@ public class JavaCharFilter extends CharFilter { public Result acceptChar(char c, final int prefixLength, final Lookup lookup) { if (!lookup.isCompletion()) return null; + if (!(lookup.getPsiFile() instanceof PsiJavaFile)) { + return null; + } + LookupElement item = lookup.getCurrentItem(); if (item == null) return null; if (c == '!') { - if (lookup.getPsiFile() instanceof PsiJavaFile) { - final Object o = item.getObject(); - if (o instanceof PsiVariable) { - if (PsiType.BOOLEAN.isAssignableFrom(((PsiVariable)o).getType())) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; - } - if (o instanceof PsiMethod) { - final PsiType type = ((PsiMethod)o).getReturnType(); - if (type != null && PsiType.BOOLEAN.isAssignableFrom(type)) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; - } - - return null; + final Object o = item.getObject(); + if (o instanceof PsiVariable) { + if (PsiType.BOOLEAN.isAssignableFrom(((PsiVariable)o).getType())) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; } + if (o instanceof PsiMethod) { + final PsiType type = ((PsiMethod)o).getReturnType(); + if (type != null && PsiType.BOOLEAN.isAssignableFrom(type)) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + } + + return null; } if (c == '.' && isWithinLiteral(lookup)) return Result.ADD_TO_PREFIX; if (c == '[') return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java index 3f82af576b82..01192094320b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java @@ -17,6 +17,8 @@ package org.jetbrains.plugins.groovy.lang.completion; import com.intellij.codeInsight.lookup.CharFilter; import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; @@ -30,12 +32,15 @@ public class GroovyReferenceCharFilter extends CharFilter { final PsiFile psiFile = lookup.getPsiFile(); if (psiFile != null && !psiFile.getViewProvider().getLanguages().contains(GroovyFileType.GROOVY_LANGUAGE)) return null; + LookupElement item = lookup.getCurrentItem(); + if (item == null) return null; + if (Character.isJavaIdentifierPart(c) || c == '\'') { return Result.ADD_TO_PREFIX; } - if (c == '\n' || c == '\t') { - return Result.SELECT_ITEM_AND_FINISH_LOOKUP; - } + + if (c == '[') return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP; + if (c == '<' && item.getObject() instanceof PsiClass) return Result.SELECT_ITEM_AND_FINISH_LOOKUP; return null; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 76df8dd40eed..34b817f0be9f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -604,4 +604,34 @@ return fo""" def foo(def a) {2} return foo()""" } + + void checkCompletion(String before, String type, String after) { + myFixture.configureByText("a.groovy", before) + myFixture.completeBasic() + myFixture.type(type) + myFixture.checkResult(after) + } + + public void testFinishClassNameWithSquareBracket() { + myFixture.addClass("class AbcdClass {}; class AbcdeClass {}") + checkCompletion("Abcd", '[', "AbcdClass[]") + } + + public void testFinishMethodNameWithSquareBracket() { + myFixture.addClass("""class AbcdClass { + static int[] foo(int x){} + static int[] fobar(){} + }""") + checkCompletion("AbcdClass.fo", '[', "AbcdClass.fobar()[]") + } + + public void testFinishVariableNameWithSquareBracket() { + checkCompletion("int[] fooo, foobar; foo", '[', "int[] fooo, foobar; foobar[]") + } + + public void testFinishClassNameWithLt() { + myFixture.addClass("class AbcdClass {}; class AbcdeClass {}") + checkCompletion("Abcd", '<', "AbcdClass<>") + } + } \ No newline at end of file From 500ea48cc345909026a8d676cd8f1e699881c203 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 20:06:54 +0100 Subject: [PATCH 76/95] extension matching doesn't require all words in file name to be present in the pattern --- platform/util/src/com/intellij/psi/codeStyle/NameUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 65132fb9c5af..16951ed85ced 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -480,7 +480,7 @@ public class NameUtil { private final String myPattern; public MinusculeMatcher(String pattern) { - myPattern = pattern.replaceAll(":", "\\*:"); + myPattern = pattern.replaceAll(":", "\\*:").replaceAll("\\.", "\\*\\."); } private boolean matches(int patternIndex, List words, int wordIndex) { From 5350cc60f37a930a133b5d3626857c8b74ea0e1d Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 20:47:29 +0100 Subject: [PATCH 77/95] rename the option --- platform/util/src/com/intellij/psi/codeStyle/NameUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 16951ed85ced..653fc14bb630 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -39,7 +39,7 @@ public class NameUtil { } }; private static final int MAX_LENGTH = 40; - public static final boolean useMinusculeHumpMatcher = "true".equals(System.getProperty("minuscule.humps.sorting")); + public static final boolean useMinusculeHumpMatcher = "true".equals(System.getProperty("minuscule.humps.matching")); private NameUtil() {} From a05a2bad5d6a0083939f3d8bdc8c493b0b4c5d71 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Mar 2011 20:57:30 +0100 Subject: [PATCH 78/95] test debugging --- .../intellij/codeInsight/completion/JavaAutoPopupTest.groovy | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 d2c1027ab325..6ab60c1f970d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -601,7 +601,10 @@ public interface Test { } joinAlarm() joinCompletion() - assert !LookupManager.getActiveLookup(another) + def l1 = LookupManager.getActiveLookup(another) + if (l1) { + assert false : l1.items + } type 'l' assert lookup } From 28dc9bdc6521b027fb39b9351aa8e53e3533ce05 Mon Sep 17 00:00:00 2001 From: nik Date: Sat, 5 Mar 2011 18:23:55 +0300 Subject: [PATCH 79/95] IDEA-66257: Artifacts: new modules are not sorted in combobox of "Create Jar from Modules" dialog --- .../impl/artifacts/JarArtifactFromModulesDialog.java | 5 ++++- .../roots/ui/configuration/ModulesAlphaComparator.java | 2 ++ .../openapi/roots/ui/configuration/ModulesConfigurator.java | 4 +--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java index 5be9eb25f1a3..fab2d0833a6b 100644 --- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java +++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java @@ -17,6 +17,7 @@ package com.intellij.packaging.impl.artifacts; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.ModulesAlphaComparator; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.io.FileUtil; @@ -32,6 +33,7 @@ import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.Arrays; /** * @author nik @@ -74,7 +76,8 @@ public class JarArtifactFromModulesDialog extends DialogWrapper { updateManifestDirField(); myManifestDirField.addBrowseFolderListener(null, null, project, ManifestFileUtil.createDescriptorForManifestDirectory()); - final Module[] modules = context.getModulesProvider().getModules(); + final Module[] modules = context.getModulesProvider().getModules().clone(); + Arrays.sort(modules, ModulesAlphaComparator.INSTANCE); if (modules.length > 1) { myModuleComboBox.addItem(null); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java index b3bb01f50a50..9bef5a71428a 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java @@ -25,6 +25,8 @@ import java.util.Comparator; * @author 2003 */ public class ModulesAlphaComparator implements Comparator{ + public static ModulesAlphaComparator INSTANCE = new ModulesAlphaComparator(); + public int compare(Module module1, Module module2) { final String name1 = module1.getName(); final String name2 = module2.getName(); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java index daf020a0615e..d36cabf4eb0d 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModulesConfigurator.java @@ -73,10 +73,8 @@ public class ModulesConfigurator implements ModulesProvider, ModuleEditor.Change private final ProjectConfigurable myProjectConfigurable; private final List myModuleEditors = new ArrayList(); private final Comparator myModuleEditorComparator = new Comparator() { - final ModulesAlphaComparator myModulesComparator = new ModulesAlphaComparator(); - public int compare(ModuleEditor editor1, ModuleEditor editor2) { - return myModulesComparator.compare(editor1.getModule(), editor2.getModule()); + return ModulesAlphaComparator.INSTANCE.compare(editor1.getModule(), editor2.getModule()); } @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) From 323e032347dac525bae8c2656659ea7bf7661fa4 Mon Sep 17 00:00:00 2001 From: nik Date: Sat, 5 Mar 2011 18:24:30 +0300 Subject: [PATCH 80/95] IDEA-66217: Host name in HTTP Proxy settings should be trimmed --- .../com/intellij/util/net/HTTPProxySettings.form | 6 +++++- .../intellij/util/net/HTTPProxySettingsPanel.java | 14 ++++++++++---- .../src/messages/CommonBundle.properties | 14 +++++++------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/net/HTTPProxySettings.form b/platform/platform-api/src/com/intellij/util/net/HTTPProxySettings.form index c51a9a381614..94d5591186f5 100644 --- a/platform/platform-api/src/com/intellij/util/net/HTTPProxySettings.form +++ b/platform/platform-api/src/com/intellij/util/net/HTTPProxySettings.form @@ -3,7 +3,7 @@ - + @@ -21,6 +21,7 @@ + @@ -29,6 +30,7 @@ + @@ -81,6 +83,7 @@ + @@ -89,6 +92,7 @@ + diff --git a/platform/platform-api/src/com/intellij/util/net/HTTPProxySettingsPanel.java b/platform/platform-api/src/com/intellij/util/net/HTTPProxySettingsPanel.java index 3f3f7bcbb4d5..74376bc0cfaf 100644 --- a/platform/platform-api/src/com/intellij/util/net/HTTPProxySettingsPanel.java +++ b/platform/platform-api/src/com/intellij/util/net/HTTPProxySettingsPanel.java @@ -106,15 +106,21 @@ public class HTTPProxySettingsPanel implements SearchableConfigurable { httpConfigurable.PROXY_AUTHENTICATION = myProxyAuthCheckBox.isSelected(); httpConfigurable.KEEP_PROXY_PASSWORD = myRememberProxyPasswordCheckBox.isSelected(); - httpConfigurable.PROXY_LOGIN = myProxyLoginTextField.getText(); - httpConfigurable.setPlainProxyPassword(new String (myProxyPasswordTextField.getPassword())); + httpConfigurable.PROXY_LOGIN = trimFieldText(myProxyLoginTextField); + httpConfigurable.setPlainProxyPassword(new String(myProxyPasswordTextField.getPassword())); try { - httpConfigurable.PROXY_PORT = Integer.valueOf(myProxyPortTextField.getText()).intValue(); + httpConfigurable.PROXY_PORT = Integer.valueOf(trimFieldText(myProxyPortTextField)).intValue(); } catch (NumberFormatException e) { httpConfigurable.PROXY_PORT = 80; } - httpConfigurable.PROXY_HOST = myProxyHostTextField.getText(); + httpConfigurable.PROXY_HOST = trimFieldText(myProxyHostTextField); + } + + private static String trimFieldText(JTextField field) { + String trimmed = field.getText().trim(); + field.setText(trimmed); + return trimmed; } private void enableProxy (boolean enabled) { diff --git a/platform/platform-resources-en/src/messages/CommonBundle.properties b/platform/platform-resources-en/src/messages/CommonBundle.properties index 7b941fe2c63b..f1836e5cfc4f 100644 --- a/platform/platform-resources-en/src/messages/CommonBundle.properties +++ b/platform/platform-resources-en/src/messages/CommonBundle.properties @@ -9,13 +9,13 @@ button.cancel=Cancel button.ok=OK button.help=&Help button.retry=&Retry -editbox.password=Password: -checkbox.remember.password=Remember password -editbox.login=Login: -checkbox.use.http.proxy=Use HTTP proxy -checkbox.proxy.authentication=Proxy authentication -editbox.port.number= Port number: -editbox.host.name= Host name: +editbox.password=&Password: +checkbox.remember.password=&Remember password +editbox.login=&Login: +checkbox.use.http.proxy=&Use HTTP proxy +checkbox.proxy.authentication=Proxy &authentication +editbox.port.number= Port &number: +editbox.host.name= &Host name: title.http.proxy.settings=HTTP Proxy Settings tree.node.loading=Loading... title.error=Error From d9f704deaea099fc2431c033e176ac9fa3bd7399 Mon Sep 17 00:00:00 2001 From: nik Date: Sat, 5 Mar 2011 18:34:43 +0300 Subject: [PATCH 81/95] WI-2592: Funny bug with moving breakpoints --- .../xdebugger/impl/breakpoints/XLineBreakpointImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index bf0671c4fc21..335b77697a24 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -271,7 +271,7 @@ public class XLineBreakpointImpl

extends XBreak } private boolean canMoveTo(int line, VirtualFile file) { - return file != null && myType.canPutAt(file, line, getProject()); + return file != null && myType.canPutAt(file, line, getProject()) && getBreakpointManager().findBreakpointAtLine(myType, file, line) == null; } @Nullable From c50e7eeef337041b789fee6895f04480c68f57aa Mon Sep 17 00:00:00 2001 From: nik Date: Sat, 5 Mar 2011 18:55:41 +0300 Subject: [PATCH 82/95] IDEA-63452: The dialog name "Choose Dependent Modules" needs to be changed --- .../ui/configuration/classpath/ClasspathPanelImpl.java | 7 ++++--- .../configuration/libraryEditor/ChooseModulesDialog.java | 5 +++++ .../src/messages/ProjectBundle.properties | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java index dfbaa0d5ce4d..a7a23e18f039 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/classpath/ClasspathPanelImpl.java @@ -489,7 +489,8 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { Messages.showMessageDialog(ClasspathPanelImpl.this, ProjectBundle.message("message.no.module.dependency.candidates"), getTitle(), Messages.getInformationIcon()); return null; } - return new ModuleChooser(chooseItems, ProjectBundle.message("classpath.chooser.title.add.module.dependency")); + return new ModuleChooser(chooseItems, ProjectBundle.message("classpath.chooser.title.add.module.dependency"), + ProjectBundle.message("classpath.chooser.description.add.module.dependency")); } } ); @@ -669,8 +670,8 @@ public class ClasspathPanelImpl extends JPanel implements ClasspathPanel { } private class ModuleChooser extends ChooseModulesDialog implements ClasspathElementChooser { - public ModuleChooser(final List items, final String title) { - super(ClasspathPanelImpl.this, items, title); + public ModuleChooser(final List items, final String title, String description) { + super(ClasspathPanelImpl.this, items, title, description); } public void doChoose() { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/ChooseModulesDialog.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/ChooseModulesDialog.java index e876f5588a5f..013628bc233a 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/ChooseModulesDialog.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/ChooseModulesDialog.java @@ -25,6 +25,7 @@ package com.intellij.openapi.roots.ui.configuration.libraryEditor; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.ide.util.ChooseElementsDialog; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -36,6 +37,10 @@ public class ChooseModulesDialog extends ChooseElementsDialog { super(parent, items, title, null, true); } + public ChooseModulesDialog(Component parent, List items, String title, @Nullable String description) { + super(parent, items, title, description, true); + } + public ChooseModulesDialog(final Project project, final List items, final String title, final String description) { super(project, items, title, description, true); } diff --git a/platform/platform-resources-en/src/messages/ProjectBundle.properties b/platform/platform-resources-en/src/messages/ProjectBundle.properties index 66375fb926c4..f091a77df3ce 100644 --- a/platform/platform-resources-en/src/messages/ProjectBundle.properties +++ b/platform/platform-resources-en/src/messages/ProjectBundle.properties @@ -225,7 +225,8 @@ classpath.add.new.library.action=New Library... classpath.add.simple.module.library.action=Single-Entry Module Library... classpath.add.library.action=Library... classpath.add.module.dependency.action=Module Dependency... -classpath.chooser.title.add.module.dependency=Choose Dependent Modules +classpath.chooser.title.add.module.dependency=Choose Modules +classpath.chooser.description.add.module.dependency=Select the modules the current module should depend on classpath.title.adding.dependency=Adding dependency classpath.message.library.already.added=Library ''{0}'' already added to this module message.no.module.dependency.candidates=Found no modules to depend on From 9ba4d4bb8a823c765c30278b02f88f9cd9b0fc5c Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Mar 2011 12:53:04 +0300 Subject: [PATCH 83/95] cleanup --- .../execution/console/LanguageConsoleImpl.java | 1 + .../intellij/internal/psiView/PsiViewerDialog.java | 3 ++- .../fixtures/impl/CodeInsightTestFixtureImpl.java | 1 + .../util/testSrc/com/intellij/util/Assertion.java | 14 +++++++------- .../jetbrains/idea/maven/dom/MavenDomTestCase.java | 1 + 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index 6e5151894664..4a58c854a986 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -417,6 +417,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { private static void duplicateHighlighters(MarkupModel to, MarkupModel from, int offset, TextRange textRange) { for (RangeHighlighter rangeHighlighter : from.getAllHighlighters()) { + if (!rangeHighlighter.isValid()) continue; final int localOffset = textRange.getStartOffset(); final int start = Math.max(rangeHighlighter.getStartOffset(), localOffset) - localOffset; final int end = Math.min(rangeHighlighter.getEndOffset(), textRange.getEndOffset()) - localOffset; diff --git a/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java b/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java index d4a9586fe297..1dd56eedd869 100644 --- a/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java +++ b/platform/lang-impl/src/com/intellij/internal/psiView/PsiViewerDialog.java @@ -59,6 +59,7 @@ import com.intellij.ui.TitledBorderWithMnemonic; import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.components.JBList; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; @@ -869,7 +870,7 @@ public class PsiViewerDialog extends DialogWrapper implements DataProvider { } public void clearSelection() { - if (myHighlighter != null && Arrays.asList(myEditor.getMarkupModel().getAllHighlighters()).contains(myHighlighter)) { + if (myHighlighter != null && ArrayUtil.contains(myHighlighter, myEditor.getMarkupModel().getAllHighlighters())) { myHighlighter.dispose(); myHighlighter = null; } 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 003e446c9749..7ac2cc1acdc6 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -788,6 +788,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } for (final RangeHighlighter highlighter : myEditor.getDocument().getMarkupModel(project).getAllHighlighters()) { + if (!highlighter.isValid()) continue; addGutterIconRenderer(highlighter.getGutterIconRenderer(), highlighter.getStartOffset(), result); } return ContainerUtil.concat(result.values()); diff --git a/platform/util/testSrc/com/intellij/util/Assertion.java b/platform/util/testSrc/com/intellij/util/Assertion.java index d8be62de91ea..72e727ad5b2b 100644 --- a/platform/util/testSrc/com/intellij/util/Assertion.java +++ b/platform/util/testSrc/com/intellij/util/Assertion.java @@ -126,7 +126,7 @@ public class Assertion extends Assert { compareAll(expected.toArray(), actual); } - public void compareUnordered(Object[] expected, Collection actual) { + public static void compareUnordered(Object[] expected, Collection actual) { assertEquals(expected.length, actual.size()); for (Object exp : expected) { assertTrue(actual.contains(exp)); @@ -142,11 +142,11 @@ public class Assertion extends Assert { //compareAll(expectedList, actualList); } - public void compareUnordered(Collection expected, Collection actual) { + public static void compareUnordered(Collection expected, Collection actual) { compareUnordered(expected.toArray(), actual); } - public void compareUnordered(Collection expected, Object[] actual) { + public static void compareUnordered(Collection expected, Object[] actual) { compareUnordered(expected, new ArrayList(Arrays.asList(actual))); } @@ -210,7 +210,7 @@ public class Assertion extends Assert { count(number, Arrays.asList(objects)); } - public void compareUnordered(Object[] expected, Object[] actual) { + public static void compareUnordered(Object[] expected, Object[] actual) { compareUnordered(expected, new HashSet(Arrays.asList(actual))); } @@ -235,7 +235,7 @@ public class Assertion extends Assert { compareAll(new int[]{element}, actual); } - public void size(int size, Collection collection) { + public static void size(int size, Collection collection) { if (collection.size() != size) { System.err.println("Expected: " + size + " actual: " + collection.size()); } @@ -268,7 +268,7 @@ public class Assertion extends Assert { } } - public int countOccurences(Collection collection, T item) { + public static int countOccurences(Collection collection, T item) { int counter = 0; for (T obj : collection) { if (Comparing.equal(item, obj)) counter++; @@ -280,7 +280,7 @@ public class Assertion extends Assert { containsAll(collection, Arrays.asList(subArray)); } - public void size(int size, Object[] objects) { + public static void size(int size, Object[] objects) { size(size, Arrays.asList(objects)); } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenDomTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenDomTestCase.java index 9ddc18a77c6d..f0cb83c74e1e 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenDomTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenDomTestCase.java @@ -358,6 +358,7 @@ public abstract class MavenDomTestCase extends MavenImportingTestCase { RangeHighlighter[] highlighters = editor.getMarkupModel().getAllHighlighters(); List actual = new ArrayList(); for (RangeHighlighter each : highlighters) { + if (!each.isValid()) continue; int offset = each.getStartOffset(); PsiElement element = getTestPsiFile(file).findElementAt(offset); element = PsiTreeUtil.getParentOfType(element, XmlTag.class); From ba9e4f9bf4207e19ba2febdb6e1a0e7db8b59d60 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Mar 2011 12:54:10 +0300 Subject: [PATCH 84/95] range marker lazy creation --- .../injected/editor/DocumentWindowImpl.java | 4 - .../openapi/editor/ex/DocumentEx.java | 1 - .../openapi/editor/impl/DocumentImpl.java | 8 +- .../intellij/openapi/editor/impl/Getable.java | 31 ++ .../openapi/editor/impl/IntervalTree.java | 1 - .../openapi/editor/impl/IntervalTreeImpl.java | 373 +++++++++++------- .../openapi/editor/impl/MarkupModelImpl.java | 27 +- .../impl/PersistentRangeHighlighterImpl.java | 3 +- .../editor/impl/RangeHighlighterData.java | 24 +- .../editor/impl/RangeHighlighterImpl.java | 42 +- .../editor/impl/RangeHighlighterTree.java | 36 +- .../openapi/editor/impl/RangeMarkerImpl.java | 59 +-- .../openapi/editor/impl/RangeMarkerTree.java | 151 +++---- .../openapi/editor/impl/RedBlackTree.java | 37 +- .../src/com/intellij/mock/MockDocument.java | 4 - .../util/containers/ContainerUtil.java | 29 ++ 16 files changed, 506 insertions(+), 324 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/editor/impl/Getable.java diff --git a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java index 41ee9e967491..06e9afc0ba37 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java @@ -526,10 +526,6 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable return myDelegate.removeRangeMarker(((RangeMarkerWindow)rangeMarker).getDelegate()); } - public void addRangeMarker(@NotNull RangeMarkerEx rangeMarker, int start, int end) { - myDelegate.addRangeMarker(((RangeMarkerWindow)rangeMarker).getDelegate(), start, end); - } - public boolean isInBulkUpdate() { return false; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/DocumentEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/DocumentEx.java index 1d7cff61ee85..6757c21e7371 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/DocumentEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/DocumentEx.java @@ -50,7 +50,6 @@ public interface DocumentEx extends Document { void clearLineModificationFlags(); boolean removeRangeMarker(@NotNull RangeMarkerEx rangeMarker); - void addRangeMarker(@NotNull RangeMarkerEx rangeMarker, int start, int end); boolean isInBulkUpdate(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 734f2f2cb502..838d0b5770f9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -213,15 +213,19 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return myRangeMarkers.removeInterval(rangeMarker); } - public void addRangeMarker(@NotNull RangeMarkerEx rangeMarker, int start, int end) { + public void addRangeMarker(@NotNull RangeMarkerEx rangeMarker, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { ApplicationManagerEx.getApplicationEx().assertReadAccessToDocumentsAllowed(); - myRangeMarkers.addInterval(rangeMarker, start, end, null); + myRangeMarkers.addInterval(rangeMarker, start, end, greedyToLeft, greedyToRight, layer); } @TestOnly public int getRangeMarkersSize() { return myRangeMarkers.size(); } + @TestOnly + public int getRangeMarkersNodeSize() { + return myRangeMarkers.nodeSize(); + } @NotNull public RangeMarker createGuardedBlock(int startOffset, int endOffset) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/Getable.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/Getable.java new file mode 100644 index 000000000000..3ebdfcf3b6b6 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/Getable.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 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.openapi.editor.impl; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +/** + * User: cdr + */ +interface Getable { + T get(); +} +class WeakReferencedGetable extends WeakReference implements Getable { + public WeakReferencedGetable(T referent, ReferenceQueue q) { + super(referent, q); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTree.java index 120878b3c521..2225a43bd179 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTree.java @@ -26,6 +26,5 @@ public interface IntervalTree extends Iterable { boolean processOverlappingWith(int start, int end, @NotNull Processor processor); boolean processOverlappingWith(int offset, @NotNull Processor processor); - Object addInterval(@NotNull T interval, int start, int end, Object data); boolean removeInterval(@NotNull T interval); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index 76a499692d42..c5f7460f6616 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -15,17 +15,16 @@ */ package com.intellij.openapi.editor.impl; -import com.intellij.openapi.editor.ex.RangeMarkerEx; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.Trinity; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; +import gnu.trove.TLongHashSet; import org.jetbrains.annotations.NotNull; -import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; @@ -35,13 +34,14 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * User: cdr */ public abstract class IntervalTreeImpl extends RedBlackTree implements IntervalTree { + protected int keySize; // number of all keys protected final ReadWriteLock l = new ReentrantReadWriteLock(); protected abstract EqualStartIntervalComparator getComparator(); private final ReferenceQueue myReferenceQueue = new ReferenceQueue(); private int deadReferenceCount; - public abstract static class IntervalNode extends RedBlackTree.Node implements MutableInterval { + public abstract class IntervalNode extends RedBlackTree.Node implements MutableInterval { protected int maxEnd; // max of all intervalEnd()s among all children. protected int delta; // delta of startOffset. getStartOffset() = myStartOffset + Sum of deltas up to root protected abstract int computeDeltaUpToRoot(); @@ -53,28 +53,98 @@ public abstract class IntervalTreeImpl extends RedBla public IntervalNode getRight() { return (IntervalNode)super.getRight(); } - @Override public IntervalNode getParent() { return (IntervalNode)super.getParent(); } - } - protected class MyNode extends IntervalNode { + protected class MyNode extends IntervalNode { private volatile int myStart; private volatile int myEnd; private volatile boolean isValid = true; - private final Reference interval; + protected final List> intervals; public MyNode(@NotNull T key, int start, int end) { // maxEnd == 0 so to not disrupt existing maxes - interval = new WeakReference(key,myReferenceQueue); + intervals = new SmartList>(createGetable(key)); myStart = start; myEnd = end; } @Override - public T getKey() { - return interval.get(); + public boolean processAliveKeys(@NotNull Processor processor) { + for (Getable interval : intervals) { + T key = interval.get(); + if (key != null && !processor.process(key)) return false; + } + return true; + } + + @NotNull + @Override + public List getAliveKeys() { + List result = null; + for (Getable ref : intervals) { + T interval = ref.get(); + if (interval == null) continue; + if (result == null) { + result = new ArrayList(intervals.size()); + } + result.add(interval); + } + return result == null ? Collections.emptyList() : result; + } + + public boolean hasAliveKey(boolean purgeDead) { + for (int i = intervals.size() - 1; i >= 0; i--) { + Getable interval = intervals.get(i); + if (interval.get() != null) return true; + if (purgeDead) { + assertUnderWriteLock(); + intervals.remove(i); + assert keySize > 0 : keySize; + keySize--; + } + } + return false; + } + + // removes interval and the node, if node become empty + public boolean removeInterval(@NotNull T key) { + checkBelongsToTheTree(key, true); + assertUnderWriteLock(); + for (int i = intervals.size() - 1; i >= 0; i--) { + Getable interval = intervals.get(i); + T t = interval.get(); + if (t == key) { + intervals.remove(i); + assert keySize > 0 : keySize; + keySize--; + if (intervals.isEmpty()) { + removeNode(this); + return true; + } + return false; + } + } + List aliveKeys = getAliveKeys(); + assert false: "not found interval: "+key +"; "+ aliveKeys; + return false; + } + + private void assertUnderWriteLock() { + if (!VERIFY) return; + String s = l.writeLock().toString(); + assert s.contains("Locked by thread") : s; + } + + public void addInterval(@NotNull T interval) { + assertUnderWriteLock(); + intervals.add(createGetable(interval)); + keySize++; + } + + protected Getable createGetable(@NotNull T interval) { + return new WeakReferencedGetable(interval, myReferenceQueue); } @Override @@ -134,38 +204,12 @@ public abstract class IntervalTreeImpl extends RedBla } } - @Override - protected MyNode createNewNode(T key, int start, int end, Object data) { - return new MyNode(key, start, end); - } + @NotNull + protected abstract MyNode createNewNode(@NotNull T key, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer); + protected abstract MyNode lookupNode(@NotNull T key); - @Override - protected IntervalNode lookupNode(@NotNull T key, Node interval) { - return ((RangeMarkerImpl)key).myNode; - //int delta = 0; - //int delta1 = ((RangeMarkerImpl)key).myNode == null ? 0 : ((RangeMarkerImpl)key).myNode.computeDeltaUpToRoot(); - //List invalid = new ArrayList(); - //IntervalNode root = (IntervalNode)interval; - //while (root != null) { - // delta += root.delta; - // int compResult = compareNodes(((RangeMarkerImpl)key).myNode, delta1, root, delta, invalid); - // if (compResult < 0) { - // root = root.getLeft(); - // } - // else if (compResult > 0) { - // root = root.getRight(); - // } - // else { - // return root; - // } - //} - //deleteNodes(invalid); - //return root; - } - - private int compareNodes(@NotNull IntervalNode i1, int delta1, @NotNull IntervalNode i2, int delta2, List invalid) { - T i2Key = (T)i2.getKey(); - if (i2Key == null) { + private int compareNodes(@NotNull IntervalNode i1, int delta1, @NotNull IntervalNode i2, int delta2, @NotNull List invalid) { + if (!i2.hasAliveKey(false)) { invalid.add(i2); //gced } int start1 = i1.intervalStart() + delta1; @@ -179,8 +223,10 @@ public abstract class IntervalTreeImpl extends RedBla protected interface EqualStartIntervalComparator { int compare(T i1, T i2); + } - protected IntervalTreeImpl.IntervalNode getRoot() { + + protected IntervalNode getRoot() { return (IntervalNode)root; } @@ -200,11 +246,8 @@ public abstract class IntervalTreeImpl extends RedBla if (root == null) return true; if (!process(root.getLeft(), processor, modCountBefore)) return false; - T key = (T)root.getKey(); - if (key != null) { - if (!processor.process(key)) return false; - assert modCount == modCountBefore; - } + if (!root.processAliveKeys(processor)) return false; + assert modCount == modCountBefore; return process(root.getRight(), processor, modCountBefore); } @@ -241,9 +284,8 @@ public abstract class IntervalTreeImpl extends RedBla int myStartOffset = root.intervalStart() + delta; int myEndOffset = root.intervalEnd() + delta; boolean overlaps = Math.max(myStartOffset, start) <= Math.min(myEndOffset, end); - T key = (T)root.getKey(); - if (key != null) { - if (overlaps && !processor.process(key)) return false; + if (overlaps) { + if (!root.processAliveKeys(processor)) return false; assert modCount == modCountBefore; } @@ -285,9 +327,8 @@ public abstract class IntervalTreeImpl extends RedBla int myEndOffset = root.intervalEnd() + delta; boolean overlaps = myStartOffset <= offset && offset < myEndOffset; - T key = (T)root.getKey(); - if (key != null) { - if (overlaps && !processor.process(key)) return false; + if (overlaps) { + if (!root.processAliveKeys(processor)) return false; assert modCount == modCountBefore; } @@ -298,7 +339,7 @@ public abstract class IntervalTreeImpl extends RedBla return processOverlapping(root.getRight(), offset, processor, modCountBefore, delta); } - protected void insert(@NotNull IntervalNode node) { + protected MyNode findOrInsert(@NotNull IntervalNode node) { node.color = Color.RED; node.setParent(null); node.setValid(true); @@ -308,8 +349,6 @@ public abstract class IntervalTreeImpl extends RedBla node.setRight(null); List gced = new ArrayList(); - //T nodeKey = (T)node.getKey(); - //assert nodeKey != null; if (root == null) { root = node; } @@ -320,6 +359,9 @@ public abstract class IntervalTreeImpl extends RedBla while (true) { delta += current.delta; int compResult = compareNodes(node, 0, current, delta, gced); + if (compResult == 0) { + return (MyNode)current; + } if (compResult < 0) { if (current.getLeft() == null) { current.setLeft(node); @@ -327,44 +369,25 @@ public abstract class IntervalTreeImpl extends RedBla } current = current.getLeft(); } - else if (compResult > 0) { + else /*if (compResult > 0)*/ { if (current.getRight() == null) { current.setRight(node); break loop; } current = current.getRight(); } - else { - T i1 = (T)node.getKey(); - T i2 = (T)current.getKey(); - int delta1 = 0; - int delta2 = delta; - assert false : "already inserted: " + - i1 + - ":" + - delta1 + - "; " + - ((RangeMarkerEx)i1).getId() + - " <-> " + - i2 + - ":" + - delta2 + - "; " + - ((RangeMarkerEx)i2).getId() + - " iden=" + - (i1 == i2); - return; - } } node.delta = -delta; node.setParent(current); } - size++; correctMaxUp(node); + onInsertNode(); + keySize += ((MyNode)node).intervals.size(); insertCase1(node); verifyProperties(); deleteNodes(gced); + return (MyNode)node; } private void deleteNodes(List collectedAway) { @@ -382,18 +405,21 @@ public abstract class IntervalTreeImpl extends RedBla } } - @Override - public IntervalNode addInterval(@NotNull T interval, int start, int end, Object data) { + public MyNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { try { l.writeLock().lock(); checkMax(true); processReferenceQueue(); modCount++; - IntervalNode newNode = createNewNode(interval, start, end, data); - insert(newNode); + IntervalNode newNode = createNewNode(interval, start, end, greedyToLeft, greedyToRight, layer); + MyNode insertedNode = findOrInsert(newNode); + if (insertedNode != newNode) { + // merged + insertedNode.addInterval(interval); + } - checkMax(true); // myNode assigned - return newNode; + checkMax(true); + return insertedNode; } finally { l.writeLock().unlock(); @@ -404,10 +430,13 @@ public abstract class IntervalTreeImpl extends RedBla public boolean checkMax(boolean assertInvalid) { if (!VERIFY) return false; Ref allValid = new Ref(true); - AtomicInteger counter = new AtomicInteger(); - checkMax(getRoot(), 0, assertInvalid, allValid, counter); + AtomicInteger keyCounter = new AtomicInteger(); + AtomicInteger nodeCounter = new AtomicInteger(); + TLongHashSet ids = new TLongHashSet(); + checkMax(getRoot(), 0, assertInvalid, allValid, keyCounter, nodeCounter, ids); if (assertInvalid) { - assert size == counter.get() : "size: "+size+"; actual: "+counter; + assert nodeSize() == nodeCounter.get() : "node size: "+ nodeSize() +"; actual: "+nodeCounter; + assert keySize == keyCounter.get() : "key size: "+ keySize +"; actual: "+keyCounter; } return allValid.get(); } @@ -416,15 +445,23 @@ public abstract class IntervalTreeImpl extends RedBla protected Trinity checkMax(IntervalNode root, int deltaUpToRootExclusive, boolean assertInvalid, - Ref allValid, AtomicInteger counter) { + Ref allValid, + AtomicInteger keyCounter, + AtomicInteger nodeCounter, + TLongHashSet ids) { if (root == null) return Trinity.create(Integer.MAX_VALUE,Integer.MIN_VALUE,Integer.MIN_VALUE); - counter.getAndIncrement(); + for (T t : root.getAliveKeys()) { + checkBelongsToTheTree(t, assertInvalid); + assert ids.add(((RangeMarkerImpl)t).getId()) : t; + } + keyCounter.addAndGet(((MyNode)root).intervals.size()); + nodeCounter.incrementAndGet(); int delta = deltaUpToRootExclusive + (root.isValid() ? root.delta : 0); - Trinity l = checkMax(root.getLeft(), delta, assertInvalid, allValid, counter); + Trinity l = checkMax(root.getLeft(), delta, assertInvalid, allValid, keyCounter, nodeCounter, ids); int minLeftStart = l.first; int maxLeftStart = l.second; int maxLeftEnd = l.third; - Trinity r = checkMax(root.getRight(), delta, assertInvalid, allValid, counter); + Trinity r = checkMax(root.getRight(), delta, assertInvalid, allValid, keyCounter, nodeCounter, ids); int maxRightEnd = r.third; int minRightStart = r.first; int maxRightStart = r.second; @@ -434,8 +471,7 @@ public abstract class IntervalTreeImpl extends RedBla return Trinity.create(Math.min(minLeftStart, minRightStart), Math.max(maxLeftStart, maxRightStart), Math.max(maxRightEnd, maxLeftEnd)); } IntervalNode parent = root.getParent(); - T rootKey = (T)root.getKey(); - if (parent != null && assertInvalid && rootKey != null) { + if (parent != null && assertInvalid && root.hasAliveKey(false)) { int c = compareNodes(root, delta, parent, delta - root.delta, new ArrayList()); assert c != 0; assert c < 0 && parent.getLeft() == root || c > 0 && parent.getRight() == root; @@ -465,17 +501,39 @@ public abstract class IntervalTreeImpl extends RedBla return root; } + protected void checkBelongsToTheTree(T interval, boolean assertInvalid) { + if (!VERIFY) return; + MyNode root = lookupNode(interval); + if (root == null) return; + assert !root.intervals.isEmpty(); + + assert root.getTree() == this; + List keys = root.getAliveKeys(); + assert keys.contains(interval) : keys + "; " + interval; + for (T key : keys) { + MyNode node = lookupNode(key); + assert assertInvalid && node == root || !assertInvalid && (node == null || node == root) : node; + assert assertInvalid && node.getTree() == this || !assertInvalid && (node == null || node.getTree() == this) : node; + } + + IntervalNode e = root; + while (e.getParent() != null) e = e.getParent(); + assert e == this.root; // assert the node belongs to our tree + } + @Override public boolean removeInterval(@NotNull T interval) { if (!interval.isValid()) return false; try { l.writeLock().lock(); + checkBelongsToTheTree(interval, true); checkMax(true); processReferenceQueue(); - IntervalNode node = lookupNode(interval, root); + MyNode node = lookupNode(interval); if (node == null) return false; - removeNode(node); + + node.removeInterval(interval); checkMax(true); return true; } @@ -493,33 +551,51 @@ public abstract class IntervalTreeImpl extends RedBla @Override protected void deleteNode(Node n) { - pushDeltaFromRoot((IntervalNode)n); + MyNode node = (MyNode)n; + pushDeltaFromRoot(node); super.deleteNode(n); + + keySize -= node.intervals.size(); + assert keySize >= 0 : keySize; } - protected static void pushDelta(IntervalNode root) { - if (root == null || !root.isValid()) return; + @Override + public int size() { + return keySize; + } + + // returns true if some delta was or became not null + protected boolean pushDelta(IntervalNode root) { + if (root == null || !root.isValid()) return false; int delta = root.delta; if (delta != 0) { root.setIntervalStart(root.intervalStart() + delta); root.setIntervalEnd(root.intervalEnd() + delta); root.maxEnd += delta; root.delta = 0; - incDelta(root.getLeft(), delta); + //noinspection NonShortCircuitBooleanExpression + return + incDelta(root.getLeft(), delta) | + incDelta(root.getRight(), delta); + } + return false; + } + + // returns true if some delta was or became not null + private boolean incDelta(IntervalNode root, int delta) { + if (root == null) return false; + if (root.isValid()) { + int newDelta = root.delta += delta; + return newDelta != 0; + } + else { + //noinspection NonShortCircuitBooleanExpression + return + incDelta(root.getLeft(), delta) | incDelta(root.getRight(), delta); } } - private static void incDelta(IntervalNode root, int delta) { - if (root == null) return; - if (root.isValid()) { - root.delta += delta; - } - else { - incDelta(root.getLeft(), delta); - incDelta(root.getRight(), delta); - } - } @Override protected IntervalNode swapWithMaxPred(Node root, Node maxPred) { checkMax(false); @@ -546,7 +622,6 @@ public abstract class IntervalTreeImpl extends RedBla checkMax(false); return a; } - private void swapNodes(IntervalNode n1, IntervalNode n2) { IntervalNode l1 = n1.getLeft(); IntervalNode r1 = n1.getRight(); @@ -580,7 +655,7 @@ public abstract class IntervalTreeImpl extends RedBla if (r2 != null) r2.setParent(n1); } - protected static int maxEndOf(IntervalNode node, int deltaUpToRootExclusive) { + private int maxEndOf(IntervalNode node, int deltaUpToRootExclusive) { if (node == null) { return 0; } @@ -591,14 +666,14 @@ public abstract class IntervalTreeImpl extends RedBla } // max of n.left's maxend, n.right's maxend and its own interval endOffset - protected static void correctMax(@NotNull IntervalNode node, int deltaUpToRoot) { + protected void correctMax(@NotNull IntervalNode node, int deltaUpToRoot) { if (!node.isValid()) return; int realMax = Math.max(Math.max(maxEndOf(node.getLeft(), deltaUpToRoot), maxEndOf(node.getRight(), deltaUpToRoot)), deltaUpToRoot + node.intervalEnd()); node.maxEnd = realMax - deltaUpToRoot; } - private static void correctMaxUp(IntervalNode node) { + private void correctMaxUp(IntervalNode node) { int delta = node == null ? 0 : node.computeDeltaUpToRoot(); while (node != null) { if (node.isValid()) { @@ -720,37 +795,39 @@ public abstract class IntervalTreeImpl extends RedBla final int modCountBefore = modCount; return new Iterator() { private IntervalNode node = firstNode; - private T element = (T)firstNode.getKey(); + private Iterator iteratorInCurrentList = firstNode.getAliveKeys().iterator(); { // find first non-null key - while (element == null) { + while (!iteratorInCurrentList.hasNext()) { moveNext(); if (node == null) break; } } public boolean hasNext() { - return element != null; + Iterator it = iteratorInCurrentList; + return it != null && it.hasNext(); } public T next() { assert modCount == modCountBefore : "Must not modify range markers during iterate"; - if (node == null || element == null) throw new NoSuchElementException(); - T current = element; + if (node == null || iteratorInCurrentList == null || !iteratorInCurrentList.hasNext()) throw new NoSuchElementException(); + T current = iteratorInCurrentList.next(); moveNext(); return current; } private void moveNext() { + if (iteratorInCurrentList != null && iteratorInCurrentList.hasNext()) return; while (true) { node = getNextNode(); if (node == null) { - element = null; + iteratorInCurrentList = null; break; } - element = (T)node.getKey(); - if (element != null) break; + iteratorInCurrentList = node.getAliveKeys().iterator(); + if (iteratorInCurrentList.hasNext()) break; } } @@ -793,14 +870,38 @@ public abstract class IntervalTreeImpl extends RedBla l.writeLock().unlock(); } } - - private static void normalize(IntervalNode root) { + private void normalize(IntervalNode root) { if (root == null) return; pushDelta(root); normalize(root.getLeft()); normalize(root.getRight()); } + public void changeData(T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + try { + l.writeLock().lock(); + + MyNode node = lookupNode(interval); + if (node == null) return; + int before = size(); + boolean nodeRemoved = node.removeInterval(interval); + assert nodeRemoved || !node.intervals.isEmpty(); + + MyNode insertedNode = addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); + assert node != insertedNode; + + int after = size(); + // can be gced + assert before >= after : before +";" + after; + checkBelongsToTheTree(interval, true); + checkMax(true); + } + finally { + l.writeLock().unlock(); + } + } + + // called under write lock private void processReferenceQueue() { int dead = 0; @@ -821,35 +922,19 @@ public abstract class IntervalTreeImpl extends RedBla deleteNodes(gced); } - private static void collectGced(IntervalNode root, List gced) { + private void collectGced(IntervalNode root, List gced) { if (root == null) return; - if (root.getKey() == null) gced.add(root); + if (!root.hasAliveKey(true)) gced.add(root); collectGced(root.getLeft(), gced); collectGced(root.getRight(), gced); } - public void changeAttribute(@NotNull IntervalNode node, @NotNull Runnable changeAttributes) { - normalize(); - try { - l.writeLock().lock(); - checkMax(true); - removeNode(node); - changeAttributes.run(); - insert(node); - checkMax(true); - } - finally { - l.writeLock().unlock(); - } - } - private void printSorted() { printSorted(getRoot());} - private static void printSorted(IntervalNode root) { + private void printSorted(IntervalNode root) { if (root == null) return; printSorted(root.getLeft()); System.out.println(root); printSorted(root.getRight()); } - } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index 04812916c5e3..c3efa8a61aed 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -35,9 +35,7 @@ import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.util.CommonProcessors; -import com.intellij.util.Consumer; -import com.intellij.util.Processor; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -99,6 +97,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx return offset; } + // NB: Can return invalid highlighters @NotNull public RangeHighlighter[] getAllHighlighters() { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -123,16 +122,11 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx ApplicationManager.getApplication().assertIsDispatchThread(); RangeHighlighterEx highlighter = isPersistent ? new PersistentRangeHighlighterImpl(this, startOffset, layer, targetArea, textAttributes) - : new RangeHighlighterImpl(this, startOffset, endOffset, layer, targetArea, textAttributes); + : new RangeHighlighterImpl(this, startOffset, endOffset, layer, targetArea, textAttributes, false, false); myCachedHighlighters = null; if (changeAttributesAction != null) { - if (isPersistent) { - ((PersistentRangeHighlighterImpl)highlighter).changeAttributesInBatch(changeAttributesAction); - } - else { - ((RangeHighlighterImpl)highlighter).changeAttributesInBatch(changeAttributesAction); - } + ((RangeHighlighterImpl)highlighter).changeAttributesNoEvents(changeAttributesAction); } fireAfterAdded(highlighter); return highlighter; @@ -141,17 +135,20 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @Override public void changeAttributesInBatch(@NotNull RangeHighlighterEx highlighter, @NotNull Consumer changeAttributesAction) { ApplicationManager.getApplication().assertIsDispatchThread(); - boolean changed = highlighter instanceof PersistentRangeHighlighterImpl - ? ((PersistentRangeHighlighterImpl)highlighter).changeAttributesInBatch(changeAttributesAction) - : ((RangeHighlighterImpl)highlighter).changeAttributesInBatch(changeAttributesAction); + boolean changed = ((RangeHighlighterImpl)highlighter).changeAttributesNoEvents(changeAttributesAction); if (changed) { fireAttributesChanged(highlighter); } } - void addRangeHighlighter(RangeHighlighterEx marker, int start, int end, RangeHighlighterData data) { + IntervalTreeImpl.IntervalNode addRangeHighlighter(RangeHighlighterEx marker, + int start, + int end, + boolean greedyToLeft, + boolean greedyToRight, + int layer) { ApplicationManager.getApplication().assertIsDispatchThread(); - myHighlighterTree.addInterval(marker, start, end, data); + return myHighlighterTree.addInterval(marker, start, end, greedyToLeft, greedyToRight, layer); } @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java index 30b1aedf7f52..55b3bb8c3d9a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/PersistentRangeHighlighterImpl.java @@ -34,7 +34,8 @@ class PersistentRangeHighlighterImpl extends RangeHighlighterImpl implements Ran int layer, @NotNull HighlighterTargetArea target, TextAttributes textAttributes) { - super(model, model.getDocument().getLineStartOffset(model.getDocument().getLineNumber(offset)), model.getDocument().getLineEndOffset(model.getDocument().getLineNumber(offset)),layer, target, textAttributes); + super(model, model.getDocument().getLineStartOffset(model.getDocument().getLineNumber(offset)), model.getDocument().getLineEndOffset(model.getDocument().getLineNumber(offset)),layer, target, textAttributes, + false, false); setLine(model.getDocument().getLineNumber(offset)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterData.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterData.java index fc498a3e15f4..24d1ebec98ee 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterData.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterData.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.markup.*; @@ -30,7 +31,6 @@ import java.awt.*; */ abstract class RangeHighlighterData { private final MarkupModel myModel; - private final int myLayer; private final HighlighterTargetArea myTargetArea; private TextAttributes myTextAttributes; private LineMarkerRenderer myLineMarkerRenderer; @@ -46,12 +46,10 @@ abstract class RangeHighlighterData { int myLine; // for PersistentRangeHighlighterImpl only RangeHighlighterData(@NotNull MarkupModel model, - int layer, @NotNull HighlighterTargetArea target, TextAttributes textAttributes) { myTextAttributes = textAttributes; myTargetArea = target; - myLayer = layer; myModel = model; if (textAttributes != null) { myErrorStripeColor = textAttributes.getErrorStripeColor(); @@ -73,10 +71,6 @@ abstract class RangeHighlighterData { } } - public int getLayer() { - return myLayer; - } - public HighlighterTargetArea getTargetArea() { return myTargetArea; } @@ -127,6 +121,7 @@ abstract class RangeHighlighterData { } public void setErrorStripeTooltip(Object tooltipObject) { + ApplicationManager.getApplication().assertIsDispatchThread(); Object old = myErrorStripeTooltip; myErrorStripeTooltip = tooltipObject; if (!Comparing.equal(old, tooltipObject)) { @@ -139,6 +134,7 @@ abstract class RangeHighlighterData { } public void setThinErrorStripeMark(boolean value) { + ApplicationManager.getApplication().assertIsDispatchThread(); boolean old = myErrorStripeMarkIsThin; myErrorStripeMarkIsThin = value; if (old != value) { @@ -223,16 +219,10 @@ abstract class RangeHighlighterData { return Math.min(textLength, document.getLineEndOffset(document.getLineNumber(endOffset)) + 1); } - public void registerMe(int start, int end) { - ((MarkupModelImpl)myModel).addRangeHighlighter(getRangeHighlighter(), start, end,this); - } - - public void unregisterMe() { - myModel.removeHighlighter(getRangeHighlighter()); - } - // returns true if change was detected boolean changeAttributesInBatch(@NotNull Consumer change) { + assert !inBatchChange; + assert !changed; inBatchChange = true; boolean result; try { @@ -245,4 +235,8 @@ abstract class RangeHighlighterData { } return result; } + + public MarkupModel getMarkupModel() { + return myModel; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java index fe847de29778..9f028ebcbb51 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterImpl.java @@ -28,43 +28,64 @@ import java.awt.*; * Implementation of the markup element for the editor and document. * @author max */ -class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx { +class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx, Getable { + private final RangeHighlighterData data; + RangeHighlighterImpl(@NotNull MarkupModel model, int start, int end, int layer, @NotNull HighlighterTargetArea target, - TextAttributes textAttributes) { + TextAttributes textAttributes, boolean greedyToLeft, boolean greedyToRight) { super((DocumentEx)model.getDocument(), start, end,false); - RangeHighlighterData data = new RangeHighlighterData(model, layer, target, textAttributes) { + data = new RangeHighlighterData(model, target, textAttributes) { @NotNull @Override public RangeHighlighterEx getRangeHighlighter() { return RangeHighlighterImpl.this; } }; - data.registerMe(start, end); + + registerInTree(start, end, greedyToLeft, greedyToRight, layer); + } + + @Override + public void setGreedyToLeft(boolean greedy) { + if (!isValid() || greedy == isGreedyToLeft()) return; + myNode.getTree().changeData(this, getStartOffset(), getEndOffset(), greedy, isGreedyToRight(), getLayer()); + } + + @Override + public void setGreedyToRight(boolean greedy) { + if (!isValid() || greedy == isGreedyToRight()) return; + myNode.getTree().changeData(this, getStartOffset(), getEndOffset(), isGreedyToLeft(), greedy, getLayer()); } protected RangeHighlighterData getData() { - return ((RangeHighlighterTree.RHNode)myNode).data; + return data; } @Override - protected void registerInDocument(int start, int end) { + protected void registerInTree(int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { // we store highlighters in MarkupModel + ((MarkupModelImpl)data.getMarkupModel()).addRangeHighlighter(this, start, end, greedyToLeft, greedyToRight, layer); } @Override - protected boolean unregisterInDocument() { + protected boolean unregisterInTree() { if (myNode == null) return false; // we store highlighters in MarkupModel - getData().unregisterMe(); + getData().getMarkupModel().removeHighlighter(this); myNode = null; return true; } + @Override + public RangeHighlighterImpl get() { + return this; + } + // delegates public TextAttributes getTextAttributes() { return getData().getTextAttributes(); @@ -74,12 +95,13 @@ class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx getData().setTextAttributes(textAttributes); } - boolean changeAttributesInBatch(@NotNull Consumer change) { + boolean changeAttributesNoEvents(@NotNull Consumer change) { return getData().changeAttributesInBatch(change); } public int getLayer() { - return getData().getLayer(); + RangeHighlighterTree.RHNode node = (RangeHighlighterTree.RHNode)myNode; + return node == null ? -1 : node.myLayer; } public HighlighterTargetArea getTargetArea() { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java index fcf92a4c720e..f8fa6ff69c4d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java @@ -28,8 +28,8 @@ public class RangeHighlighterTree extends RangeMarkerTree { public int compare(IntervalNode i1, IntervalNode i2) { RHNode o1 = (RHNode)i1; RHNode o2 = (RHNode)i2; - if (o1.data.getLayer() != o2.data.getLayer()) { - return o2.data.getLayer() - o1.data.getLayer(); + if (o1.myLayer != o2.myLayer) { + return o2.myLayer - o1.myLayer; } boolean greedyL1 = o1.isGreedyToLeft(); boolean greedyL2 = o2.isGreedyToLeft(); @@ -42,9 +42,7 @@ public class RangeHighlighterTree extends RangeMarkerTree { boolean greedyR2 = o2.isGreedyToRight(); if (greedyR1 != greedyR2) return greedyR1 ? -1 : 1; - // for now we tolerate equal range range markers (till lazy creation impl) - d = (int)(o1.getId() - o2.getId()); - return d; + return 0; } }; @@ -57,19 +55,29 @@ public class RangeHighlighterTree extends RangeMarkerTree { return myComparator; } + @NotNull @Override - protected RHNode createNewNode(RangeHighlighterEx key, int start, int end, Object data) { - RHNode node = new RHNode(key, start, end, (RangeHighlighterData)data); - ((RangeMarkerImpl)key).myNode = node; - return node; + protected RHNode createNewNode(@NotNull RangeHighlighterEx key, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + return new RHNode(key, start, end, greedyToLeft, greedyToRight,layer); } class RHNode extends RMNode { - final RangeHighlighterData data; - public RHNode(@NotNull final RangeHighlighterEx key, int start, int end, RangeHighlighterData data) { - super(key, start, end); - this.data = data; + final int myLayer; + + public RHNode(@NotNull final RangeHighlighterEx key, + int start, + int end, + boolean greedyToLeft, + boolean greedyToRight, + int layer) { + super(key, start, end, greedyToLeft, greedyToRight); + myLayer = layer; + } + + // range highlighters are strongly referenced + @Override + protected Getable createGetable(@NotNull RangeHighlighterEx interval) { + return (Getable)interval; } } - } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java index 88e05ac03d34..77d654cfe5d8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java @@ -23,13 +23,22 @@ import com.intellij.openapi.util.UserDataHolderBase; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import java.util.concurrent.atomic.AtomicLong; + public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx, MutableInterval { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerImpl"); protected final DocumentEx myDocument; RangeMarkerTree.RMNode myNode; + private final long myId; + //private static long counter; + private static final AtomicLong counter = new AtomicLong(); + protected RangeMarkerImpl(@NotNull DocumentEx document, int start, int end, boolean register) { + this(document, start, end, register, false, false); + } + private RangeMarkerImpl(@NotNull DocumentEx document, int start, int end, boolean register, boolean greedyToLeft, boolean greedyToRight) { if (start < 0) { throw new IllegalArgumentException("Wrong start: " + start+"; end="+end); } @@ -41,29 +50,38 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx } myDocument = document; + myId = counter.getAndIncrement(); if (register) { - registerInDocument(start, end); + registerInTree(start, end, greedyToLeft, greedyToRight, 0); } } - protected void registerInDocument(int start, int end) { - myNode = null; - myDocument.addRangeMarker(this, start, end); - assert myNode != null; + private static Object createData(boolean greedyToLeft, boolean greedyToRight) { + return (greedyToLeft ? 2 : 0) | (greedyToRight ? 1 : 0); } - protected boolean unregisterInDocument() { + + protected void registerInTree(int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + ((DocumentImpl)myDocument).addRangeMarker(this, start, end, greedyToLeft, greedyToRight, layer); + } + + protected boolean unregisterInTree() { + IntervalTreeImpl tree = myNode.getTree(); + tree.checkMax(true); boolean b = myDocument.removeRangeMarker(this); myNode = null; + tree.checkMax(true); return b; } public long getId() { - return myNode.getId(); + return myId; } @Override public void dispose() { - unregisterInDocument(); + if(isValid()) { + unregisterInTree(); + } } public int getStartOffset() { @@ -85,22 +103,13 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx public void setGreedyToLeft(final boolean greedy) { if (!isValid() || greedy == isGreedyToLeft()) return; - myNode.getTree().changeAttribute(myNode, new Runnable() { - @Override - public void run() { - myNode.setGreedyToLeft(greedy); - } - }); + + myNode.getTree().changeData(this, getStartOffset(), getEndOffset(), greedy, isGreedyToRight(), 0); } public void setGreedyToRight(final boolean greedy) { if (!isValid() || greedy == isGreedyToRight()) return; - myNode.getTree().changeAttribute(myNode, new Runnable() { - @Override - public void run() { - myNode.setGreedyToRight(greedy); - } - }); + myNode.getTree().changeData(this, getStartOffset(), getEndOffset(), isGreedyToLeft(), greedy, 0); } public boolean isGreedyToLeft() { @@ -210,7 +219,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx @NonNls public String toString() { return "RangeMarker" + (isGreedyToLeft() ? "[" : "(") + (isValid() ? "valid" : "invalid") + "," + getStartOffset() + "," + getEndOffset() + ( - isGreedyToRight() ? "]" : ")"); + isGreedyToRight() ? "]" : ")") + " " + getId(); } @Override @@ -241,9 +250,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx if (node == null) { return -1; } - else { - return node.intervalStart(); - } + return node.intervalStart(); } @Override @@ -252,8 +259,6 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx if (node == null) { return -1; } - else { - return node.intervalEnd(); - } + return node.intervalEnd(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index 1c3dd66d76c8..65e4ba599d06 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -20,22 +20,18 @@ import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; import com.intellij.openapi.editor.ex.RangeMarkerEx; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.Segment; -import com.intellij.openapi.util.Trinity; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; /** * User: cdr */ public class RangeMarkerTree extends IntervalTreeImpl { private final PrioritizedDocumentListener myListener; - private final Document myDocument; + final Document myDocument; private final EqualStartIntervalComparator myEqualStartIntervalComparator = new EqualStartIntervalComparator() { @Override public int compare(IntervalNode i1, IntervalNode i2) { @@ -54,9 +50,7 @@ public class RangeMarkerTree extends IntervalTreeImpl extends IntervalTreeImpl checkMax(IntervalNode root, - int deltaUpToRootExclusive, - boolean assertInvalid, - Ref allValid, AtomicInteger counter) { - if (root != null) { - RangeMarkerImpl r = (RangeMarkerImpl)root.getKey(); - if (r != null) { - assert /*r.myNode == null || */r.myNode == root; - assert r.myNode.getTree() == this; - } - } - return super.checkMax(root, deltaUpToRootExclusive, assertInvalid, allValid, counter); - } - - @Override - public IntervalNode addInterval(@NotNull T interval, int start, int end, Object data) { + public MyNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { RangeMarkerImpl marker = (RangeMarkerImpl)interval; marker.setValid(true); - return super.addInterval(interval, start, end, data); - } + RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); + ((RangeMarkerImpl)interval).myNode = node; + + checkBelongsToTheTree(interval, true); - @Override - protected RMNode createNewNode(T key, int start, int end, Object data) { - RMNode node = new RMNode(key, start, end); - ((RangeMarkerImpl)key).myNode = node; return node; } - //private static long counter; - private static final AtomicLong counter = new AtomicLong(); + @NotNull + @Override + protected RMNode createNewNode(@NotNull T key, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + return new RMNode(key, start, end, greedyToLeft, greedyToRight); + } + + @Override + protected void checkBelongsToTheTree(T interval, boolean assertInvalid) { + if (!VERIFY) return; + assert ((RangeMarkerImpl)interval).myDocument == myDocument; + + super.checkBelongsToTheTree(interval, assertInvalid); + } + + @Override + protected MyNode lookupNode(@NotNull T key) { + return ((RangeMarkerImpl)key).myNode; + } + public class RMNode extends MyNode { - private boolean isExpandToLeft = false; - private boolean isExpandToRight = false; - private final long myId; + private final boolean isExpandToLeft; + private final boolean isExpandToRight; - public RMNode(@NotNull T key, int start, int end) { + public RMNode(@NotNull T key, int start, int end, boolean greedyToLeft, boolean greedyToRight) { super(key, start, end); - myId = counter.getAndIncrement(); - //myId = counter++; + isExpandToLeft = greedyToLeft; + isExpandToRight = greedyToRight; } - public void setGreedyToLeft(boolean greedy) { - isExpandToLeft = greedy; - } - - public void setGreedyToRight(boolean greedy) { - isExpandToRight = greedy; + @Override + public boolean processAliveKeys(@NotNull Processor processor) { + return super.processAliveKeys(processor); } public boolean isGreedyToLeft() { @@ -145,8 +135,18 @@ public class RangeMarkerTree extends IntervalTreeImpl extends IntervalTreeImpl affected = new ArrayList(); - updateMarkersOnChange(getRoot(), e, affected); + normalized &= !collectAffectedMarkers(getRoot(), e, affected); checkMax(false); if (!affected.isEmpty()) { @@ -172,7 +171,7 @@ public class RangeMarkerTree extends IntervalTreeImpl extends IntervalTreeImpl aliveKeys = node.getAliveKeys(); + if (aliveKeys.isEmpty()) continue; // collected + RangeMarkerImpl marker = (RangeMarkerImpl)aliveKeys.get(0); marker.setValid(true); //marker.myNode = null; marker.documentChanged(e); if (marker.isValid()) { - insert(node); + RMNode insertedNode = (RMNode)findOrInsert(node); + // can change if two range become the one + if (insertedNode != node) { + // merge happened + for (T interval : aliveKeys) { + insertedNode.addInterval(interval); + } + } + assert marker.isValid(); } } - checkMax(true); } + checkMax(true); IntervalNode root = getRoot(); assert root == null || root.maxEnd + root.delta <= myDocument.getTextLength(); @@ -201,19 +209,20 @@ public class RangeMarkerTree extends IntervalTreeImpl affected) { - if (root == null) return; - pushDelta(root); + // returns true if some delta was or became not null + private boolean collectAffectedMarkers(IntervalNode root, + @NotNull DocumentEvent e, + @NotNull List affected) { + if (root == null) return false; + boolean denorm = pushDelta(root); int maxEnd = root.maxEnd; assert root.isValid(); int offset = e.getOffset(); int affectedEndOffset = offset + e.getOldLength(); - Object key = root.getKey(); - if (key == null) { + boolean hasAliveKeys = root.hasAliveKey(false); + if (!hasAliveKeys) { // marker was garbage collected affected.add(root); } @@ -222,28 +231,31 @@ public class RangeMarkerTree extends IntervalTreeImpl sweepProcessor) { normalize(); return sweep(new Generator() { @@ -252,7 +264,6 @@ public class RangeMarkerTree extends IntervalTreeImpl { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java index c616d49cbeff..88919cc518b9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java @@ -15,8 +15,11 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * User: cdr @@ -24,7 +27,7 @@ import org.jetbrains.annotations.NotNull; public abstract class RedBlackTree { public static boolean VERIFY = false; private static final int INDENT_STEP = 4; - protected int size; + private int nodeSize; // number of nodes protected int modCount; protected Node root; @@ -33,8 +36,6 @@ public abstract class RedBlackTree { verifyProperties(); } - protected abstract Node lookupNode(@NotNull K key, Node root); - protected void rotateLeft(Node n) { Node r = n.getRight(); replaceNode(n, r); @@ -78,7 +79,9 @@ public abstract class RedBlackTree { //oldn.right = null; } - protected abstract Node createNewNode(K key, int start, int end, Object data); + protected void onInsertNode() { + nodeSize++; + } protected void insertCase1(Node n) { if (n.getParent() == null) { @@ -137,12 +140,6 @@ public abstract class RedBlackTree { assert node1 == null || node1.getParent() == null || node1.getParent().getLeft() == node1 || node1.getParent().getRight() == node1; } - public Node delete(@NotNull K key) { - Node n = lookupNode(key, root); - deleteNode(n); - return n; - } - protected void deleteNode(Node n) { modCount++; if (n == null) return; // Key not found, do nothing @@ -175,7 +172,9 @@ public abstract class RedBlackTree { if (nodeColor(root) == Color.RED) { root.color = Color.BLACK; } - size--; + + assert nodeSize > 0 : nodeSize; + nodeSize--; verifyProperties(); } @@ -286,10 +285,10 @@ public abstract class RedBlackTree { System.err.print(" "); } if (n.color == Color.BLACK) { - System.err.println(n.getKey()); + System.err.println(n); } else { - System.err.println("<" + n.getKey() + ">"); + System.err.println("<" + n + ">"); } if (n.getLeft() != null) { printHelper(n.getLeft(), indent + INDENT_STEP); @@ -347,7 +346,10 @@ public abstract class RedBlackTree { this.parent = parent; } - public abstract K getKey(); + public abstract boolean processAliveKeys(@NotNull Processor processor); + @NotNull + public abstract List getAliveKeys(); + public abstract boolean hasAliveKey(boolean purgeDead); } protected static enum Color { @@ -355,7 +357,10 @@ public abstract class RedBlackTree { } public int size() { - return size; + return nodeSize; + } + public int nodeSize() { + return nodeSize; } public void verifyProperties() { @@ -426,6 +431,6 @@ public abstract class RedBlackTree { public void clear() { modCount++; root = null; - size = 0; + nodeSize = 0; } } diff --git a/platform/testFramework/src/com/intellij/mock/MockDocument.java b/platform/testFramework/src/com/intellij/mock/MockDocument.java index 2156531a7f69..c5a84d8011d2 100644 --- a/platform/testFramework/src/com/intellij/mock/MockDocument.java +++ b/platform/testFramework/src/com/intellij/mock/MockDocument.java @@ -287,10 +287,6 @@ public class MockDocument implements DocumentEx { return false; } - @Override - public void addRangeMarker(@NotNull RangeMarkerEx rangeMarker, int start, int end) { - } - @Override public boolean isInBulkUpdate() { return false; diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index f6f7f4979abe..ecfb00ea0c68 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -768,11 +768,29 @@ public class ContainerUtil { } return result; } + @NotNull + public static List map(@NotNull Collection iterable, @NotNull Function mapping) { + List result = new ArrayList(iterable.size()); + for (T t : iterable) { + result.add(mapping.fun(t)); + } + return result; + } @NotNull public static List mapNotNull(@NotNull T[] array, Function mapping) { return mapNotNull(Arrays.asList(array), mapping); } + public static V[] mapNotNull(@NotNull T[] arr, @NotNull Function mapping, @NotNull V[] emptyArray) { + List result = new ArrayList(arr.length); + for (T t : arr) { + V v = mapping.fun(t); + if (v != null) { + result.add(v); + } + } + return result.toArray(emptyArray); + } @NotNull public static List mapNotNull(Iterable iterable, Function mapping) { @@ -785,6 +803,17 @@ public class ContainerUtil { } return result; } + @NotNull + public static List mapNotNull(Collection iterable, Function mapping) { + List result = new ArrayList(iterable.size()); + for (T t : iterable) { + final V o = mapping.fun(t); + if (o != null) { + result.add(o); + } + } + return result; + } @NotNull public static List packNullables(@NotNull T... elements) { From 7725214e6b86434cafe55665c3c25f007542a3d0 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Mar 2011 12:59:08 +0300 Subject: [PATCH 85/95] made getText() work even for invalid action --- .../impl/quickfix/ChangeMethodSignatureFromUsageFix.java | 1 + .../daemon/impl/quickfix/GeneralizeCatchFix.java | 2 +- .../codeInsight/daemon/impl/quickfix/ModifierFix.java | 5 +++-- .../impl/quickfix/ReplaceAddAllArrayToCollectionFix.java | 8 +++----- .../daemon/impl/quickfix/StaticImportMethodFix.java | 9 ++++++--- .../impl/quickfix/VariableAccessFromInnerClassFix.java | 1 - .../daemon/impl/quickfix/WrapExpressionFix.java | 6 +++--- .../codeInsight/intention/impl/BaseIntentionAction.java | 5 +++++ 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java index 04543c0dc731..c446d083b469 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java @@ -91,6 +91,7 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction { } private static String formatTypesList(ParameterInfoImpl[] infos, PsiElement context) { + if (infos == null) return null; String result = ""; try { for (ParameterInfoImpl info : infos) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java index 33953721c035..78300d1bcf5b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GeneralizeCatchFix.java @@ -40,7 +40,7 @@ public class GeneralizeCatchFix implements IntentionAction { @NotNull public String getText() { return QuickFixBundle.message("generalize.catch.text", - HighlightUtil.formatType(myCatchParameter.getType()), + HighlightUtil.formatType(myCatchParameter == null ? null : myCatchParameter.getType()), HighlightUtil.formatType(myUnhandledException)); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java index df081d7e7cb0..06b80346c053 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java @@ -30,6 +30,7 @@ import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.psi.util.PsiUtil; import com.intellij.util.VisibilityUtil; import com.intellij.util.IncorrectOperationException; @@ -65,12 +66,12 @@ public class ModifierFix extends IntentionAndQuickFixAction { @NotNull public String getName() { String name = null; - PsiElement parent = myVariable == null ? myModifierList.getParent() : myVariable; + PsiElement parent = myVariable == null ? myModifierList == null ? null : myModifierList.getParent() : myVariable; if (parent instanceof PsiClass) { name = ((PsiClass)parent).getName(); } else { - int options = PsiFormatUtil.SHOW_NAME | (myShowContainingClass ? PsiFormatUtil.SHOW_CONTAINING_CLASS : 0); + int options = PsiFormatUtilBase.SHOW_NAME | (myShowContainingClass ? PsiFormatUtilBase.SHOW_CONTAINING_CLASS : 0); if (parent instanceof PsiMethod) { name = PsiFormatUtil.formatMethod((PsiMethod)parent, PsiSubstitutor.EMPTY, options, 0); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceAddAllArrayToCollectionFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceAddAllArrayToCollectionFix.java index 96804cdc70dc..009754d48537 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceAddAllArrayToCollectionFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceAddAllArrayToCollectionFix.java @@ -101,15 +101,13 @@ public class ReplaceAddAllArrayToCollectionFix implements IntentionAction { @NonNls private String getCollectionsMethodCall() { final PsiExpression qualifierExpression = myMethodCall.getMethodExpression().getQualifierExpression(); + PsiExpression[] expressions = myMethodCall.getArgumentList().getExpressions(); return "java.util.Collections.addAll(" + (qualifierExpression != null ? qualifierExpression.getText() : "this") + - ", " + - myMethodCall.getArgumentList().getExpressions()[0] - .getText() + - ")"; + ", " + (expressions.length == 0 ? "" : expressions[0].getText()) + ")"; } public boolean startInWriteAction() { return true; } -} \ No newline at end of file +} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index cc5d211ae100..cc2a3d8a1a9d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -35,6 +35,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.proximity.PsiProximityComparator; import com.intellij.ui.popup.list.ListPopupImpl; @@ -62,8 +63,10 @@ public class StaticImportMethodFix implements IntentionAction { @NotNull public String getText() { String text = QuickFixBundle.message("static.import.method.text"); - if (candidates.size() == 1) { - text += " '" + PsiFormatUtil.formatMethod(candidates.get(0), PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_CONTAINING_CLASS | PsiFormatUtil.SHOW_FQ_NAME, 0)+"'"; + if (candidates != null && candidates.size() == 1) { + text += " '" + PsiFormatUtil.formatMethod(candidates.get(0), PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | + PsiFormatUtilBase.SHOW_CONTAINING_CLASS | + PsiFormatUtilBase.SHOW_FQ_NAME, 0)+"'"; } else { text += "..."; @@ -243,7 +246,7 @@ public class StaticImportMethodFix implements IntentionAction { final PopupListElementRenderer rightArrow = new PopupListElementRenderer(this); @Override protected ListCellRenderer getListElementRenderer() { - return new MethodCellRenderer(true, PsiFormatUtil.SHOW_NAME){ + return new MethodCellRenderer(true, PsiFormatUtilBase.SHOW_NAME){ @Override protected DefaultListCellRenderer getRightCellRenderer() { final DefaultListCellRenderer moduleRenderer = super.getRightCellRenderer(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java index 56b34711ed8b..ddc5e9fb58db 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableAccessFromInnerClassFix.java @@ -70,7 +70,6 @@ public class VariableAccessFromInnerClassFix implements IntentionAction { case COPY_TO_FINAL: return QuickFixBundle.message("make.final.copy.to.temp", myVariable.getName()); default: - LOG.error("invalid type "+myFixType); return ""; } Collection vars = getVariablesToFix(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java index d4c85df105fb..ff3112b69525 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/WrapExpressionFix.java @@ -56,13 +56,13 @@ public class WrapExpressionFix implements IntentionAction { @NotNull public String getText() { - final PsiMethod wrapper = myExpression.isValid() ? findWrapper(myExpression.getType(), myExpectedType, myPrimitiveExpected) : null; - final String methodPresentation = wrapper != null ? (wrapper.getContainingClass().getName() + "." + wrapper.getName()) : ""; + final PsiMethod wrapper = myExpression.isValid() && myExpectedType != null ? findWrapper(myExpression.getType(), myExpectedType, myPrimitiveExpected) : null; + final String methodPresentation = wrapper != null ? wrapper.getContainingClass().getName() + "." + wrapper.getName() : ""; return QuickFixBundle.message("wrap.expression.using.static.accessor.text", methodPresentation); } @Nullable - private static PsiMethod findWrapper(PsiType type, PsiClassType expectedType, boolean primitiveExpected) { + private static PsiMethod findWrapper(PsiType type, @NotNull PsiClassType expectedType, boolean primitiveExpected) { PsiClass aClass = expectedType.resolve(); if (aClass != null) { PsiType expectedReturnType = expectedType; diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/BaseIntentionAction.java b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/BaseIntentionAction.java index 98c1d0e23d12..31c89570a388 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/intention/impl/BaseIntentionAction.java +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/impl/BaseIntentionAction.java @@ -37,4 +37,9 @@ public abstract class BaseIntentionAction implements IntentionAction { public boolean startInWriteAction() { return true; } + + @Override + public String toString() { + return getText(); + } } From 96cec7510b3f0e4d9e0d78aa02c41a0f017a748c Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Mar 2011 12:59:40 +0300 Subject: [PATCH 86/95] cleanup --- .../quickFix/LightQuickFixTestCase.java | 4 ++-- .../daemon/impl/HighlightInfoComposite.java | 20 +++++++++++++------ .../daemon/impl/ShowIntentionsPass.java | 9 ++++----- .../daemon/impl/quickfix/QuickFixAction.java | 8 ++++---- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java index 121ad9908699..d03a74e5c619 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java @@ -133,12 +133,12 @@ public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase texts.add(intentionAction.getText()); } Collection infos = quickFix.doHighlighting(); - fail("Action with text '" + text + "' is not available in test " + testFullPath+"\nAvailable actions: "+texts+"\n"+actions+"\nErrors:"+infos); + fail("Action with text '" + text + "' is not available in test " + testFullPath+"\nAvailable actions ("+texts.size()+"): "+texts+"\n"+actions+"\nInfos:"+infos); } } else { if (!actionShouldBeAvailable) { - fail("Action '" + text + "' is available in test " + testFullPath); + fail("Action '" + text + "' is available (but must not) in test " + testFullPath); } quickFix.invoke(action); UIUtil.dispatchAllInvocationEvents(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoComposite.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoComposite.java index 0e219704aeb2..822255428fff 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoComposite.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoComposite.java @@ -19,13 +19,18 @@ */ package com.intellij.codeInsight.daemon.impl; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; public class HighlightInfoComposite extends HighlightInfo { @NonNls private static final String HTML_HEADER = ""; @@ -35,21 +40,24 @@ public class HighlightInfoComposite extends HighlightInfo { @NonNls private static final String LINE_BREAK = "\n


"; public HighlightInfoComposite(@NotNull List infos) { - super(infos.get(0).type, infos.get(0).startOffset, infos.get(0).endOffset, createCompositeDescription(infos), - createCompositeTooltip(infos)); + super(infos.get(0).type, infos.get(0).startOffset, infos.get(0).endOffset, createCompositeDescription(infos), createCompositeTooltip(infos)); text = infos.get(0).text; highlighter = infos.get(0).highlighter; group = infos.get(0).group; - quickFixActionMarkers = ContainerUtil.createEmptyCOWList(); - quickFixActionRanges = ContainerUtil.createEmptyCOWList(); + List> markers = null; + List> ranges = null; for (HighlightInfo info : infos) { if (info.quickFixActionMarkers != null) { - quickFixActionMarkers.addAll(info.quickFixActionMarkers); + if (markers == null) markers = new ArrayList>(); + markers.addAll(info.quickFixActionMarkers); } if (info.quickFixActionRanges != null) { - quickFixActionRanges.addAll(info.quickFixActionRanges); + if (ranges == null) ranges = new ArrayList>(); + ranges.addAll(info.quickFixActionRanges); } } + quickFixActionMarkers = markers == null ? ContainerUtil.>createEmptyCOWList() : new CopyOnWriteArrayList>(markers); + quickFixActionRanges = ranges == null ? ContainerUtil.>createEmptyCOWList() : new CopyOnWriteArrayList>(ranges); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java index 1ee2b413a854..49bc17d515d0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java @@ -122,11 +122,10 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { public void doCollectInformation(ProgressIndicator progress) { if (!ApplicationManager.getApplication().isUnitTestMode() && !myEditor.getContentComponent().hasFocus()) return; TemplateState state = TemplateManagerImpl.getTemplateState(myEditor); - if (state == null || state.isFinished()) { - DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject); - getIntentionActionsToShow(); - updateActions(codeAnalyzer); - } + if (state != null && !state.isFinished()) return; + DaemonCodeAnalyzerImpl codeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(myProject); + getIntentionActionsToShow(); + updateActions(codeAnalyzer); } public void doApplyInformationToEditor() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QuickFixAction.java index 00f9650e32cf..441ad5dbea5f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/QuickFixAction.java @@ -114,13 +114,13 @@ public final class QuickFixAction { return result; } - private static void addAvailableActionsForGroups(HighlightInfo info, + private static void addAvailableActionsForGroups(@NotNull HighlightInfo info, Editor editor, - PsiFile file, - List outList, + @NotNull PsiFile file, + @NotNull List outList, int group, int offset) { - if (info == null || info.quickFixActionMarkers == null) return; + if (info.quickFixActionMarkers == null) return; if (group != -1 && group != info.group) return; for (Pair pair : info.quickFixActionMarkers) { HighlightInfo.IntentionActionDescriptor actionInGroup = pair.first; From 289526a2099d1ed3ebeb8db35c3550c6a8387ae1 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Mar 2011 13:01:22 +0300 Subject: [PATCH 87/95] interruptibility --- .../daemon/impl/LocalInspectionsPass.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index 498d6a9326be..7e9c84af6981 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -255,7 +255,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass indicator.checkCanceled(); myInfos = new ArrayList(); - addHighlightsFromResults(myInfos); + addHighlightsFromResults(myInfos, indicator); } private void visitPriorityElementsAndInit(@NotNull List tools, @@ -389,7 +389,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass public Collection getHighlights() { List highlights = new ArrayList(); - addHighlightsFromResults(highlights); + addHighlightsFromResults(highlights, new DaemonProgressIndicator()); return highlights; } @@ -397,13 +397,12 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass private HighlightInfo highlightInfoFromDescriptor(@NotNull ProblemDescriptor problemDescriptor, @NotNull HighlightInfoType highlightInfoType, @NotNull String message, - String toolTip) { + String toolTip, PsiElement psiElement) { TextRange textRange = ((ProblemDescriptorImpl)problemDescriptor).getTextRange(); - PsiElement element = problemDescriptor.getPsiElement(); - if (textRange == null || element == null) return null; - boolean isFileLevel = element instanceof PsiFile && textRange.equals(element.getTextRange()); + if (textRange == null || psiElement == null) return null; + boolean isFileLevel = psiElement instanceof PsiFile && textRange.equals(psiElement.getTextRange()); - final HighlightSeverity severity = highlightInfoType.getSeverity(element); + final HighlightSeverity severity = highlightInfoType.getSeverity(psiElement); TextAttributes attributes = mySeverityRegistrar.getTextAttributesBySeverity(severity); return new HighlightInfo(attributes, highlightInfoType, textRange.getStartOffset(), textRange.getEndOffset(), message, toolTip, @@ -435,8 +434,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass HighlightSeverity severity = inspectionProfile.getErrorLevel(HighlightDisplayKey.find(tool.getShortName()), file).getSeverity(); infos.clear(); - createHighlightsForDescriptor(infos, emptyActionRegistered, ilManager, file, thisDocument, tool, severity, descriptor, psiElement, - psiElement.getText()); + createHighlightsForDescriptor(infos, emptyActionRegistered, ilManager, file, thisDocument, tool, severity, descriptor, psiElement); for (HighlightInfo info : infos) { final EditorColorsScheme colorsScheme = getColorsScheme(); UpdateHighlightersUtil.addHighlighterToEditorIncrementally(myProject, myDocument, myFile, myStartOffset, myEndOffset, @@ -516,29 +514,26 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, myStartOffset, myEndOffset, myInfos, getColorsScheme(), getId()); } - private void addHighlightsFromResults(final List outInfos) { + private void addHighlightsFromResults(@NotNull List outInfos, @NotNull ProgressIndicator indicator) { InspectionProfile inspectionProfile = InspectionProjectProfileManager.getInstance(myProject).getInspectionProfile(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); InjectedLanguageManager ilManager = InjectedLanguageManager.getInstance(myProject); Set emptyActionRegistered = new THashSet(); for (Map.Entry> entry : result.entrySet()) { + indicator.checkCanceled(); PsiFile file = entry.getKey(); Document documentRange = documentManager.getDocument(file); if (documentRange == null) continue; List resultList = entry.getValue(); - Map text = new THashMap(resultList.size()); for (InspectionResult inspectionResult : resultList) { + indicator.checkCanceled(); LocalInspectionTool tool = inspectionResult.tool; HighlightSeverity severity = inspectionProfile.getErrorLevel(HighlightDisplayKey.find(tool.getShortName()), file).getSeverity(); for (ProblemDescriptor descriptor : inspectionResult.foundProblems) { + indicator.checkCanceled(); PsiElement element = descriptor.getPsiElement(); - String psiText = element == null ? null : text.get(element); - if (psiText == null && element != null) { - psiText = element.getText(); - //text.put(element, psiText); - } - createHighlightsForDescriptor(outInfos, emptyActionRegistered, ilManager, file, documentRange, tool, severity, descriptor, element, psiText); + createHighlightsForDescriptor(outInfos, emptyActionRegistered, ilManager, file, documentRange, tool, severity, descriptor, element); } } } @@ -551,7 +546,8 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass Document documentRange, LocalInspectionTool tool, HighlightSeverity severity, - ProblemDescriptor descriptor, PsiElement element, String psiText) { + ProblemDescriptor descriptor, + PsiElement element) { if (element == null) return; if (myIgnoreSuppressed && InspectionManagerEx.inspectionResultSuppressed(element, tool)) return; HighlightInfoType level = highlightTypeFromDescriptor(descriptor, severity); @@ -603,7 +599,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass tooltip = "" + XmlStringUtil.escapeString(message) + link + ""; } } - HighlightInfo highlightInfo = highlightInfoFromDescriptor(descriptor, type, plainMessage, tooltip); + HighlightInfo highlightInfo = highlightInfoFromDescriptor(descriptor, type, plainMessage, tooltip,element); if (highlightInfo != null) { registerQuickFixes(tool, descriptor, highlightInfo, emptyActionRegistered); } From c6e450c7ab2955173ac756ae4521994ac970e35b Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 9 Mar 2011 13:02:13 +0300 Subject: [PATCH 88/95] cleanup --- .../src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java index 77d654cfe5d8..8197d311427f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java @@ -56,10 +56,6 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx } } - private static Object createData(boolean greedyToLeft, boolean greedyToRight) { - return (greedyToLeft ? 2 : 0) | (greedyToRight ? 1 : 0); - } - protected void registerInTree(int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { ((DocumentImpl)myDocument).addRangeMarker(this, start, end, greedyToLeft, greedyToRight, layer); } From 9bba9d1baa23c4fff27732f52baac36280e77dac Mon Sep 17 00:00:00 2001 From: Oleg Shpynov Date: Wed, 9 Mar 2011 13:11:08 +0300 Subject: [PATCH 89/95] Remind to register ssh keys for the github account --- .../plugins/github/ui/GithubLoginPanel.form | 15 +++++++++++--- .../github/ui/GithubSettingsPanel.form | 20 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form index 3fc070c35ec8..218243985ea7 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubLoginPanel.form @@ -1,9 +1,9 @@
- + - + @@ -65,7 +65,7 @@ - + @@ -87,6 +87,15 @@ + + + + + +