diff --git a/java/compiler/impl/src/com/intellij/compiler/ant/artifacts/ArtifactsGenerator.java b/java/compiler/impl/src/com/intellij/compiler/ant/artifacts/ArtifactsGenerator.java index e10c152397a4..57b54a7405f1 100644 --- a/java/compiler/impl/src/com/intellij/compiler/ant/artifacts/ArtifactsGenerator.java +++ b/java/compiler/impl/src/com/intellij/compiler/ant/artifacts/ArtifactsGenerator.java @@ -15,10 +15,7 @@ */ package com.intellij.compiler.ant.artifacts; -import com.intellij.compiler.ant.BuildProperties; -import com.intellij.compiler.ant.Comment; -import com.intellij.compiler.ant.GenerationOptions; -import com.intellij.compiler.ant.Generator; +import com.intellij.compiler.ant.*; import com.intellij.compiler.ant.taskdefs.*; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -158,6 +155,7 @@ public class ArtifactsGenerator { final String outputPath = BuildProperties.propertyRef(myContext.getArtifactOutputProperty(artifact)); artifactTarget.add(new Mkdir(outputPath)); + generateTasksForArtifacts(artifact, artifactTarget, true); final DirectoryAntCopyInstructionCreator creator = new DirectoryAntCopyInstructionCreator(outputPath); @@ -170,9 +168,16 @@ public class ArtifactsGenerator { for (Generator tag : copyInstructions) { artifactTarget.add(tag); } + generateTasksForArtifacts(artifact, artifactTarget, false); return artifactTarget; } + private void generateTasksForArtifacts(Artifact artifact, Target artifactTarget, final boolean preprocessing) { + for (ChunkBuildExtension extension : ChunkBuildExtension.EP_NAME.getExtensions()) { + extension.generateTasksForArtifact(myResolvingContext.getProject(), artifact, preprocessing, artifactTarget); + } + } + public List getCleanTargetNames() { final List targets = new ArrayList(); for (Artifact artifact : myAllArtifacts) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/CompilerParsingThread.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/CompilerParsingThread.java index e440d1d8666f..63c851a8cb06 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/CompilerParsingThread.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/CompilerParsingThread.java @@ -27,6 +27,8 @@ import com.intellij.util.StringBuilderSpinAllocator; import org.jetbrains.annotations.NonNls; import java.io.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; /** * @author Eugene Zhuravlev @@ -47,6 +49,8 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { private String myPushBackLine = null; private volatile boolean myProcessExited = false; private final CompileContext myContext; + + private final BlockingQueue myLines = new LinkedBlockingQueue(); public CompilerParsingThread(Process process, OutputParser outputParser, final boolean readErrorStream, boolean trimLines, CompileContext context) { myProcess = process; @@ -60,6 +64,24 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { volatile boolean processing; public void run() { + if (CompileDriver.ourDebugMode) { + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + while (true) { + final String line = readLine(myCompilerOutStreamReader); + if (CompileDriver.ourDebugMode) { + System.out.println("RAW_LIne read: #" + line + "#"); + } + if (line == null) { + myLines.offer(TERMINATION_STRING); + break; + } + myLines.offer(line); + } + } + }); + } processing = true; try { while (true) { @@ -111,7 +133,7 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { myLastReadLine = pushBack; return pushBack; } - final String line = readLine(myCompilerOutStreamReader); + final String line = getNextUnprocessedLine(); if (LOG.isDebugEnabled()) { LOG.debug("LIne read: #" + line + "#"); } @@ -127,6 +149,28 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { return myLastReadLine; } + private String getNextUnprocessedLine() { + if (CompileDriver.ourDebugMode) { + try { + if (TERMINATION_STRING.equals(myLines.peek())) { + return TERMINATION_STRING; + } + final String line = myLines.take(); + if (TERMINATION_STRING.equals(line)) { + myLines.offer(TERMINATION_STRING); // pushback + } + return line; + } + catch (InterruptedException e) { + e.printStackTrace(); + return TERMINATION_STRING; + } + } + else { + return readLine(myCompilerOutStreamReader); + } + } + @Override public void pushBack(String line) { myLastReadLine = null; @@ -144,6 +188,9 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { processCompiledClass(previousPath); } catch (CacheCorruptedException e) { + if (CompileDriver.ourDebugMode) { + e.printStackTrace(); + } myError = e; LOG.info(e); killProcess(); @@ -177,6 +224,9 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { buffer = StringBuilderSpinAllocator.alloc(); } catch (SpinAllocator.AllocatorExhaustedException e) { + if (CompileDriver.ourDebugMode) { + e.printStackTrace(); + } LOG.info(e); buffer = new StringBuilder(); releaseBuffer = false; @@ -220,6 +270,9 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { try { while(!reader.ready()) { if (isProcessTerminated()) { + if (reader.ready()) { + break; + } return -1; } try { @@ -231,7 +284,16 @@ public class CompilerParsingThread implements Runnable, OutputParser.Callback { return reader.read(); } catch (IOException e) { - return -1; // When process terminated Process.getInputStream()'s underlaying stream becomes closed on Linux. + if (CompileDriver.ourDebugMode) { + e.printStackTrace(); + } + return -1; // When process terminated Process.getInputStream()'s underlying stream becomes closed on Linux. + } + catch (Throwable t) { + if (CompileDriver.ourDebugMode) { + t.printStackTrace(); + } + return -1; } } diff --git a/java/compiler/openapi/src/com/intellij/compiler/ant/ChunkBuildExtension.java b/java/compiler/openapi/src/com/intellij/compiler/ant/ChunkBuildExtension.java index eb896db7ffe7..d0318e1d9ac3 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/ant/ChunkBuildExtension.java +++ b/java/compiler/openapi/src/com/intellij/compiler/ant/ChunkBuildExtension.java @@ -20,6 +20,7 @@ import com.intellij.ExtensionPoints; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; +import com.intellij.packaging.artifacts.Artifact; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; @@ -44,6 +45,9 @@ public abstract class ChunkBuildExtension { public void generateProperties(final PropertyFileGenerator generator, final Project project, final GenerationOptions options) { } + public void generateTasksForArtifact(Project project, Artifact artifact, boolean preprocessing, CompositeGenerator generator) { + } + public List getCleanTargetNames(Project project, GenerationOptions genOptions) { return Collections.emptyList(); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LibraryChooserElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LibraryChooserElement.java deleted file mode 100644 index 99c2c8efebd6..000000000000 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/LibraryChooserElement.java +++ /dev/null @@ -1,94 +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. - */ - -/** - * @author cdr - */ -package com.intellij.openapi.roots.ui.configuration; - -import com.intellij.ide.util.ElementsChooser; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.ProjectBundle; -import com.intellij.openapi.roots.LibraryOrderEntry; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.util.Icons; - -import javax.swing.*; -import java.awt.*; - -public class LibraryChooserElement { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.ui.configuration.LibraryChooserElement"); - - private final String myName; - private final Library myLibrary; - private LibraryOrderEntry myOrderEntry; - public static final ElementsChooser.ElementProperties VALID_LIBRARY_ELEMENT_PROPERTIES = new ElementsChooser.ElementProperties() { - public Icon getIcon() { - return Icons.LIBRARY_ICON; - } - public Color getColor() { - return null; - } - }; - public static final ElementsChooser.ElementProperties INVALID_LIBRARY_ELEMENT_PROPERTIES = new ElementsChooser.ElementProperties() { - public Icon getIcon() { - return Icons.LIBRARY_ICON; - } - public Color getColor() { - return Color.RED; - } - }; - - public LibraryChooserElement(Library library, final LibraryOrderEntry orderEntry) { - myLibrary = library; - myOrderEntry = orderEntry; - if (myLibrary == null && myOrderEntry == null) { - LOG.error("Both library and order entry are null"); - myName = ProjectBundle.message("module.libraries.unknown.item"); - } - else { - myName = myLibrary != null? myLibrary.getName() : myOrderEntry.getLibraryName(); - } - } - - public String toString() { - return myName; - } - - public String getName() { - return myName; - } - - public Library getLibrary() { - return myLibrary; - } - - public LibraryOrderEntry getOrderEntry() { - return myOrderEntry; - } - - public void setOrderEntry(LibraryOrderEntry orderEntry) { - myOrderEntry = orderEntry; - } - - public boolean isAttachedToProject() { - return myOrderEntry != null; - } - - public boolean isValid() { - return myLibrary != null; - } -} \ No newline at end of file diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleChooserElement.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleChooserElement.java deleted file mode 100644 index 0831bce4e3ee..000000000000 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleChooserElement.java +++ /dev/null @@ -1,87 +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.openapi.roots.ui.configuration; - -import com.intellij.ide.util.ElementsChooser; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.ModuleOrderEntry; -import com.intellij.openapi.roots.ui.util.CellAppearanceUtils; - -import javax.swing.*; -import java.awt.*; - -/** - * TODO: remove it together witrh DependenciesEditor - */ -public class ModuleChooserElement implements ElementsChooser.ElementProperties{ - private final String myName; - private final Module myModule; - private ModuleOrderEntry myOrderEntry; - - public ModuleChooserElement(Module module, ModuleOrderEntry orderEntry) { - myModule = module; - myOrderEntry = orderEntry; - myName = module != null? module.getName() : orderEntry.getModuleName(); - } - - public Module getModule() { - return myModule; - } - - public ModuleOrderEntry getOrderEntry() { - return myOrderEntry; - } - - public void setOrderEntry(ModuleOrderEntry orderEntry) { - myOrderEntry = orderEntry; - } - - public String getName() { - return myName; - } - - public Icon getIcon() { - if (myModule != null) { - return myModule.getModuleType().getNodeIcon(false); - } - else { - return CellAppearanceUtils.INVALID_ICON; - } - } - - public Color getColor() { - return myModule == null ? Color.RED : null; - } - - public String toString() { - return getName(); - } - - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ModuleChooserElement)) return false; - - final ModuleChooserElement chooserElement = (ModuleChooserElement)o; - - if (!myName.equals(chooserElement.myName)) return false; - - return true; - } - - public int hashCode() { - return myName.hashCode(); - } -} diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java index 866913fb8a3c..8427af7488f6 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactEditorContextImpl.java @@ -169,10 +169,7 @@ public class ArtifactEditorContextImpl implements ArtifactEditorContext { } public List chooseModules(final List modules, final String title) { - ChooseModulesDialog dialog = new ChooseModulesDialog(getProject(), modules, title, null); - dialog.show(); - List selected = dialog.getChosenElements(); - return dialog.isOK() ? selected : Collections.emptyList(); + return new ChooseModulesDialog(getProject(), modules, title, null).showAndGetResult(); } public List chooseLibraries(final String title) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index bea298445334..37d9c74d9e08 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -4,6 +4,7 @@ import com.intellij.codeInsight.generation.GenerateMembersUtil; import com.intellij.codeInsight.generation.OverrideImplementUtil; import com.intellij.codeInsight.generation.PsiGenerationInfo; import com.intellij.codeInsight.generation.PsiMethodMember; +import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElementDecorator; import com.intellij.codeInsight.lookup.LookupItem; import com.intellij.featureStatistics.FeatureUsageTracker; @@ -34,6 +35,8 @@ class ConstructorInsertHandler implements InsertHandler= 0 && plEnd >= 0) { + context.getDocument().deleteString(plStart, plEnd); + PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments(); + } + } + insertParentheses(context, delegate, delegate.getObject(), withTail && isAbstract); DefaultInsertHandler.addImportForItem(context, delegate); 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 4f265740cc16..19a7ae421770 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -79,13 +79,7 @@ class JavaClassNameInsertHandler implements InsertHandler 0) { + if (PsiTreeUtil.getParentOfType(position, PsiDocTag.class) != null && ref.isReferenceTo(psiClass)) { return; } } @@ -132,6 +126,15 @@ class JavaClassNameInsertHandler implements InsertHandler 0) { + return false; + } + final PsiElement prevElement = FilterPositionUtil.searchNonSpaceNonCommentBack(ref); if (prevElement != null && prevElement.getParent() instanceof PsiNewExpression) { 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 a04bc0bf4dcb..5c834c965a1b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -177,6 +177,7 @@ public class JavaCompletionContributor extends CompletionContributor { } if (AFTER_NUMBER_LITERAL.accepts(position)) { + _result.stopHere(); return; } @@ -535,6 +536,15 @@ public class JavaCompletionContributor extends CompletionContributor { final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null && !(ref instanceof PsiReferenceExpression)) { context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";"); + + if (JavaSmartCompletionContributor.AFTER_NEW.accepts(ref)) { + final PsiReferenceParameterList paramList = ref.getParameterList(); + if (paramList != null && paramList.getTextLength() > 0) { + context.getOffsetMap().addOffset(ConstructorInsertHandler.PARAM_LIST_START, paramList.getTextRange().getStartOffset()); + context.getOffsetMap().addOffset(ConstructorInsertHandler.PARAM_LIST_END, paramList.getTextRange().getEndOffset()); + } + } + return; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionStatistician.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionStatistician.java index d782d4137cbc..d05c520a1a67 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionStatistician.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionStatistician.java @@ -23,13 +23,11 @@ import com.intellij.psi.*; import com.intellij.psi.statistics.JavaStatisticsManager; import com.intellij.psi.statistics.StatisticsInfo; import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NonNls; /** * @author peter */ public class JavaCompletionStatistician extends CompletionStatistician{ - @NonNls public static final String CLASS_NAME_COMPLETION_PREFIX = "classNameCompletion#"; public StatisticsInfo serialize(final LookupElement element, final CompletionLocation location) { final Object o = element.getObject(); @@ -76,6 +74,10 @@ public class JavaCompletionStatistician extends CompletionStatistician{ if (!isClass && type == CompletionType.BASIC) return JavaStatisticsManager.createInfo(qualifierType, (PsiMember)o); return StatisticsInfo.EMPTY; } + + if (isClass) { + return JavaStatisticsManager.createInfo(qualifierType, (PsiMember)o); + } } if (qualifierType != null) return StatisticsInfo.EMPTY; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java index 4d9450ad5f64..c8a837d1177a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull; public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends CompletionWeigher { enum MyResult { + className, classLiteral, normal, superMethodParameters, @@ -54,6 +55,10 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends Completio if (object instanceof PsiAnnotationMethod && ((PsiAnnotationMethod)object).getContainingClass().isAnnotationType()) { return MyResult.annoMethod; } + + if (object instanceof PsiClass) { + return MyResult.className; + } } return MyResult.normal; 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 fae7d6f3c6db..8fddf2096830 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 @@ -16,29 +16,18 @@ package com.intellij.codeInsight.daemon.impl.analysis; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.JavaErrorMessages; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; -import com.intellij.codeInsight.daemon.impl.JavaHightlightInfoTypes; -import com.intellij.codeInsight.daemon.impl.actions.SuppressFix; import com.intellij.codeInsight.daemon.impl.quickfix.*; -import com.intellij.codeInsight.intention.EmptyIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; -import com.intellij.codeInspection.InspectionProfile; -import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.SuppressManager; -import com.intellij.codeInspection.ex.InspectionManagerEx; -import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; -import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; import com.intellij.pom.java.LanguageLevel; -import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; @@ -48,7 +37,6 @@ import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -529,21 +517,7 @@ public class GenericsHighlightUtil { return null; } - //precondition: TypeConversionUtil.isAssignable(lType, rType) || expressionAssignable - public static HighlightInfo checkRawToGenericAssignment(PsiType lType, PsiType rType, @NotNull final PsiElement elementToHighlight) { - if (!PsiUtil.isLanguageLevel5OrHigher(elementToHighlight)) return null; - final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME); - if (!InspectionProjectProfileManager.getInstance(elementToHighlight.getProject()).getInspectionProfile().isToolEnabled(key, - elementToHighlight)) return null; - if (!isRawToGeneric(lType, rType)) return null; - String description = JavaErrorMessages.message("generics.unchecked.assignment", - HighlightUtil.formatType(rType), - HighlightUtil.formatType(lType)); - - return createUncheckedWarning(elementToHighlight, key, description, elementToHighlight); - } - - private static boolean isRawToGeneric(PsiType lType, PsiType rType) { + public static boolean isRawToGeneric(PsiType lType, PsiType rType) { if (lType instanceof PsiPrimitiveType || rType instanceof PsiPrimitiveType) return false; if (lType.equals(rType)) return false; if (lType instanceof PsiArrayType && rType instanceof PsiArrayType) { @@ -628,27 +602,7 @@ public class GenericsHighlightUtil { return false; } - public static HighlightInfo checkUncheckedTypeCast(PsiTypeCastExpression typeCast) { - if (!PsiUtil.isLanguageLevel5OrHigher(typeCast)) return null; - final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME); - if (!InspectionProjectProfileManager.getInstance(typeCast.getProject()).getInspectionProfile().isToolEnabled(key, typeCast)) return null; - final PsiTypeElement typeElement = typeCast.getCastType(); - if (typeElement == null) return null; - final PsiType castType = typeElement.getType(); - final PsiExpression expression = typeCast.getOperand(); - if (expression == null) return null; - final PsiType exprType = expression.getType(); - if (exprType == null) return null; - if (isUncheckedCast(castType, exprType)) { - String description = JavaErrorMessages.message("generics.unchecked.cast", - HighlightUtil.formatType(exprType), - HighlightUtil.formatType(castType)); - return createUncheckedWarning(expression, key, description, typeCast); - } - return null; - } - - private static boolean isUncheckedCast(PsiType castType, PsiType operandType) { + public static boolean isUncheckedCast(PsiType castType, PsiType operandType) { if (TypeConversionUtil.isAssignable(castType, operandType, false)) return false; castType = castType.getDeepComponentType(); @@ -727,74 +681,7 @@ public class GenericsHighlightUtil { ((PsiClassType)rTypeArg).resolve() instanceof PsiTypeParameter; } - public static HighlightInfo checkUncheckedCall(JavaResolveResult resolveResult, PsiCall call) { - if (!PsiUtil.isLanguageLevel5OrHigher(call)) return null; - final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME); - if (!InspectionProjectProfileManager.getInstance(call.getProject()).getInspectionProfile().isToolEnabled(key, call)) return null; - - final PsiMethod method = (PsiMethod)resolveResult.getElement(); - if (method == null) return null; - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - final PsiParameter[] parameters = method.getParameterList().getParameters(); - for (final PsiParameter parameter : parameters) { - final PsiType parameterType = parameter.getType(); - if (parameterType.accept(new PsiTypeVisitor() { - public Boolean visitPrimitiveType(PsiPrimitiveType primitiveType) { - return Boolean.FALSE; - } - - public Boolean visitArrayType(PsiArrayType arrayType) { - return arrayType.getComponentType().accept(this); - } - - public Boolean visitClassType(PsiClassType classType) { - PsiClass psiClass = classType.resolve(); - if (psiClass instanceof PsiTypeParameter) { - return substitutor.substitute((PsiTypeParameter)psiClass) == null ? Boolean.TRUE : Boolean.FALSE; - } - PsiType[] parameters = classType.getParameters(); - for (PsiType parameter : parameters) { - if (parameter.accept(this).booleanValue()) return Boolean.TRUE; - - } - return Boolean.FALSE; - } - - public Boolean visitWildcardType(PsiWildcardType wildcardType) { - PsiType bound = wildcardType.getBound(); - if (bound != null) return bound.accept(this); - return Boolean.FALSE; - } - - public Boolean visitEllipsisType(PsiEllipsisType ellipsisType) { - return ellipsisType.getComponentType().accept(this); - } - }).booleanValue()) { - final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); - PsiType type = elementFactory.createType(method.getContainingClass(), substitutor); - String description = JavaErrorMessages.message("generics.unchecked.call.to.member.of.raw.type", - HighlightUtil.formatMethod(method), - HighlightUtil.formatType(type)); - PsiElement element = call instanceof PsiMethodCallExpression - ? ((PsiMethodCallExpression)call).getMethodExpression() - : call; - return createUncheckedWarning(call, key, description, element); - } - } - return null; - } - - private static HighlightInfo createUncheckedWarning(PsiElement context, HighlightDisplayKey key, String description, PsiElement elementToHighlight) { - final InspectionProfile inspectionProfile = - InspectionProjectProfileManager.getInstance(context.getProject()).getInspectionProfile(); - final LocalInspectionTool tool = - ((LocalInspectionToolWrapper)inspectionProfile.getInspectionTool(UncheckedWarningLocalInspection.SHORT_NAME, elementToHighlight)).getTool(); - if (InspectionManagerEx.inspectionResultSuppressed(context, tool)) return null; - HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(JavaHightlightInfoTypes.UNCHECKED_WARNING, elementToHighlight, description); - QuickFixAction.registerQuickFixAction(highlightInfo, new GenerifyFileFix(elementToHighlight.getContainingFile()), key); - return highlightInfo; - } - + @Nullable public static HighlightInfo checkForeachLoopParameterType(PsiForeachStatement statement) { final PsiParameter parameter = statement.getIterationParameter(); final PsiExpression expression = statement.getIteratedValue(); @@ -811,14 +698,12 @@ public class GenericsHighlightUtil { HighlightInfo highlightInfo = HighlightUtil.checkAssignability(parameterType, itemType, null, new TextRange(start, end)); if (highlightInfo != null) { HighlightUtil.registerChangeVariableTypeFixes(parameter, itemType, highlightInfo); - } else { - highlightInfo = checkRawToGenericAssignment(parameterType, itemType, statement.getIterationParameter()); } return highlightInfo; } @Nullable - private static PsiType getCollectionItemType(PsiExpression expression) { + public static PsiType getCollectionItemType(PsiExpression expression) { final PsiType type = expression.getType(); if (type == null) return null; if (type instanceof PsiArrayType) { @@ -1112,25 +997,11 @@ public class GenericsHighlightUtil { } } - @Nullable - public static HighlightInfo checkUncheckedGenericsArrayCreation(PsiReferenceExpression referenceExpression, PsiElement resolved){ - if (isUncheckedWarning(referenceExpression, resolved, false)) { - final HighlightInfo highlightInfo = - HighlightInfo.createHighlightInfo(HighlightInfoType.WARNING, referenceExpression, "Unchecked generics array creation for varargs parameter"); - QuickFixAction.registerQuickFixAction(highlightInfo, new SuppressFix("unchecked")); - return highlightInfo; - } - return null; - } - - public static boolean isUncheckedWarning(PsiReferenceExpression expression, PsiElement resolve, boolean ignoreSuppressed) { + public static boolean isUncheckedWarning(PsiJavaCodeReferenceElement expression, PsiElement resolve) { if (resolve instanceof PsiMethod) { final PsiMethod psiMethod = (PsiMethod)resolve; final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(expression); - if (!ignoreSuppressed) { - if (SuppressManager.getInstance().isSuppressedFor(expression, "unchecked")) return false; - } if (psiMethod.isVarArgs()) { if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_7) || !AnnotationUtil.isAnnotated(psiMethod, "java.lang.SafeVarargs", false)) { @@ -1140,12 +1011,31 @@ public class GenericsHighlightUtil { final PsiType componentType = ((PsiEllipsisType)varargParameter.getType()).getComponentType(); if (!isReifiableType(componentType)) { final PsiElement parent = expression.getParent(); - if (parent instanceof PsiMethodCallExpression) { - final PsiExpression[] args = ((PsiMethodCallExpression)parent).getArgumentList().getExpressions(); - for (int i = parametersCount - 1; i < args.length; i++) { - if (!isReifiableType(args[i].getType())){ - return true; + if (parent instanceof PsiCall) { + final PsiExpressionList argumentList = ((PsiCall)parent).getArgumentList(); + if (argumentList != null) { + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length == parametersCount) { + final PsiExpression lastArg = args[args.length - 1]; + if (lastArg instanceof PsiReferenceExpression) { + final PsiElement lastArgsResolve = ((PsiReferenceExpression)lastArg).resolve(); + if (lastArgsResolve instanceof PsiParameter) { + if (((PsiParameter)lastArgsResolve).getType() instanceof PsiArrayType) { + return false; + } + } + } else if (lastArg instanceof PsiMethodCallExpression) { + if (lastArg.getType() instanceof PsiArrayType) { + return false; + } + } } + for (int i = parametersCount - 1; i < args.length; i++) { + if (!isReifiableType(args[i].getType())){ + return true; + } + } + return args.length < parametersCount; } } } @@ -1169,14 +1059,22 @@ public class GenericsHighlightUtil { } if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; + final PsiClassType classType = (PsiClassType)PsiUtil.convertAnonymousToBaseType(type); if (classType.isRaw()) { return true; } - if (!classType.hasParameters()) { - return true; + PsiType[] parameters = classType.getParameters(); + + for (PsiType parameter : parameters) { + if (parameter instanceof PsiWildcardType && ((PsiWildcardType)parameter).getBound() == null) { + return true; + } } - return !classType.hasNonTrivialParameters(); + final PsiClass resolved = ((PsiClassType)PsiUtil.convertAnonymousToBaseType(classType)).resolve(); + if (resolved instanceof PsiTypeParameter) { + return false; + } + return parameters.length == 0; } return false; @@ -1253,29 +1151,6 @@ public class GenericsHighlightUtil { return list; } - public static HighlightInfo checkGenericCallWithRawArguments(JavaResolveResult resolveResult, PsiCallExpression callExpression) { - final PsiMethod method = (PsiMethod)resolveResult.getElement(); - if (method == null) return null; - final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); - final PsiExpressionList argumentList = callExpression.getArgumentList(); - if (argumentList == null) return null; - final PsiExpression[] expressions = argumentList.getExpressions(); - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 0) { - for (int i = 0; i < expressions.length; i++) { - PsiParameter parameter = parameters[Math.min(i, parameters.length - 1)]; - final PsiExpression expression = expressions[i]; - final PsiType parameterType = substitutor.substitute(parameter.getType()); - final PsiType expressionType = substitutor.substitute(expression.getType()); - if (expressionType != null) { - final HighlightInfo highlightInfo = checkRawToGenericAssignment(parameterType, expressionType, expression); - if (highlightInfo != null) return highlightInfo; - } - } - } - return null; - } - public static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) { if (refParamList.getTypeArguments().length == 0) return null; JavaResolveResult resolveResult = null; @@ -1334,42 +1209,6 @@ public class GenericsHighlightUtil { return null; } - public static HighlightInfo checkUncheckedOverriding (PsiMethod overrider, final List superMethodSignatures) { - if (!PsiUtil.isLanguageLevel5OrHigher(overrider)) return null; - final HighlightDisplayKey key = HighlightDisplayKey.find(UncheckedWarningLocalInspection.SHORT_NAME); - final InspectionProfile inspectionProfile = - InspectionProjectProfileManager.getInstance(overrider.getProject()).getInspectionProfile(); - if (!inspectionProfile.isToolEnabled(key, overrider)) return null; - final LocalInspectionTool tool = - ((LocalInspectionToolWrapper)inspectionProfile.getInspectionTool(UncheckedWarningLocalInspection.SHORT_NAME, overrider)).getTool(); - if (InspectionManagerEx.inspectionResultSuppressed(overrider, tool)) return null; - final MethodSignature signature = overrider.getSignature(PsiSubstitutor.EMPTY); - for (MethodSignatureBackedByPsiMethod superSignature : superMethodSignatures) { - PsiMethod baseMethod = superSignature.getMethod(); - PsiSubstitutor substitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(signature, superSignature); - if (substitutor == null) substitutor = superSignature.getSubstitutor(); - if (PsiUtil.isRawSubstitutor(baseMethod, superSignature.getSubstitutor())) continue; - final PsiType baseReturnType = substitutor.substitute(baseMethod.getReturnType()); - final PsiType overriderReturnType = overrider.getReturnType(); - if (baseReturnType == null || overriderReturnType == null) return null; - if (isRawToGeneric(baseReturnType, overriderReturnType)) { - final String message = JavaErrorMessages.message("unchecked.overriding.incompatible.return.type", - HighlightUtil.formatType(overriderReturnType), - HighlightUtil.formatType(baseReturnType)); - - final PsiTypeElement returnTypeElement = overrider.getReturnTypeElement(); - LOG.assertTrue(returnTypeElement != null); - final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(JavaHightlightInfoTypes.UNCHECKED_WARNING, returnTypeElement, message); - QuickFixAction.registerQuickFixAction(highlightInfo, - new EmptyIntentionAction(JavaErrorMessages.message("unchecked.overriding")), - key); - - return highlightInfo; - } - } - return null; - } - public static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) { if (!aClass.isEnum()) return null; PsiElement parent = aClass.getParent(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index a68745e64ce9..a1609e04d8be 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -317,13 +317,6 @@ public class HighlightMethodUtil { if (element instanceof PsiMethod && resolveResult.isValidResult()) { TextRange fixRange = getFixRange(methodCall); highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); - - if (highlightInfo == null) { - highlightInfo = GenericsHighlightUtil.checkUncheckedCall(resolveResult, methodCall); - } - if (highlightInfo == null) { - highlightInfo = GenericsHighlightUtil.checkGenericCallWithRawArguments(resolveResult, methodCall); - } } else { PsiMethod resolvedMethod = null; @@ -1271,11 +1264,7 @@ public class HighlightMethodUtil { ChangeStringLiteralToCharInMethodCallFix.registerFixes(constructors, constructorCall, info); } else { - HighlightInfo highlightInfo = GenericsHighlightUtil.checkUncheckedCall(result, constructorCall); - if (highlightInfo != null) { - holder.add(highlightInfo); - return; - } + HighlightInfo highlightInfo; if (constructorCall instanceof PsiNewExpression) { highlightInfo = GenericsHighlightUtil.checkReferenceTypeArgumentList(constructor, ((PsiNewExpression)constructorCall).getTypeArgumentList(), @@ -1284,13 +1273,7 @@ public class HighlightMethodUtil { holder.add(highlightInfo); return; } - highlightInfo = GenericsHighlightUtil.checkGenericCallWithRawArguments(result, (PsiCallExpression)constructorCall); - if (highlightInfo != null) { - holder.add(highlightInfo); - } - //if (PsiUtil.isLanguageLevel7OrHigher(constructorCall)) { - // // todo[anna] check if not diamond - apply corresponding fix - //} + } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 9002d4678cd5..0dc9884a9207 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -459,8 +459,7 @@ public class HighlightUtil { if (rType == null || lType == null || TypeConversionUtil.isAssignable(lType, rType)) return null; } else if (TypeConversionUtil.areTypesAssignmentCompatible(lType, expression)) { - if (lType == null || rType == null) return null; - return GenericsHighlightUtil.checkRawToGenericAssignment(lType, rType, expression); + return null; } if (rType == null) { rType = expression.getType(); @@ -1131,7 +1130,7 @@ public class HighlightUtil { return null; } - private static PsiType sameType(PsiExpression[] expressions) { + public static PsiType sameType(PsiExpression[] expressions) { PsiType type = null; for (PsiExpression expression : expressions) { final PsiType currentType; 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 a0e24bba2741..e4e7d8ebf7c3 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 @@ -635,7 +635,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodIncompatibleThrows(methodSignature, superMethodSignatures, true, method.getContainingClass())); if (!method.hasModifierProperty(PsiModifier.STATIC)) { if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodWeakerPrivileges(methodSignature, superMethodSignatures, true)); - if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkUncheckedOverriding(method, superMethodSignatures)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodOverridesFinal(methodSignature, superMethodSignatures)); } } @@ -836,7 +835,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallMustBeFirstStatement(expression)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkAccessStaticFieldFromEnumConstructor(expression, result)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); - if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkUncheckedGenericsArrayCreation(expression, resolved)); } @Override public void visitReferenceList(PsiReferenceList list) { @@ -917,7 +915,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitTypeCastExpression(PsiTypeCastExpression typeCast) { super.visitTypeCastExpression(typeCast); if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkInconvertibleTypeCast(typeCast)); - if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkUncheckedTypeCast(typeCast)); } @Override public void visitTypeParameterList(PsiTypeParameterList list) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GenerifyFileFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GenerifyFileFix.java index 3276949bb404..11ed68014b75 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GenerifyFileFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/GenerifyFileFix.java @@ -18,14 +18,19 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.CodeInsightUtilBase; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.refactoring.actions.TypeCookAction; import org.jetbrains.annotations.NotNull; -public class GenerifyFileFix implements IntentionAction { +public class GenerifyFileFix implements IntentionAction, LocalQuickFix { private final PsiFile myFile; public GenerifyFileFix(PsiFile file) { @@ -37,11 +42,28 @@ public class GenerifyFileFix implements IntentionAction { return QuickFixBundle.message("generify.text", myFile.getName()); } + @NotNull + @Override + public String getName() { + return getText(); + } + @NotNull public String getFamilyName() { return QuickFixBundle.message("generify.family"); } + @Override + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + if (isAvailable(project, null, null)) { + new WriteCommandAction(project) { + protected void run(Result result) throws Throwable { + invoke(project, FileEditorManager.getInstance(project).getSelectedTextEditor(), descriptor.getPsiElement().getContainingFile()); + } + }.execute(); + } + } + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { return myFile.isValid() && PsiManager.getInstance(project).isInProject(myFile); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableArrayTypeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableArrayTypeFix.java index 4059dafa7a74..4ee0823b3a1c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableArrayTypeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableArrayTypeFix.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.IntentionAndQuickFixAction; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -29,7 +30,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class VariableArrayTypeFix implements IntentionAction { +public class VariableArrayTypeFix extends IntentionAndQuickFixAction { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.VariableArrayTypeFix"); private final PsiVariable myVariable; @@ -93,12 +94,15 @@ public class VariableArrayTypeFix implements IntentionAction { } @NotNull - public String getText() { + @Override + public String getName() { return myTargetType.equals(myVariable.getType()) && myNewExpression != null ? QuickFixBundle.message("change.new.operator.type.text", getNewText(), myTargetType.getCanonicalText(), "") : QuickFixBundle.message("fix.variable.type.text", myVariable.getName(), myTargetType.getCanonicalText()); } + + @NotNull public String getFamilyName() { return myTargetType.equals(myVariable.getType()) && myNewExpression != null ? @@ -113,7 +117,8 @@ public class VariableArrayTypeFix implements IntentionAction { && myInitializer.isValid(); } - public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { + @Override + public void applyFix(Project project, PsiFile file, @Nullable Editor editor) { if (!CodeInsightUtilBase.prepareFileForWrite(myVariable.getContainingFile())) return; try { final PsiElementFactory factory = JavaPsiFacade.getInstance(file.getProject()).getElementFactory(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableTypeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableTypeFix.java index 934505dbf443..9d570812deaf 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableTypeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/VariableTypeFix.java @@ -18,6 +18,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.IntentionAndQuickFixAction; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -27,8 +28,9 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class VariableTypeFix implements IntentionAction { +public class VariableTypeFix extends IntentionAndQuickFixAction { static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.VariableTypeFix"); private final PsiVariable myVariable; @@ -39,8 +41,10 @@ public class VariableTypeFix implements IntentionAction { myReturnType = toReturn != null ? GenericsUtil.getVariableTypeByExpressionType(toReturn) : null; } + @NotNull - public String getText() { + @Override + public String getName() { return QuickFixBundle.message("fix.variable.type.text", getVariable().getName(), getReturnType().getCanonicalText()); @@ -61,7 +65,8 @@ public class VariableTypeFix implements IntentionAction { && !TypeConversionUtil.isVoidType(getReturnType()); } - public void invoke(@NotNull Project project, Editor editor, PsiFile file) { + @Override + public void applyFix(Project project, PsiFile file, @Nullable Editor editor) { if (!CodeInsightUtilBase.prepareFileForWrite(getVariable().getContainingFile())) return; try { getVariable().normalizeDeclaration(); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InsertLiteralUnderscoresAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InsertLiteralUnderscoresAction.java index 40762fde4f14..281a18d78abc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/InsertLiteralUnderscoresAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/InsertLiteralUnderscoresAction.java @@ -39,7 +39,10 @@ public class InsertLiteralUnderscoresAction extends PsiElementBaseIntentionActio !PsiType.FLOAT.equals(type) && !PsiType.DOUBLE.equals(type)) return false; final String text = literalExpression.getText(); - return text != null && !text.contains("_"); + if (text == null || text.contains("_")) return false; + + final String converted = LiteralFormatUtil.format(text, type); + return converted.length() != text.length(); } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java index a916513e5a5d..afd8c91f32b5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ExplicitTypeCanBeDiamondInspection.java @@ -16,6 +16,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.daemon.GroupNames; +import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -71,29 +72,8 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT final PsiTypeElement[] typeElements = parameterList.getTypeParameterElements(); if (typeElements.length > 0) { if (typeElements.length == 1 && typeElements[0].getType() instanceof PsiDiamondType) return; - holder.registerProblem(parameterList, "Redundant type argument #ref #loc", - new LocalQuickFix() { - @NotNull - @Override - public String getName() { - return "Replace with <>"; - } - - @NotNull - @Override - public String getFamilyName() { - return getName(); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiElement psiElement = descriptor.getPsiElement(); - if (psiElement instanceof PsiReferenceParameterList) { - final PsiTypeElement[] parameterElements = ((PsiReferenceParameterList)psiElement).getTypeParameterElements(); - psiElement.deleteChildRange(parameterElements[0], parameterElements[parameterElements.length - 1]); - } - } - }); + holder.registerProblem(parameterList, "Redundant type argument #ref #loc", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, new ReplaceWithDiamondFix()); } } } @@ -101,4 +81,27 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaLocalInspectionT } }; } + + private static class ReplaceWithDiamondFix implements LocalQuickFix, HighPriorityAction { + @NotNull + @Override + public String getName() { + return "Replace with <>"; + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement psiElement = descriptor.getPsiElement(); + if (psiElement instanceof PsiReferenceParameterList) { + final PsiTypeElement[] parameterElements = ((PsiReferenceParameterList)psiElement).getTypeParameterElements(); + psiElement.deleteChildRange(parameterElements[0], parameterElements[parameterElements.length - 1]); + } + } + } } diff --git a/java/java-impl/src/com/intellij/codeInspection/RedundantUncheckedSuppressWarningsInspection.java b/java/java-impl/src/com/intellij/codeInspection/RedundantUncheckedSuppressWarningsInspection.java index 11fe84b84ac5..a63a9b6f99ca 100644 --- a/java/java-impl/src/com/intellij/codeInspection/RedundantUncheckedSuppressWarningsInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/RedundantUncheckedSuppressWarningsInspection.java @@ -17,7 +17,9 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.GroupNames; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil; +import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; @@ -105,8 +107,8 @@ public class RedundantUncheckedSuppressWarningsInspection extends BaseJavaLocalI } private static void checkIfSafeToRemoveWarning(PsiElement suppressElement, PsiElement placeToCheckWarningsIn, ProblemsHolder holder) { - final HashSet warningsElements = new HashSet(); - collectUncheckedWarnings(placeToCheckWarningsIn, true, warningsElements); + final HashSet warningsElements = new HashSet(); + collectUncheckedWarnings(placeToCheckWarningsIn, warningsElements); if (warningsElements.isEmpty()) { final int uncheckedIdx = suppressElement.getText().indexOf(RemoveUncheckedWarningFix.UNCHECKED); holder.registerProblem(suppressElement, @@ -115,14 +117,19 @@ public class RedundantUncheckedSuppressWarningsInspection extends BaseJavaLocalI } } - public static void collectUncheckedWarnings(final PsiElement place, final boolean ignoreSuppressed, final Collection warningsElements) { - place.accept(new JavaRecursiveElementVisitor() { - @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - super.visitReferenceExpression(expression); - if (GenericsHighlightUtil.isUncheckedWarning(expression, expression.resolve(), ignoreSuppressed)) { - warningsElements.add(expression); + public static void collectUncheckedWarnings(final PsiElement place, final Collection warningsElements) { + final UncheckedWarningLocalInspection.UncheckedWarningsVisitor visitor = + new UncheckedWarningLocalInspection.UncheckedWarningsVisitor(false) { + @Override + protected void registerProblem(String message, PsiElement psiElement, LocalQuickFix... quickFix) { + warningsElements.add(psiElement); } + }; + place.accept(new JavaRecursiveElementVisitor(){ + @Override + public void visitElement(PsiElement element) { + super.visitElement(element); + element.accept(visitor); } }); } diff --git a/java/java-impl/src/com/intellij/codeInspection/SafeVarargsCanBeUsedInspection.java b/java/java-impl/src/com/intellij/codeInspection/SafeVarargsCanBeUsedInspection.java index 63eaa00f3c94..c5ed564fa65a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/SafeVarargsCanBeUsedInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/SafeVarargsCanBeUsedInspection.java @@ -68,43 +68,22 @@ public class SafeVarargsCanBeUsedInspection extends BaseJavaLocalInspectionTool if (!PsiUtil.getLanguageLevel(method).isAtLeast(LanguageLevel.JDK_1_7)) return; if (AnnotationUtil.isAnnotated(method, "java.lang.SafeVarargs", false)) return; if (!method.isVarArgs()) return; - if (method.hasModifierProperty(PsiModifier.STATIC) || method.hasModifierProperty(PsiModifier.FINAL)) { - final PsiParameter psiParameter = method.getParameterList().getParameters()[method.getParameterList().getParametersCount() - 1]; - final PsiType componentType = ((PsiEllipsisType)psiParameter.getType()).getComponentType(); - if (GenericsHighlightUtil.isReifiableType(componentType)) { + final PsiParameter psiParameter = method.getParameterList().getParameters()[method.getParameterList().getParametersCount() - 1]; + final PsiType componentType = ((PsiEllipsisType)psiParameter.getType()).getComponentType(); + if (GenericsHighlightUtil.isReifiableType(componentType)) { + return; + } + for (PsiReference reference : ReferencesSearch.search(psiParameter)) { + final PsiElement element = reference.getElement(); + if (element instanceof PsiExpression && !PsiUtil.isAccessedForReading((PsiExpression)element)) { return; } - for (PsiReference reference : ReferencesSearch.search(psiParameter)) { - final PsiElement element = reference.getElement(); - if (element instanceof PsiExpression && !PsiUtil.isAccessedForReading((PsiExpression)element)) { - return; - } - } - final PsiIdentifier nameIdentifier = method.getNameIdentifier(); - if (nameIdentifier != null) { - holder.registerProblem(nameIdentifier, "Possible heap pollution from parametrized vararg type #loc", new LocalQuickFix() { - @NotNull - @Override - public String getName() { - return "Annotate as @SafeVarargs"; - } - - @NotNull - @Override - public String getFamilyName() { - return getName(); - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiElement psiElement = descriptor.getPsiElement(); - if (psiElement instanceof PsiIdentifier) { - final PsiMethod psiMethod = (PsiMethod)psiElement.getParent(); - new AddAnnotationFix("java.lang.SafeVarargs", psiMethod).applyFix(project, descriptor); - } - } - }); - } + } + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier != null) { + holder.registerProblem(nameIdentifier, "Possible heap pollution from parameterized vararg type #loc", + //todo check if can be final or static + method.hasModifierProperty(PsiModifier.FINAL) || method.hasModifierProperty(PsiModifier.STATIC) ? new AnnotateAsSafeVarargsQuickFix() : null); } } @@ -113,4 +92,27 @@ public class SafeVarargsCanBeUsedInspection extends BaseJavaLocalInspectionTool } }; } + + private static class AnnotateAsSafeVarargsQuickFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return "Annotate as @SafeVarargs"; + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement psiElement = descriptor.getPsiElement(); + if (psiElement instanceof PsiIdentifier) { + final PsiMethod psiMethod = (PsiMethod)psiElement.getParent(); + new AddAnnotationFix("java.lang.SafeVarargs", psiMethod).applyFix(project, descriptor); + } + } + } } diff --git a/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java index 6d6657fad91c..7cb7f5eed2ea 100644 --- a/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspection.java @@ -16,20 +16,38 @@ package com.intellij.codeInspection.uncheckedWarnings; -import com.intellij.codeInspection.BaseJavaLocalInspectionTool; -import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInsight.daemon.JavaErrorMessages; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.codeInsight.daemon.impl.quickfix.GenerifyFileFix; +import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction; +import com.intellij.codeInsight.daemon.impl.quickfix.VariableArrayTypeFix; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.QuickFixFactory; +import com.intellij.codeInsight.quickfix.ChangeVariableTypeQuickFixProvider; +import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.UnfairLocalInspectionTool; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.psi.*; +import com.intellij.psi.util.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; /** * User: anna * Date: 17-Feb-2006 */ -public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool implements UnfairLocalInspectionTool { +public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool { @NonNls public static final String SHORT_NAME = "UNCHECKED_WARNING"; public static final String DISPLAY_NAME = InspectionsBundle.message("unchecked.warning"); @NonNls public static final String ID = "unchecked"; + private static final Logger LOG = Logger.getInstance("#" + UncheckedWarningLocalInspection.class); @NotNull public String getGroupDisplayName() { @@ -56,4 +74,303 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool public boolean isEnabledByDefault() { return true; } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { + return new UncheckedWarningsVisitor(isOnTheFly){ + @Override + protected void registerProblem(String message, PsiElement psiElement, LocalQuickFix... quickFix) { + holder.registerProblem(psiElement, message, quickFix); + } + }; + } + + public static abstract class UncheckedWarningsVisitor extends JavaElementVisitor { + private final boolean myOnTheFly; + + public UncheckedWarningsVisitor(boolean onTheFly) { + myOnTheFly = onTheFly; + } + + protected abstract void registerProblem(String message, PsiElement psiElement, LocalQuickFix... quickFix); + + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; + if (GenericsHighlightUtil.isUncheckedWarning(expression, expression.resolve())) { + registerProblem("Unchecked generics array creation for varargs parameter", expression, null); + } + } + + @Override + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; + final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); + if (GenericsHighlightUtil.isUncheckedWarning(classReference, expression.resolveConstructor())) { + registerProblem("Unchecked generics array creation for varargs parameter", classReference, null); + } + } + + @Override + public void visitTypeCastExpression(PsiTypeCastExpression expression) { + super.visitTypeCastExpression(expression); + if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; + final PsiTypeElement typeElement = expression.getCastType(); + if (typeElement == null) return; + final PsiType castType = typeElement.getType(); + final PsiExpression operand = expression.getOperand(); + if (operand == null) return; + final PsiType exprType = operand.getType(); + if (exprType == null) return; + if (!TypeConversionUtil.areTypesConvertible(exprType, castType)) return; + if (GenericsHighlightUtil.isUncheckedCast(castType, exprType)) { + final String description = + JavaErrorMessages.message("generics.unchecked.cast", HighlightUtil.formatType(exprType), HighlightUtil.formatType(castType)); + registerProblem(description, expression, myOnTheFly ? new GenerifyFileFix(operand.getContainingFile()) : null); + } + } + + @Override + public void visitCallExpression(PsiCallExpression callExpression) { + super.visitCallExpression(callExpression); + if (!PsiUtil.isLanguageLevel5OrHigher(callExpression)) return; + final JavaResolveResult result = callExpression.resolveMethodGenerics(); + final String description = getUncheckedCallDescription(result); + if (description != null) { + registerProblem(description, callExpression instanceof PsiMethodCallExpression + ? ((PsiMethodCallExpression)callExpression).getMethodExpression() + : callExpression, myOnTheFly ? new GenerifyFileFix(callExpression.getContainingFile()) : null); + } + else { + final PsiSubstitutor substitutor = result.getSubstitutor(); + final PsiExpressionList argumentList = callExpression.getArgumentList(); + if (argumentList != null) { + final PsiMethod method = (PsiMethod)result.getElement(); + if (method != null) { + final PsiExpression[] expressions = argumentList.getExpressions(); + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length != 0) { + for (int i = 0; i < expressions.length; i++) { + PsiParameter parameter = parameters[Math.min(i, parameters.length - 1)]; + final PsiExpression expression = expressions[i]; + final PsiType parameterType = substitutor.substitute(parameter.getType()); + final PsiType expressionType = substitutor.substitute(expression.getType()); + if (expressionType != null) { + checkRawToGenericsAssignment(expression, parameterType, expressionType, true, myOnTheFly ? new GenerifyFileFix(expression.getContainingFile()) : null); + } + } + } + } + } + } + } + + @Override + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + if (!PsiUtil.isLanguageLevel5OrHigher(variable)) return; + PsiExpression initializer = variable.getInitializer(); + if (initializer == null || initializer instanceof PsiArrayInitializerExpression) return; + final PsiType initializerType = initializer.getType(); + checkRawToGenericsAssignment(initializer, variable.getType(), initializerType, true, myOnTheFly ? getChangeVariableTypeFixes(variable, initializerType) : null); + } + + @Override + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + if (!PsiUtil.isLanguageLevel5OrHigher(statement)) return; + final PsiParameter parameter = statement.getIterationParameter(); + final PsiType parameterType = parameter.getType(); + final PsiType itemType = GenericsHighlightUtil.getCollectionItemType(statement.getIteratedValue()); + if (!PsiUtil.isLanguageLevel5OrHigher(statement)) return; + checkRawToGenericsAssignment(parameter, parameterType, itemType, true, myOnTheFly ? getChangeVariableTypeFixes(parameter, itemType) : null); + } + + @Override + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + if (!PsiUtil.isLanguageLevel5OrHigher(expression)) return; + if (!"=".equals(expression.getOperationSign().getText())) return; + PsiExpression lExpr = expression.getLExpression(); + PsiExpression rExpr = expression.getRExpression(); + if (rExpr == null) return; + PsiType lType = lExpr.getType(); + PsiType rType = rExpr.getType(); + if (rType == null) return; + PsiVariable leftVar = null; + if (lExpr instanceof PsiReferenceExpression) { + PsiElement element = ((PsiReferenceExpression)lExpr).resolve(); + if (element instanceof PsiVariable) { + leftVar = (PsiVariable)element; + } + } + checkRawToGenericsAssignment(rExpr, lType, rType, true, myOnTheFly && leftVar != null ? getChangeVariableTypeFixes(leftVar, rType) : null); + } + + @Override + public void visitArrayInitializerExpression(PsiArrayInitializerExpression arrayInitializer) { + super.visitArrayInitializerExpression(arrayInitializer); + if (!PsiUtil.isLanguageLevel5OrHigher(arrayInitializer)) return; + final PsiType type = arrayInitializer.getType(); + if (!(type instanceof PsiArrayType)) return; + final PsiType componentType = ((PsiArrayType)type).getComponentType(); + + + boolean arrayTypeFixChecked = false; + VariableArrayTypeFix fix = null; + + final PsiExpression[] initializers = arrayInitializer.getInitializers(); + for (PsiExpression expression : initializers) { + final PsiType itemType = expression.getType(); + + if (itemType == null) continue; + if (!TypeConversionUtil.isAssignable(componentType, itemType)) continue; + if (GenericsHighlightUtil.isRawToGeneric(componentType, itemType)) { + String description = JavaErrorMessages.message("generics.unchecked.assignment", + HighlightUtil.formatType(itemType), + HighlightUtil.formatType(componentType)); + if (!arrayTypeFixChecked) { + final PsiType checkResult = HighlightUtil.sameType(initializers); + fix = checkResult != null ? new VariableArrayTypeFix(arrayInitializer, checkResult) : null; + arrayTypeFixChecked = true; + } + + if (fix != null) { + registerProblem(description, expression, (LocalQuickFix)fix); + } + } + } + } + + private void checkRawToGenericsAssignment(PsiElement parameter, + PsiType parameterType, + PsiType itemType, + boolean checkAssignability, + final LocalQuickFix... quickFix) { + if (parameterType == null || itemType == null) return; + if (checkAssignability && !TypeConversionUtil.isAssignable(parameterType, itemType)) return; + if (GenericsHighlightUtil.isRawToGeneric(parameterType, itemType)) { + String description = JavaErrorMessages.message("generics.unchecked.assignment", + HighlightUtil.formatType(itemType), + HighlightUtil.formatType(parameterType)); + registerProblem(description, parameter, quickFix); + } + } + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!PsiUtil.isLanguageLevel5OrHigher(method)) return; + if (!method.isConstructor()) { + List superMethodSignatures = method.getHierarchicalMethodSignature().getSuperSignatures(); + if (!superMethodSignatures.isEmpty() && !method.hasModifierProperty(PsiModifier.STATIC)) { + final MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); + for (MethodSignatureBackedByPsiMethod superSignature : superMethodSignatures) { + PsiMethod baseMethod = superSignature.getMethod(); + PsiSubstitutor substitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(signature, superSignature); + if (substitutor == null) substitutor = superSignature.getSubstitutor(); + if (PsiUtil.isRawSubstitutor(baseMethod, superSignature.getSubstitutor())) continue; + final PsiType baseReturnType = substitutor.substitute(baseMethod.getReturnType()); + final PsiType overriderReturnType = method.getReturnType(); + if (baseReturnType == null || overriderReturnType == null) return; + if (GenericsHighlightUtil.isRawToGeneric(baseReturnType, overriderReturnType)) { + final String message = JavaErrorMessages.message("unchecked.overriding.incompatible.return.type", + HighlightUtil.formatType(overriderReturnType), + HighlightUtil.formatType(baseReturnType)); + + final PsiTypeElement returnTypeElement = method.getReturnTypeElement(); + LOG.assertTrue(returnTypeElement != null); + registerProblem(message, returnTypeElement); + } + } + } + } + } + + @Override + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + if (!PsiUtil.isLanguageLevel5OrHigher(statement)) return; + final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class); + if (method != null) { + final PsiType returnType = method.getReturnType(); + if (returnType != null && returnType != PsiType.VOID) { + final PsiExpression returnValue = statement.getReturnValue(); + if (returnValue != null) { + final PsiType valueType = returnValue.getType(); + if (valueType != null) { + checkRawToGenericsAssignment(returnValue, returnType, valueType, + false, + (LocalQuickFix)QuickFixFactory.getInstance().createMethodReturnFix(method, valueType, true)); + } + } + } + } + } + + + @Nullable + public static String getUncheckedCallDescription(JavaResolveResult resolveResult) { + final PsiMethod method = (PsiMethod)resolveResult.getElement(); + if (method == null) return null; + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + final PsiParameter[] parameters = method.getParameterList().getParameters(); + for (final PsiParameter parameter : parameters) { + final PsiType parameterType = parameter.getType(); + if (parameterType.accept(new PsiTypeVisitor() { + public Boolean visitPrimitiveType(PsiPrimitiveType primitiveType) { + return Boolean.FALSE; + } + + public Boolean visitArrayType(PsiArrayType arrayType) { + return arrayType.getComponentType().accept(this); + } + + public Boolean visitClassType(PsiClassType classType) { + PsiClass psiClass = classType.resolve(); + if (psiClass instanceof PsiTypeParameter) { + return substitutor.substitute((PsiTypeParameter)psiClass) == null ? Boolean.TRUE : Boolean.FALSE; + } + PsiType[] parameters = classType.getParameters(); + for (PsiType parameter : parameters) { + if (parameter.accept(this).booleanValue()) return Boolean.TRUE; + } + return Boolean.FALSE; + } + + public Boolean visitWildcardType(PsiWildcardType wildcardType) { + PsiType bound = wildcardType.getBound(); + if (bound != null) return bound.accept(this); + return Boolean.FALSE; + } + + public Boolean visitEllipsisType(PsiEllipsisType ellipsisType) { + return ellipsisType.getComponentType().accept(this); + } + }).booleanValue()) { + final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory(); + PsiType type = elementFactory.createType(method.getContainingClass(), substitutor); + return JavaErrorMessages.message("generics.unchecked.call.to.member.of.raw.type", + HighlightUtil.formatMethod(method), + HighlightUtil.formatType(type)); + } + } + return null; + } + } + + public static LocalQuickFix[] getChangeVariableTypeFixes(PsiVariable parameter, PsiType itemType) { + final List result = new ArrayList(); + for (ChangeVariableTypeQuickFixProvider fixProvider : Extensions.getExtensions(ChangeVariableTypeQuickFixProvider.EP_NAME)) { + for (IntentionAction action : fixProvider.getFixes(parameter, itemType)) { + if (action instanceof LocalQuickFix) { + result.add((LocalQuickFix)action); + } + } + } + return result.toArray(new LocalQuickFix[result.size()]); + } } diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java b/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java index 6e00723653a6..d7ba93b430ae 100644 --- a/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java +++ b/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java @@ -66,7 +66,8 @@ public class ClassesTreeStructureProvider implements SelectableTreeStructureProv PsiClass[] classes = classOwner.getClasses(); if (fileInRoots(file)) { - if (classes.length == 1 && !(classes[0] instanceof SyntheticElement)) { + if (classes.length == 1 && !(classes[0] instanceof SyntheticElement) && + (file == null || file.getNameWithoutExtension().equals(classes[0].getName()))) { result.add(new ClassTreeNode(myProject, classes[0], settings1)); } else { result.add(new PsiClassOwnerTreeNode(classOwner, settings1)); diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index a7676dc247f2..14527352e906 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -18,6 +18,8 @@ package com.intellij.psi.impl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import gnu.trove.THashMap; import gnu.trove.TObjectHashingStrategy; @@ -25,10 +27,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author ik, dsl @@ -99,11 +98,13 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } private abstract static class SubstitutionVisitorBase extends PsiTypeVisitorEx { + @Override public PsiType visitType(PsiType type) { LOG.assertTrue(false); return null; } + @Override public PsiType visitWildcardType(PsiWildcardType wildcardType) { final PsiType bound = wildcardType.getBound(); if (bound == null) { @@ -135,10 +136,12 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { return PsiWildcardType.createUnbounded(wildcardType.getManager()); } + @Override public PsiType visitPrimitiveType(PsiPrimitiveType primitiveType) { return primitiveType; } + @Override public PsiType visitArrayType(PsiArrayType arrayType) { final PsiType componentType = arrayType.getComponentType(); final PsiType substitutedComponentType = componentType.accept(this); @@ -147,6 +150,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { return new PsiArrayType(substitutedComponentType); } + @Override public PsiType visitEllipsisType(PsiEllipsisType ellipsisType) { final PsiType componentType = ellipsisType.getComponentType(); final PsiType substitutedComponentType = componentType.accept(this); @@ -155,15 +159,26 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { return new PsiEllipsisType(substitutedComponentType); } + @Override public PsiType visitTypeVariable(final PsiTypeVariable var) { return var; } + @Override public PsiType visitBottom(final Bottom bottom) { return bottom; } + @Override public abstract PsiType visitClassType(PsiClassType classType); + + @Override + public PsiType visitDisjunctionType(PsiDisjunctionType disjunctionType) { + final List substituted = ContainerUtil.map(disjunctionType.getDisjunctions(), new Function() { + @Override public PsiType fun(PsiType psiType) { return psiType.accept(SubstitutionVisitorBase.this); } + }); + return new PsiDisjunctionType(substituted, disjunctionType.getManager()); + } } private final SubstitutionVisitor myAddingBoundsSubstitutionVisitor = new SubstitutionVisitor(SubstituteKind.ADD_BOUNDS); diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java index fe1db0118759..ae32fccd1998 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.smartPointers; import com.intellij.openapi.diagnostic.Logger; @@ -26,20 +22,28 @@ import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.impl.source.PsiClassReferenceType; import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NullableFunction; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; import java.util.Map; import java.util.Set; +/** + * @author max + */ public class SmartTypePointerManagerImpl extends SmartTypePointerManager { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.SmartTypePointerManagerImpl"); + private final SmartPointerManager myPsiPointerManager; private final Project myProject; - public SmartTypePointerManagerImpl(SmartPointerManager psiPointerManager, final Project project) { + public SmartTypePointerManagerImpl(final SmartPointerManager psiPointerManager, final Project project) { myPsiPointerManager = psiPointerManager; myProject = project; } @@ -102,26 +106,24 @@ public class SmartTypePointerManagerImpl extends SmartTypePointerManager { return PsiWildcardType.createUnbounded(myManager); } else { + final PsiType type = myBoundPointer.getType(); + assert type != null : myBoundPointer; if (myIsExtending) { - return PsiWildcardType.createExtends(myManager, myBoundPointer.getType()); + return PsiWildcardType.createExtends(myManager, type); } else { - return PsiWildcardType.createSuper(myManager, myBoundPointer.getType()); + return PsiWildcardType.createSuper(myManager, type); } } } } - private static class ClassTypePointer implements SmartTypePointer { private PsiType myType; private final SmartPsiElementPointer myClass; private final Map myMap; - - public ClassTypePointer(PsiType type, - SmartPsiElementPointer aClass, - Map map) { + public ClassTypePointer(PsiType type, SmartPsiElementPointer aClass, Map map) { myType = type; myClass = aClass; myMap = map; @@ -182,15 +184,40 @@ public class SmartTypePointerManagerImpl extends SmartTypePointerManager { } } + private class DisjunctionTypePointer implements SmartTypePointer { + private PsiType myType; + private final List myPointers; + + private DisjunctionTypePointer(final PsiDisjunctionType type) { + myType = type; + myPointers = ContainerUtil.map(type.getDisjunctions(), new Function() { + @Override public SmartTypePointer fun(PsiType psiType) { return createSmartTypePointer(psiType); } + }); + } + + @Override + public PsiType getType() { + if (myType.isValid()) return myType; + + final List types = ContainerUtil.map(myPointers, new NullableFunction() { + @Override public PsiType fun(SmartTypePointer typePointer) { return typePointer.getType(); } + }); + return new PsiDisjunctionType(types, PsiManager.getInstance(myProject)); + } + } + private class SmartTypeCreatingVisitor extends PsiTypeVisitor { + @Override public SmartTypePointer visitPrimitiveType(PsiPrimitiveType primitiveType) { return new SimpleTypePointer(primitiveType); } + @Override public SmartTypePointer visitArrayType(PsiArrayType arrayType) { return new ArrayTypePointer(arrayType, arrayType.getComponentType().accept(this)); } + @Override public SmartTypePointer visitWildcardType(PsiWildcardType wildcardType) { final PsiType bound = wildcardType.getBound(); final SmartTypePointer boundPointer; @@ -203,6 +230,7 @@ public class SmartTypePointerManagerImpl extends SmartTypePointerManager { return new WildcardTypePointer(wildcardType, boundPointer); } + @Override public SmartTypePointer visitClassType(PsiClassType classType) { final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics(); final PsiClass aClass = resolveResult.getElement(); @@ -226,6 +254,10 @@ public class SmartTypePointerManagerImpl extends SmartTypePointerManager { } return new ClassTypePointer(classType, myPsiPointerManager.createSmartPsiElementPointer(aClass), map); } - } + @Override + public SmartTypePointer visitDisjunctionType(PsiDisjunctionType disjunctionType) { + return new DisjunctionTypePointer(disjunctionType); + } + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java index bc34754b5053..b24b1e46c962 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeElementImpl.java @@ -32,6 +32,7 @@ import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PatchedSoftReference; import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -102,7 +103,12 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl cachedType = componentType.createArrayType(); } else { - cachedType = new PsiDisjunctionType(this); + final List typeElements = PsiTreeUtil.getChildrenOfTypeAsList(this, PsiTypeElement.class); + if (typeElements.size() < 2) LOG.error("Incorrect nested type: " + this); + final List types = ContainerUtil.map(typeElements, new Function() { + @Override public PsiType fun(final PsiTypeElement psiTypeElement) { return psiTypeElement.getType(); } + }); + cachedType = new PsiDisjunctionType(types, getManager()); } } else if (elementType == JavaElementType.JAVA_CODE_REFERENCE) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaChangeUtilSupport.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaChangeUtilSupport.java index 69eaa196df72..8dd87bc0b290 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaChangeUtilSupport.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaChangeUtilSupport.java @@ -180,15 +180,18 @@ public class JavaChangeUtilSupport implements TreeGenerator, TreeCopyHandler { return createType(original.getProject(), originalText, null, generated); } if (type instanceof PsiIntersectionType) { - PsiIntersectionType intersectionType = (PsiIntersectionType)type; - LightTypeElement te = new LightTypeElement(original.getManager(), intersectionType.getConjuncts()[0]); + LightTypeElement te = new LightTypeElement(original.getManager(), ((PsiIntersectionType)type).getRepresentative()); + return ChangeUtil.generateTreeElement(te, table, manager); + } + if (type instanceof PsiDisjunctionType) { + LightTypeElement te = new LightTypeElement(original.getManager(), ((PsiDisjunctionType)type).getLeastUpperBound()); return ChangeUtil.generateTreeElement(te, table, manager); } PsiClassType classType = (PsiClassType)type; String text = classType.getPresentableText(); final TreeElement element = createType(original.getProject(), text, original, false); - PsiTypeElementImpl result = (PsiTypeElementImpl)SourceTreeToPsiMap.treeElementToPsi(element); + PsiTypeElementImpl result = SourceTreeToPsiMap.treeToPsiNotNull(element); CodeEditUtil.setNodeGenerated(result, generated); if (generated) { @@ -397,7 +400,7 @@ public class JavaChangeUtilSupport implements TreeGenerator, TreeCopyHandler { case PsiJavaCodeReferenceElementImpl.CLASS_NAME_KIND: case PsiJavaCodeReferenceElementImpl.CLASS_OR_PACKAGE_NAME_KIND: case PsiJavaCodeReferenceElementImpl.CLASS_IN_QUALIFIED_NEW_KIND: - final PsiElement target = ((PsiJavaCodeReferenceElement)SourceTreeToPsiMap.treeElementToPsi(original)).resolve(); + final PsiElement target = SourceTreeToPsiMap.treeToPsiNotNull(original).resolve(); if (target instanceof PsiClass) { ref.putCopyableUserData(REFERENCED_CLASS_KEY, (PsiClass)target); } diff --git a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java index e5b588e196d2..a4ae0cdf045b 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java @@ -40,7 +40,7 @@ import java.util.*; public class TypeSelectorManagerImpl implements TypeSelectorManager { private SmartTypePointer myPointer; private PsiType myDefaultType; - private final PsiExpression myMainOccurence; + private final PsiExpression myMainOccurrence; private final PsiExpression[] myOccurrences; private final PsiType[] myTypesForMain; private final PsiType[] myTypesForAll; @@ -49,10 +49,9 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { private final PsiElementFactory myFactory; private final SmartTypePointerManager mySmartTypePointerManager; private ExpectedTypesProvider.ExpectedClassProvider myOccurrenceClassProvider; - private ExpectedTypesProvider myExpectedTypesProvider; - public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression mainOccurence, PsiExpression[] occurrences) { - this(project, type, null, mainOccurence, occurrences); + public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression mainOccurrence, PsiExpression[] occurrences) { + this(project, type, null, mainOccurrence, occurrences); } public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression[] occurrences) { @@ -63,14 +62,14 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { myFactory = JavaPsiFacade.getInstance(project).getElementFactory(); mySmartTypePointerManager = SmartTypePointerManager.getInstance(project); setDefaultType(type); - myMainOccurence = null; + myMainOccurrence = null; myOccurrences = occurrences; - myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project); + myOccurrenceClassProvider = createOccurrenceClassProvider(); myTypesForAll = getTypesForAll(areTypesDirected); myTypesForMain = PsiType.EMPTY_ARRAY; - myIsOneSuggestion = myTypesForAll.length == 1; + myIsOneSuggestion = myTypesForAll.length == 1; if (myIsOneSuggestion) { myTypeSelector = new TypeSelector(myTypesForAll[0]); } @@ -83,14 +82,13 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { public TypeSelectorManagerImpl(Project project, PsiType type, PsiMethod containingMethod, - PsiExpression mainOccurence, + PsiExpression mainOccurrence, PsiExpression[] occurrences) { myFactory = JavaPsiFacade.getInstance(project).getElementFactory(); mySmartTypePointerManager = SmartTypePointerManager.getInstance(project); setDefaultType(type); - myMainOccurence = mainOccurence; + myMainOccurrence = mainOccurrence; myOccurrences = occurrences; - myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project); myOccurrenceClassProvider = createOccurrenceClassProvider(); myTypesForMain = getTypesForMain(); @@ -149,8 +147,8 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { private ExpectedTypesProvider.ExpectedClassProvider createOccurrenceClassProvider() { final Set occurrenceClasses = new HashSet(); - for (final PsiExpression occurence : myOccurrences) { - final PsiType occurrenceType = occurence.getType(); + for (final PsiExpression occurrence : myOccurrences) { + final PsiType occurrenceType = occurrence.getType(); final PsiClass aClass = PsiUtil.resolveClassInType(occurrenceType); if (aClass != null) { occurrenceClasses.add(aClass); @@ -160,8 +158,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { } private PsiType[] getTypesForMain() { - final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(myMainOccurence, false, myOccurrenceClassProvider, - false); + final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(myMainOccurrence, false, myOccurrenceClassProvider, false); final ArrayList allowedTypes = new ArrayList(); RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() { public void visitType(PsiType aType) { @@ -173,9 +170,8 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { } private void checkIfAllowed(PsiType type) { - if (expectedTypes != null && expectedTypes.length > 0) { - final ExpectedTypeInfo - typeInfo = ExpectedTypesProvider.createInfo(type, ExpectedTypeInfo.TYPE_STRICTLY, type, TailType.NONE); + if (expectedTypes.length > 0) { + final ExpectedTypeInfo typeInfo = ExpectedTypesProvider.createInfo(type, ExpectedTypeInfo.TYPE_STRICTLY, type, TailType.NONE); for (ExpectedTypeInfo expectedType : expectedTypes) { if (expectedType.intersect(typeInfo).length != 0) { allowedTypes.add(type); @@ -196,9 +192,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { private PsiType[] getTypesForAll(final boolean areTypesDirected) { final ArrayList expectedTypesFromAll = new ArrayList(); for (PsiExpression occurrence : myOccurrences) { - - final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(occurrence, false, myOccurrenceClassProvider, - isUsedAfter()); + final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(occurrence, false, myOccurrenceClassProvider, isUsedAfter()); if (expectedTypes.length > 0) { expectedTypesFromAll.add(expectedTypes); } @@ -259,20 +253,22 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { result.add(0, unboxedType); } - if (defaultType instanceof PsiPrimitiveType && myMainOccurence != null) { - final PsiClassType boxedType = ((PsiPrimitiveType)defaultType).getBoxedType(myMainOccurence); + if (defaultType instanceof PsiPrimitiveType && myMainOccurrence != null) { + final PsiClassType boxedType = ((PsiPrimitiveType)defaultType).getBoxedType(myMainOccurrence); if (boxedType != null) { result.remove(boxedType); result.add(0, boxedType); } } - result.add(0, defaultType); + if (!TypeConversionUtil.isComposite(defaultType)) { + result.add(0, defaultType); + } return result; } - public void setAllOccurences(boolean allOccurences) { + public void setAllOccurences(boolean occurrences) { if (myIsOneSuggestion) return; - setTypesAndPreselect(allOccurences ? myTypesForAll : myTypesForMain); + setTypesAndPreselect(occurrences ? myTypesForAll : myTypesForMain); } private void setTypesAndPreselect(PsiType[] types) { diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java index 65f2783627ac..fb1f1494d5ed 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java @@ -34,6 +34,7 @@ import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.IntArrayList; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -49,12 +50,12 @@ public class DuplicatesFinder { private final List myOutputParameters; private final List myPatternAsList; private boolean myMultipleExitPoints = false; - private final ReturnValue myReturnValue; + @Nullable private final ReturnValue myReturnValue; public DuplicatesFinder(PsiElement[] pattern, InputVariables parameters, - ReturnValue returnValue, - List outputParameters + @Nullable ReturnValue returnValue, + @NotNull List outputParameters ) { myReturnValue = returnValue; LOG.assertTrue(pattern.length > 0); @@ -109,6 +110,14 @@ public class DuplicatesFinder { return result; } + @Nullable + public Match isDuplicate(PsiElement element, boolean ignoreParameterTypes) { + annotatePattern(); + Match match = isDuplicateFragment(element, ignoreParameterTypes); + deannotatePattern(); + return match; + } + private void annotatePattern() { for (final PsiElement patternComponent : myPattern) { patternComponent.accept(new JavaRecursiveElementWalkingVisitor() { @@ -146,7 +155,7 @@ public class DuplicatesFinder { private void findPatternOccurrences(List array, PsiElement scope) { PsiElement[] children = scope.getChildren(); for (PsiElement child : children) { - final Match match = isDuplicateFragment(child); + final Match match = isDuplicateFragment(child, false); if (match != null) { array.add(match); continue; @@ -157,7 +166,7 @@ public class DuplicatesFinder { @Nullable - private Match isDuplicateFragment(PsiElement candidate) { + private Match isDuplicateFragment(PsiElement candidate, boolean ignoreParameterTypes) { if (PsiTreeUtil.isAncestor(myPattern[0], candidate, false)) return null; PsiElement sibling = candidate; ArrayList candidates = new ArrayList(); @@ -188,7 +197,7 @@ public class DuplicatesFinder { } } - final Match match = new Match(candidates.get(0), candidates.get(candidates.size() - 1)); + final Match match = new Match(candidates.get(0), candidates.get(candidates.size() - 1), ignoreParameterTypes); for (int i = 0; i < myPattern.length; i++) { if (!matchPattern(myPattern[i], candidates.get(i), candidates, match)) return null; } diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/Match.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/Match.java index c2383b7cec7b..7686ec98a965 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/Match.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/Match.java @@ -48,16 +48,18 @@ public final class Match { private final PsiElement myMatchStart; private final PsiElement myMatchEnd; private final Map> myParameterValues = new HashMap>(); - private final Map> myParameterOccurences = new HashMap>(); + private final Map> myParameterOccurrences = new HashMap>(); private final Map myDeclarationCorrespondence = new HashMap(); private ReturnValue myReturnValue = null; private Ref myInstanceExpression = null; private final Map myChangedParams = new HashMap(); + private final boolean myIgnoreParameterTypes; - Match(PsiElement start, PsiElement end) { + Match(PsiElement start, PsiElement end, boolean ignoreParameterTypes) { LOG.assertTrue(start.getParent() == end.getParent()); myMatchStart = start; myMatchEnd = end; + myIgnoreParameterTypes = ignoreParameterTypes; } @@ -135,14 +137,14 @@ public final class Match { myChangedParams.put(psiVariable, new PsiEllipsisType(parameterType)); } } else { - if (!parameterType.isAssignableFrom(type)) return false; //todo + if (!myIgnoreParameterTypes && !parameterType.isAssignableFrom(type)) return false; //todo } } final List values = new ArrayList(); values.add(value); myParameterValues.put(psiVariable, values); final ArrayList elements = new ArrayList(); - myParameterOccurences.put(psiVariable, elements); + myParameterOccurrences.put(psiVariable, elements); return true; } else { @@ -157,7 +159,7 @@ public final class Match { currentValue.add(value); } } - myParameterOccurences.get(psiVariable).add(value); + myParameterOccurrences.get(psiVariable).add(value); return true; } } diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithGenericsTab2.java b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithGenericsTab2.java new file mode 100644 index 000000000000..20b2f662d368 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithGenericsTab2.java @@ -0,0 +1,8 @@ +import java.util.ArrayList; +import java.util.List; + +public class Foo { + public static void main(String[] args) { + List set = new ArrayList(); + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithGenericsTab2_after.java b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithGenericsTab2_after.java new file mode 100644 index 000000000000..afc79f2b3279 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithGenericsTab2_after.java @@ -0,0 +1,8 @@ +import java.util.ArrayList; +import java.util.List; + +public class Foo { + public static void main(String[] args) { + List set = new ArrayList(); + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/ImportInGenericType.java b/java/java-tests/testData/codeInsight/completion/normal/ImportInGenericType.java new file mode 100644 index 000000000000..07c2a4b0437f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ImportInGenericType.java @@ -0,0 +1,5 @@ +public class Foo { + public static void main(String[] args) { + Set + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/ImportInGenericType_after.java b/java/java-tests/testData/codeInsight/completion/normal/ImportInGenericType_after.java new file mode 100644 index 000000000000..3303a67472d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ImportInGenericType_after.java @@ -0,0 +1,7 @@ +import java.util.Set; + +public class Foo { + public static void main(String[] args) { + Set + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferInnerClasses.java b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferInnerClasses.java new file mode 100644 index 000000000000..db2e1d04d69a --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferInnerClasses.java @@ -0,0 +1,14 @@ +abstract class Base { + public static @interface IfNotParsed {} + + static class X {} +} + +class Derived extends Base { + +} +class B { + void foo(Derived b) { + b. + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/FqnStats.java b/java/java-tests/testData/codeInsight/completion/normalSorting/FqnStats.java new file mode 100644 index 000000000000..9ba38412a11f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/FqnStats.java @@ -0,0 +1,4 @@ +class Foo { + Baaax + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/MultiCatch.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/MultiCatch.java index 69cf037ebaae..705ecd8a6550 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/MultiCatch.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/MultiCatch.java @@ -5,9 +5,10 @@ abstract class C { private static class E2 extends E { } private static class E3 extends E { } private static class RE extends RuntimeException { } - private interface I { } - private static class IE1 extends E implements I { } - private static class IE2 extends E implements I { } + private interface I { } + private static class IE1 extends E implements I { } + private static class IE2 extends E implements I { } + private static class F { F(X x) { } } abstract void f() throws E1, E2; abstract void g() throws IE1, IE2; @@ -18,6 +19,8 @@ abstract class C { try { f(); } catch (E2 | E1 e) { } catch (E e) { } catch (RE e) { } try { f(); } catch (E1 | E e) { E ee = e; } try { g(); } catch (IE1 | IE2 e) { E ee = e; I ii = e; } + try { g(); } catch (IE1 | IE2 e) { F f = new F<>(e); } + try { g(); } catch (IE1 | IE2 e) { new F>(e); } try { f(); } catch (E1 | E2 | E3 e) { } try { f(); } catch (E3 | E e) { } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedGenericsArrayCreation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedGenericsArrayCreation.java index 52dcb04f60ca..06ff29ce7b48 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedGenericsArrayCreation.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/UncheckedGenericsArrayCreation.java @@ -42,4 +42,80 @@ public class Test { final ArrayList list = new ArrayList(); asList(list); } -} \ No newline at end of file + + public static void join(V[] list) { + Arrays.asList(list); + } +} + +class NoWarngs { + static final SemKey FILE_DESCRIPTION_KEY = SemKey.createKey("FILE_DESCRIPTION_KEY"); + + void f() { + OCM o = + new OCM<>("", true, new Condition(){ + @Override + public boolean val(String s) { + return false; + } + }, Condition.TRUE); + System.out.println(o); + } +} + +class SemKey { + private final String myDebugName; + private final SemKey[] mySupers; + + private SemKey(String debugName, SemKey... supers) { + myDebugName = debugName; + System.out.println(myDebugName); + mySupers = supers; + System.out.println(mySupers); + } + + public static SemKey createKey(String debugName, SemKey... supers) { + return new SemKey(debugName, supers); + } + + public SemKey subKey(String debugName, SemKey... otherSupers) { + if (otherSupers.length == 0) { + return new SemKey(debugName, this); + } + return new SemKey(debugName, append(otherSupers, this)); + } + + public static T[] append(final T[] src, final T element) { + return append(src, element, (Class)src.getClass().getComponentType()); + } + + public static T[] append(T[] src, final T element, Class componentType) { + int length = src.length; + T[] result = (T[])java.lang.reflect.Array.newInstance(componentType, length + 1); + System.arraycopy(src, 0, result, 0, length); + result[length] = element; + return result; + } +} + +interface Condition { + boolean val(T t); + + Condition TRUE = new Condition() { + @Override + public boolean val(Object o) { + return true; + } + }; +} +class OCM { + OCM(T s, boolean b, Condition... c) { + System.out.println(s); + System.out.println(b); + System.out.println(c); + } + + OCM(T s, Condition... c) { + this(s, false, c); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IntersectionTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IntersectionTypes.java index 863890a701b6..3316c0d83386 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IntersectionTypes.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IntersectionTypes.java @@ -8,7 +8,7 @@ class Test { } void foo() { - List> l = this.asList(String.class, Integer.class); + List> l = this.asList(String.class, Integer.class); l.size(); List objects = this.asList(new String(), new Integer(0)); objects.size(); @@ -131,7 +131,7 @@ class IDEADEV25515 { public static final List> SIMPLE_TYPES = -asList(String.class, Integer.class ,Long.class, Double.class, /*Date.class,*/ +asList(String.class, Integer.class ,Long.class, Double.class, /*Date.class,*/ Boolean.class, Boolean.TYPE /*,String[].class */ /*,BigDecimal.class*/); @@ -162,4 +162,4 @@ public class MaximalType { } class M extends MaximalType implements L{} class M2 extends MaximalType implements L{} -///////////// \ No newline at end of file +///////////// diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantUncheckedVarargs/before3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantUncheckedVarargs/before3.java index f5504c6e31eb..8200d154a64c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantUncheckedVarargs/before3.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantUncheckedVarargs/before3.java @@ -9,7 +9,7 @@ public class Test { void foo() { //noinspection unchecked - foo(new ArrayList()).addAll(Arrays.asList(new ArrayList); + foo(new ArrayList()).addAll(Arrays.asList(new ArrayList())); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/safeVarargs/before4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/safeVarargs/before4.java deleted file mode 100644 index aed4ed01314a..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/safeVarargs/before4.java +++ /dev/null @@ -1,7 +0,0 @@ -// "Annotate as @SafeVarargs" "false" -public class Test { - public void main(T... args) { - - } -} - diff --git a/java/java-tests/testData/refactoring/introduceVariable/MultiCatchSimple.after.java b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchSimple.after.java new file mode 100644 index 000000000000..cf16e0b4b794 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchSimple.after.java @@ -0,0 +1,11 @@ +class C { + static class E1 extends Exception { } + static class E2 extends Exception { } + + void m() { + try { } + catch (E1 | E2 ex) { + final Exception e = ex; + } + } +} diff --git a/java/java-tests/testData/refactoring/introduceVariable/MultiCatchSimple.java b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchSimple.java new file mode 100644 index 000000000000..582755caaab1 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchSimple.java @@ -0,0 +1,11 @@ +class C { + static class E1 extends Exception { } + static class E2 extends Exception { } + + void m() { + try { } + catch (E1 | E2 ex) { + ex; + } + } +} diff --git a/java/java-tests/testData/refactoring/introduceVariable/MultiCatchTyped.after.java b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchTyped.after.java new file mode 100644 index 000000000000..aed77f0ac0b7 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchTyped.after.java @@ -0,0 +1,12 @@ +class C { + interface B { } + static class E1 extends Exception implements B { } + static class E2 extends Exception implements B { } + + void m() { + try { } + catch (E1 | E2 ex) { + final B b = ex; + } + } +} diff --git a/java/java-tests/testData/refactoring/introduceVariable/MultiCatchTyped.java b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchTyped.java new file mode 100644 index 000000000000..6a8ce4f135ce --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/MultiCatchTyped.java @@ -0,0 +1,12 @@ +class C { + interface B { } + static class E1 extends Exception implements B { } + static class E2 extends Exception implements B { } + + void m() { + try { } + catch (E1 | E2 ex) { + ex; + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java index 9fe6b5a8729d..3c49ffa9dd21 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java @@ -34,11 +34,6 @@ public class ClassNameCompletionTest extends CompletionTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - @Override protected void tearDown() throws Exception { CodeInsightSettings.getInstance().AUTOCOMPLETE_ON_CLASS_NAME_COMPLETION = myOldSetting; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavySmartTypeCompletion15Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavySmartTypeCompletion15Test.java index 750c40dedd5b..49793d481d48 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavySmartTypeCompletion15Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavySmartTypeCompletion15Test.java @@ -81,8 +81,4 @@ public class HeavySmartTypeCompletion15Test extends CompletionTestCase { LookupManager.getInstance(myProject).hideActiveLookup(); super.tearDown(); } - - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 658c03401b20..1439b3b55f83 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -476,5 +476,14 @@ class JavaAutoPopupTest extends CompletionAutoPopupTestCase { assert !lookup } + public void testDoubleLiteralInField() { + myFixture.configureByText "a.java", """ +public interface Test { + double FULL = 1.0 +}""" + type 'd' + assert !lookup + } + } 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 8144fd1e8772..e3b88bd2b5e5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.java @@ -8,6 +8,7 @@ import com.intellij.JavaTestUtil; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; import java.util.List; @@ -182,4 +183,22 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase { checkPreferredItems(0, "XcodeProjectTemplate", "XcodeConfigurable"); } + public void testFqnStats() { + myFixture.addClass("public interface Baaaaaaar {}"); + myFixture.addClass("package zoo; public interface Baaaaaaar {}"); + + final LookupImpl lookup = invokeCompletion(getTestName(false) + ".java"); + assertEquals("Baaaaaaar", ((JavaPsiClassReferenceElement) lookup.getItems().get(0)).getQualifiedName()); + assertEquals("zoo.Baaaaaaar", ((JavaPsiClassReferenceElement) lookup.getItems().get(1)).getQualifiedName()); + incUseCount(lookup, 1); + + assertEquals("zoo.Baaaaaaar", ((JavaPsiClassReferenceElement) lookup.getItems().get(0)).getQualifiedName()); + assertEquals("Baaaaaaar", ((JavaPsiClassReferenceElement)lookup.getItems().get(1)).getQualifiedName()); + } + + public void testDispreferInnerClasses() { + checkPreferredItems(0); //no chosen items + assertFalse(getLookup().getItems().get(0).getObject() instanceof PsiClass); + } + } \ 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 4d5e6e857e79..b32981e99d55 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -676,6 +676,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testReturningTypeVariable() throws Throwable { doTest(); } public void testReturningTypeVariable2() throws Throwable { doTest(); } public void testReturningTypeVariable3() throws Throwable { doTest(); } + public void testImportInGenericType() throws Throwable { doTest(); } public void testCaseTailType() throws Throwable { doTest(); } @@ -808,6 +809,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testClassNameWithInnersTab() throws Throwable { doTest('\t') } public void testClassNameWithGenericsTab() throws Throwable {doTest('\t') } + public void testClassNameWithGenericsTab2() throws Throwable {doTest('\t') } public void testLiveTemplatePrefixTab() throws Throwable {doTest('\t') } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java index 4670cc526d22..85c3caba21ec 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SecondSmartTypeCompletionTest.java @@ -178,9 +178,4 @@ public class SecondSmartTypeCompletionTest extends LightCompletionTestCase { LookupManager.getInstance(getProject()).hideActiveLookup(); super.tearDown(); } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java index 7ec7c261da7d..72facd2c365c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/AnnotationsHighlightingTest.java @@ -37,8 +37,4 @@ public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testPackageAnnotationNotInPackageInfo() throws Exception { doTest(BASE_PATH + "/" + getTestName(true) + "/notPackageInfo.java", false, false); } - - @Override protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index 452ece2addbb..f3f76a8a5f65 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -36,11 +36,6 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { LanguageLevelProjectExtension.getInstance(getJavaFacade().getProject()).setLanguageLevel(level); } - @Override protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - - public void testReferenceTypeParams() throws Exception { doTest(false); } public void testOverridingMethods() throws Exception { doTest(false); } public void testTypeParameterBoundsList() throws Exception { doTest(false); } 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 8f9b3907effe..765ac83ce899 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java @@ -106,9 +106,4 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { protected void doTest() throws Exception { super.doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false); } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index a4ab1b0aa8e6..dcb332113c87 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -6,6 +6,7 @@ import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.reference.EntryPoint; import com.intellij.codeInspection.reference.RefElement; +import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection; import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.extensions.ExtensionPoint; @@ -30,7 +31,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { @Override protected LocalInspectionTool[] configureLocalInspectionTools() { - return new LocalInspectionTool[]{new UnusedSymbolLocalInspection()}; + return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection()}; } public void testDuplicateAnnotations() throws Exception { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/SuppressWarningsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/SuppressWarningsTest.java index c73767a23e24..841b6f80a29f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/SuppressWarningsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/SuppressWarningsTest.java @@ -17,10 +17,6 @@ public class SuppressWarningsTest extends LightDaemonAnalyzerTestCase { doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false); } - @Override protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - @Override protected LocalInspectionTool[] configureLocalInspectionTools() { return new LocalInspectionTool[]{new UnusedSymbolLocalInspection()}; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateFieldFromParameterTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateFieldFromParameterTest.java index 1469f4559152..dd91045350ef 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateFieldFromParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateFieldFromParameterTest.java @@ -30,8 +30,4 @@ public class CreateFieldFromParameterTest extends LightIntentionActionTestCase { protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/createFieldFromParameter"; } - - @Override protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/LightQuickFix15TestCase.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/LightQuickFix15TestCase.java index f5a060bdb80f..cd1e7f02e3ac 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/LightQuickFix15TestCase.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/LightQuickFix15TestCase.java @@ -7,10 +7,4 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; * @author ven */ public abstract class LightQuickFix15TestCase extends LightQuickFixTestCase { - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantUncheckedSuppressionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantUncheckedSuppressionTest.java index 7f2d28816f63..a886624d27e3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantUncheckedSuppressionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/RemoveRedundantUncheckedSuppressionTest.java @@ -23,12 +23,6 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; public class RemoveRedundantUncheckedSuppressionTest extends LightQuickFixTestCase { - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } - @Override protected LocalInspectionTool[] configureLocalInspectionTools() { return new LocalInspectionTool[]{ diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceAddAllArrayToCollectionsFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceAddAllArrayToCollectionsFixTest.java index f9b254d0977d..eaaf9552978c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceAddAllArrayToCollectionsFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceAddAllArrayToCollectionsFixTest.java @@ -16,9 +16,4 @@ public class ReplaceAddAllArrayToCollectionsFixTest extends LightQuickFixTestCas protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/replaceAddAllArrayToCollections"; } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SafeVarargsCanBeUsedTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SafeVarargsCanBeUsedTest.java index 8cf7f2001b31..1bd158a99325 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SafeVarargsCanBeUsedTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SafeVarargsCanBeUsedTest.java @@ -22,12 +22,6 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; public class SafeVarargsCanBeUsedTest extends LightQuickFixTestCase { - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } - @Override protected LocalInspectionTool[] configureLocalInspectionTools() { return new LocalInspectionTool[]{ 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 de19e1fc48b4..8667fdfcd617 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 @@ -32,12 +32,6 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; //todo test3 should be checked if it compiles - as now javac infers Object instead of String?! public class Simplify2DiamondInspectionsTest extends LightQuickFixTestCase { - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } - @Override protected LocalInspectionTool[] configureLocalInspectionTools() { return new LocalInspectionTool[]{ diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Suppress15InspectionsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Suppress15InspectionsTest.java index ea7f4f737b64..b9bb396985d2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Suppress15InspectionsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Suppress15InspectionsTest.java @@ -16,12 +16,6 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; public class Suppress15InspectionsTest extends LightQuickFixTestCase { - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } - @Override protected void setUp() throws Exception { super.setUp(); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithArrayFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithArrayFixTest.java index 19eb09ac7061..715c7032dedd 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithArrayFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithArrayFixTest.java @@ -16,9 +16,4 @@ public class SurroundWithArrayFixTest extends LightQuickFix15TestCase { protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithArray"; } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithIfFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithIfFixTest.java index 99a556b2e88b..a9d352678609 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithIfFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/SurroundWithIfFixTest.java @@ -23,9 +23,4 @@ public class SurroundWithIfFixTest extends LightQuickFixTestCase { protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf"; } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddOnDemandStaticImportActionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddOnDemandStaticImportActionTest.java index d9600e13982f..d917ffc71b1b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddOnDemandStaticImportActionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/intention/AddOnDemandStaticImportActionTest.java @@ -12,9 +12,4 @@ public class AddOnDemandStaticImportActionTest extends LightIntentionActionTestC protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/addOnDemandStaticImport"; } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java index 5c03d221fef0..a2c458564e23 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceBackwardTest.java @@ -33,11 +33,6 @@ import java.util.*; public class SliceBackwardTest extends DaemonAnalyzerTestCase { private final TIntObjectHashMap myFlownOffsets = new TIntObjectHashMap(); - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void dotest() throws Exception { configureByFile("/codeInsight/slice/backward/"+getTestName(false)+".java"); Map sliceUsageName2Offset = extractSliceOffsetsFromDocument(getEditor().getDocument()); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java index 5eeb74e1a597..3c6049a0bd6f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceForwardTest.java @@ -24,11 +24,6 @@ import java.util.Map; public class SliceForwardTest extends DaemonAnalyzerTestCase { private final TIntObjectHashMap myFlownOffsets = new TIntObjectHashMap(); - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void dotest() throws Exception { configureByFile("/codeInsight/slice/forward/"+getTestName(false)+".java"); Map sliceUsageName2Offset = SliceBackwardTest.extractSliceOffsetsFromDocument(getEditor().getDocument()); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java index 0d3677d62d96..a114c363b27b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/slice/SliceTreeTest.java @@ -24,10 +24,6 @@ import java.util.*; * @author cdr */ public class SliceTreeTest extends LightDaemonAnalyzerTestCase { - @Override protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } - private SliceTreeStructure configureTree(@NonNls final String name) throws Exception { configureByFile("/codeInsight/slice/backward/"+ name +".java"); PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); diff --git a/java/java-tests/testSrc/com/intellij/projectView/JavaTreeStructureTest.java b/java/java-tests/testSrc/com/intellij/projectView/JavaTreeStructureTest.java index f7afbe7fb133..ce1577e6dab0 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/JavaTreeStructureTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/JavaTreeStructureTest.java @@ -214,10 +214,4 @@ public class JavaTreeStructureTest extends TestSourceBasedTestCase { protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath(); } - - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17(); - } - } diff --git a/java/java-tests/testSrc/com/intellij/projectView/ProjectViewSwitchingTest.java b/java/java-tests/testSrc/com/intellij/projectView/ProjectViewSwitchingTest.java index 81279689983b..14769572ad6c 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/ProjectViewSwitchingTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/ProjectViewSwitchingTest.java @@ -64,10 +64,4 @@ public class ProjectViewSwitchingTest extends TestSourceBasedTestCase { protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath(); } - - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17(); - } - } diff --git a/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java b/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java index cf157662a789..d7ee434b124c 100644 --- a/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java +++ b/java/java-tests/testSrc/com/intellij/projectView/StructureViewUpdatingTest.java @@ -246,10 +246,4 @@ public class StructureViewUpdatingTest extends TestSourceBasedTestCase { protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath(); } - - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17(); - } - } diff --git a/java/java-tests/testSrc/com/intellij/psi/ModifyAnnotationsTest.java b/java/java-tests/testSrc/com/intellij/psi/ModifyAnnotationsTest.java index d5ec9c2980b5..a362f3fb693a 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ModifyAnnotationsTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ModifyAnnotationsTest.java @@ -24,11 +24,6 @@ public class ModifyAnnotationsTest extends PsiTestCase { PsiTestUtil.createTestProjectStructure(myProject, myModule, root, myFilesToDelete); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("mock 1.5"); - } - public void testReplaceAnnotation() throws Exception { //be sure not to load tree getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.ALL); diff --git a/java/java-tests/testSrc/com/intellij/psi/OptimizeImportsTest.java b/java/java-tests/testSrc/com/intellij/psi/OptimizeImportsTest.java index 358049a5d8c4..8b0816694ea6 100644 --- a/java/java-tests/testSrc/com/intellij/psi/OptimizeImportsTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/OptimizeImportsTest.java @@ -43,11 +43,6 @@ public class OptimizeImportsTest extends PsiTestCase{ public void testNewImportListIsEmptyAndCommentPreserved() throws Exception { doTest(); } public void testNewImportListIsEmptyAndJavaDocWithInvalidCodePreserved() throws Exception { doTest(); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("mock 1.5"); - } - private void doTest() throws Exception { final String extension = ".java"; doTest(extension); diff --git a/java/java-tests/testSrc/com/intellij/psi/Src15RepositoryUseTest.java b/java/java-tests/testSrc/com/intellij/psi/Src15RepositoryUseTest.java index 99c0c964392f..b3fd5a1a4e28 100644 --- a/java/java-tests/testSrc/com/intellij/psi/Src15RepositoryUseTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/Src15RepositoryUseTest.java @@ -37,11 +37,6 @@ public class Src15RepositoryUseTest extends PsiTestCase { PsiTestUtil.createTestProjectStructure(myProject, myModule, root, myFilesToDelete); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("mock 1.5"); - } - @Override protected void tearDown() throws Exception { LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(LanguageLevel.JDK_1_5); diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java index 3ecf5da63e99..8a6ed27ced68 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterTest.java @@ -354,8 +354,14 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest { public void testBraces() throws Exception { final CodeStyleSettings settings = getSettings(); - final String text = "class Foo {\n" + "void foo () {\n" + "if (a) {\n" + "int i = 0;\n" + "}\n" + "}\n" + "}"; - + final String text = + "class Foo {\n" + + "void foo () {\n" + + "if (a) {\n" + + "int i = 0;\n" + + "}\n" + + "}\n" + + "}"; settings.BRACE_STYLE = CodeStyleSettings.END_OF_LINE; settings.METHOD_BRACE_STYLE = CodeStyleSettings.END_OF_LINE; @@ -2199,7 +2205,14 @@ public void testSCR260() throws Exception { getSettings().BRACE_STYLE = CodeStyleSettings.NEXT_LINE_SHIFTED; doTextTest( - "public class ZZZZ \n" + " { \n" + " public ZZZZ() \n" + " { \n" + " if (a){\n" + "foo();}\n" + " } \n" + " }", + "public class ZZZZ \n" + + " { \n" + + " public ZZZZ() \n" + + " { \n" + + " if (a){\n" + + "foo();}\n" + + " } \n" + + " }", "public class ZZZZ\n" + " {\n" + " public ZZZZ()\n" + diff --git a/java/java-tests/testSrc/com/intellij/refactoring/AnonymousToInnerTest.java b/java/java-tests/testSrc/com/intellij/refactoring/AnonymousToInnerTest.java index 609b41c5b308..1324468bf5e9 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/AnonymousToInnerTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/AnonymousToInnerTest.java @@ -17,11 +17,6 @@ public class AnonymousToInnerTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testGenericTypeParameters() throws Exception { // IDEADEV-29446 doTest("MyIterator", true); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTargetTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTargetTest.java index 546d947a8acc..b03da3135c7a 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTargetTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ChangeSignatureTargetTest.java @@ -35,11 +35,6 @@ public class ChangeSignatureTargetTest extends LightCodeInsightTestCase { doTest("A1"); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void doTest(String expectedMemberName) throws Exception { String basePath = "/refactoring/changeSignatureTarget/" + getTestName(true); @NonNls final String filePath = basePath + ".java"; diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethod15Test.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethod15Test.java index 31a250a06b54..d8d7ba33dcb9 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethod15Test.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethod15Test.java @@ -23,10 +23,4 @@ public class ExtractMethod15Test extends LightCodeInsightTestCase { assertTrue(success); checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); } - - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 5ddf845b5212..9d632414afb4 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -30,11 +30,6 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testExitPoints1() throws Exception { doExitPointsTest(true); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractSuperClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractSuperClassTest.java index 4bab81f11dc4..34f7b9b2cc86 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractSuperClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractSuperClassTest.java @@ -108,11 +108,6 @@ public class ExtractSuperClassTest extends CodeInsightTestCase { doTest("p1.A", "AA", new RefactoringTestUtil.MemberDescriptor("m1", PsiMethod.class)); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17(); - } - @Override protected void setUp() throws Exception { super.setUp(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/FindMethodDuplicatesBaseTest.java b/java/java-tests/testSrc/com/intellij/refactoring/FindMethodDuplicatesBaseTest.java index 036e8f45f349..dc4b52b2b5dc 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/FindMethodDuplicatesBaseTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/FindMethodDuplicatesBaseTest.java @@ -20,11 +20,6 @@ public abstract class FindMethodDuplicatesBaseTest extends LightCodeInsightTestC return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - protected void doTest() throws Exception { doTest(true); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InheritanceToDelegationTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InheritanceToDelegationTest.java index a3a0f74771eb..62ed537207b2 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InheritanceToDelegationTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InheritanceToDelegationTest.java @@ -23,11 +23,6 @@ public class InheritanceToDelegationTest extends MultiFileTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - @Override protected String getTestRoot() { return "/refactoring/inheritanceToDelegation/"; diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java index 9deeb8202c37..d4b03c5545eb 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java @@ -23,11 +23,6 @@ public class InlineSuperClassTest extends MultiFileTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17(); - } - private void doTest() throws Exception { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java index bab6d71717ea..7e9be3f2c649 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceConstantTest.java @@ -124,9 +124,4 @@ public class IntroduceConstantTest extends LightCodeInsightTestCase { } }.invoke(getProject(), getEditor(), getFile(), null); } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java index 80a17f4aa744..2ad2588f7561 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFieldInSameClassTest.java @@ -18,11 +18,6 @@ public class IntroduceFieldInSameClassTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testInClassInitializer () throws Exception { configureByFile("/refactoring/introduceField/before1.java"); performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, true); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java index cba854352cc2..c193eeae4d9e 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterTest.java @@ -348,9 +348,4 @@ public class IntroduceParameterTest extends LightCodeInsightTestCase { IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE, declareFinal, false, null, parametersToRemove).run(); } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index 2a19c88e5d7b..6bbc35d63484 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -3,8 +3,6 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiType; @@ -250,15 +248,18 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { }); } + public void testMultiCatchSimple() throws Exception { + doTest(new MockIntroduceVariableHandler("e", true, true, false, "C.E1 | C.E2")); + } + + public void testMultiCatchTyped() throws Exception { + doTest(new MockIntroduceVariableHandler("b", true, true, false, "C.E1 | C.E2")); + } + private void doTest(IntroduceVariableBase testMe) throws Exception { @NonNls String baseName = "/refactoring/introduceVariable/" + getTestName(false); configureByFile(baseName + ".java"); testMe.invoke(getProject(), getEditor(), getFile(), null); checkResultByFile(baseName + ".after.java"); } - - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17(); - } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/PullUpMultifileTest.java b/java/java-tests/testSrc/com/intellij/refactoring/PullUpMultifileTest.java index 21f07ad9bca6..abad0d75f8c9 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/PullUpMultifileTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/PullUpMultifileTest.java @@ -51,12 +51,6 @@ public class PullUpMultifileTest extends MultiFileTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - - private void doTest(final String... conflicts) throws Exception { final MultiMap conflictsMap = new MultiMap(); doTest(new PerformAction() { diff --git a/java/java-tests/testSrc/com/intellij/refactoring/PullUpTest.java b/java/java-tests/testSrc/com/intellij/refactoring/PullUpTest.java index 53ef64abd01f..b5ddaf93ecdd 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/PullUpTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/PullUpTest.java @@ -135,11 +135,6 @@ public class PullUpTest extends LightCodeInsightTestCase { checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("50"); - } - @Override protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/PushDownMultifileTest.java b/java/java-tests/testSrc/com/intellij/refactoring/PushDownMultifileTest.java index c408ae325a05..385f5de7075b 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/PushDownMultifileTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/PushDownMultifileTest.java @@ -28,11 +28,6 @@ public class PushDownMultifileTest extends MultiFileTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void doTest() throws Exception { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameClassTest.java index 6550750f19ae..cf397aaab416 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameClassTest.java @@ -113,9 +113,4 @@ public class RenameClassTest extends MultiFileTestCase { protected String getTestRoot() { return "/refactoring/renameClass/"; } - - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java index bfd33dd79548..279875a4d0ab 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameCollisionsTest.java @@ -182,11 +182,6 @@ public class RenameCollisionsTest extends LightCodeInsightTestCase { checkResultByFile(BASE_PATH + getTestName(false) + ".java.after"); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testAllUsagesInCode() throws Exception { configureByFile(BASE_PATH + getTestName(false) + ".java"); PsiElement element = TargetElementUtilBase diff --git a/java/java-tests/testSrc/com/intellij/refactoring/SuggestedParamTypesTest.java b/java/java-tests/testSrc/com/intellij/refactoring/SuggestedParamTypesTest.java index b9f55f2a3942..d59a4ea63168 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/SuggestedParamTypesTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/SuggestedParamTypesTest.java @@ -46,11 +46,6 @@ public class SuggestedParamTypesTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testPostfixExprUsedAsOutput() throws Exception { doTest("byte"); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/TurnRefsToSuperTest.java b/java/java-tests/testSrc/com/intellij/refactoring/TurnRefsToSuperTest.java index fe0356736a9c..872232ed37f9 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/TurnRefsToSuperTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/TurnRefsToSuperTest.java @@ -159,9 +159,4 @@ public class TurnRefsToSuperTest extends MultiFileTestCase { new TurnRefsToSuperProcessor(myProject, aClass, superClass, replaceInstanceOf).run(); FileDocumentManager.getInstance().saveAllDocuments(); } - - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java b/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java index 5c43b16e3556..9fea974ce682 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java @@ -29,11 +29,6 @@ import java.io.PrintWriter; */ public class TypeCookTest extends MultiFileTestCase { - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - @Override protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath(); diff --git a/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java b/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java index ae2288fd5529..37e312545086 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java @@ -26,11 +26,6 @@ public class WrapReturnValueTest extends MultiFileTestCase{ return "/refactoring/wrapReturnValue/"; } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void doTest(final boolean existing) throws Exception { doTest(existing, null); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureTest.java b/java/java-tests/testSrc/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureTest.java index ae8a135a5029..67473d302711 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/changeClassSignature/ChangeClassSignatureTest.java @@ -21,11 +21,6 @@ public class ChangeClassSignatureTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testNoParams() throws Exception { doTest(new GenParams() { @Override diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineConstantFieldTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineConstantFieldTest.java index a27675020e98..27f6c8ca34f7 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineConstantFieldTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineConstantFieldTest.java @@ -29,11 +29,6 @@ public class InlineConstantFieldTest extends LightCodeInsightTestCase { doTest(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void doTest() throws Exception { String name = getTestName(false); @NonNls String fileName = "/refactoring/inlineConstantField/" + name + ".java"; 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 9f20be7086c9..adf2b4571e95 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -22,11 +22,6 @@ public class InlineLocalTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testInference () throws Exception { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java index 9d66d2a6ac0c..21e5c85695bf 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java @@ -165,11 +165,6 @@ public class InlineMethodTest extends LightCodeInsightTestCase { doTest(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - private void doTest() throws Exception { String name = getTestName(false); @NonNls String fileName = "/refactoring/inlineMethod/" + name + ".java"; diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineParameterTest.java index af27522eb21f..4ee1ff6c85d7 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineParameterTest.java @@ -20,11 +20,6 @@ public class InlineParameterTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testSameValue() throws Exception { doTest(true); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java index f032dbcd87de..51a2c7017e0d 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java @@ -24,11 +24,6 @@ public class InlineToAnonymousClassTest extends LightCodeInsightTestCase { return JavaTestUtil.getJavaTestDataPath(); } - @Override - protected Sdk getProjectJDK() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - public void testSimple() throws Exception { doTest(false, false); } diff --git a/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java b/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java index e764b3bde987..0ae89e9850b4 100644 --- a/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java +++ b/java/openapi/src/com/intellij/psi/PsiDisjunctionType.java @@ -18,39 +18,38 @@ package com.intellij.psi; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.*; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.List; +/** + * Composite type resulting from Project Coin's multi-catch statements, * i.e. FileNotFoundException | EOFException. + * In most cases should be threatened via its least upper bound * (IOException in the example above). + */ public class PsiDisjunctionType extends PsiType { - private final PsiTypeElement myTypeElement; + private final PsiManager myManager; private final List myTypes; private final CachedValue myLubCache; - public PsiDisjunctionType(final PsiTypeElement typeElement) { + public PsiDisjunctionType(final List types, final PsiManager psiManager) { super(PsiAnnotation.EMPTY_ARRAY); - myTypeElement = typeElement; + myManager = psiManager; + myTypes = Collections.unmodifiableList(types); - final List typeElements = PsiTreeUtil.getChildrenOfTypeAsList(myTypeElement, PsiTypeElement.class); - myTypes = Collections.unmodifiableList(ContainerUtil.map(typeElements, new Function() { - @Override - public PsiType fun(final PsiTypeElement psiTypeElement) { - return psiTypeElement.getType(); - } - })); - - final CachedValuesManager cacheManager = CachedValuesManager.getManager(myTypeElement.getProject()); + final CachedValuesManager cacheManager = CachedValuesManager.getManager(psiManager.getProject()); myLubCache = cacheManager.createCachedValue(new CachedValueProvider() { public Result compute() { PsiType lub = myTypes.get(0); for (int i = 1; i < myTypes.size(); i++) { - lub = GenericsUtil.getLeastUpperBound(lub, myTypes.get(i), myTypeElement.getManager()); + lub = GenericsUtil.getLeastUpperBound(lub, myTypes.get(i), psiManager); } return Result.create(lub, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } @@ -65,6 +64,10 @@ public class PsiDisjunctionType extends PsiType { return myTypes; } + public PsiManager getManager() { + return myManager; + } + @Override public String getPresentableText() { return StringUtil.join(myTypes, new Function() { @@ -101,11 +104,7 @@ public class PsiDisjunctionType extends PsiType { @Override public A accept(final PsiTypeVisitor visitor) { - final PsiType lub = getLeastUpperBound(); - if (lub instanceof PsiClassType) { - return visitor.visitClassType((PsiClassType)lub); - } - return visitor.visitType(lub); + return visitor.visitDisjunctionType(this); } @Override diff --git a/java/openapi/src/com/intellij/psi/PsiParameter.java b/java/openapi/src/com/intellij/psi/PsiParameter.java index cee4c3820388..4d0c63d8fed3 100644 --- a/java/openapi/src/com/intellij/psi/PsiParameter.java +++ b/java/openapi/src/com/intellij/psi/PsiParameter.java @@ -45,7 +45,7 @@ public interface PsiParameter extends PsiVariable { /** * Checks if the parameter accepts a variable number of arguments. * - * @return true if the parameter is varargs, false otherwise + * @return true if the parameter is a vararg, false otherwise */ boolean isVarArgs(); diff --git a/java/openapi/src/com/intellij/psi/PsiSubstitutor.java b/java/openapi/src/com/intellij/psi/PsiSubstitutor.java index 7ded0e1a995b..c60ece83b8a7 100644 --- a/java/openapi/src/com/intellij/psi/PsiSubstitutor.java +++ b/java/openapi/src/com/intellij/psi/PsiSubstitutor.java @@ -38,7 +38,7 @@ public interface PsiSubstitutor { /** * Empty, or natural, substitutor. For any type parameter T, - * substitues type T. + * substitutes type T. * Example: consider class List<E>. this * inside class List has type List with EMPTY substitutor. */ @@ -56,7 +56,7 @@ public interface PsiSubstitutor { PsiType substitute(@NotNull PsiTypeParameter typeParameter); /** - * Substitutes type parameters occuring in type with their values. + * Substitutes type parameters occurring in type with their values. * If value for type parameter is null, appropriate erasure is returned. * * @param type the type to substitute the type parameters for. @@ -98,7 +98,7 @@ public interface PsiSubstitutor { PsiSubstitutor putAll(PsiSubstitutor another); /** - * Returns the map from type parameters to types used for substution by this substitutor. + * Returns the map from type parameters to types used for substitution by this substitutor. * * @return the substitution map instance. */ diff --git a/java/openapi/src/com/intellij/psi/PsiTryStatement.java b/java/openapi/src/com/intellij/psi/PsiTryStatement.java index deb2c0560af2..a74ae8d52e61 100644 --- a/java/openapi/src/com/intellij/psi/PsiTryStatement.java +++ b/java/openapi/src/com/intellij/psi/PsiTryStatement.java @@ -40,7 +40,7 @@ public interface PsiTryStatement extends PsiStatement { PsiCodeBlock[] getCatchBlocks(); /** - * Returns the array of parametets for catch sections. + * Returns the array of parameters for catch sections. * * @return the array of parameters, or an empty array if the statement has no catch sections. */ diff --git a/java/openapi/src/com/intellij/psi/PsiType.java b/java/openapi/src/com/intellij/psi/PsiType.java index 5c70c8a21576..d52949c5f6d6 100644 --- a/java/openapi/src/com/intellij/psi/PsiType.java +++ b/java/openapi/src/com/intellij/psi/PsiType.java @@ -61,7 +61,7 @@ public abstract class PsiType implements PsiAnnotationOwner { } /** - * Returns text of this type that can be presented to user. + * @return text of this type that can be presented to user. */ public abstract String getPresentableText(); @@ -79,7 +79,7 @@ public abstract class PsiType implements PsiAnnotationOwner { public abstract boolean isValid(); /** - * Checks whether values of type type can be assigned to rvalues of this type. + * @return true if values of type type can be assigned to rvalues of this type. */ public boolean isAssignableFrom(@NotNull PsiType type) { return TypeConversionUtil.isAssignable(this, type); diff --git a/java/openapi/src/com/intellij/psi/PsiTypeVisitor.java b/java/openapi/src/com/intellij/psi/PsiTypeVisitor.java index 59c52a49e931..045060685ce0 100644 --- a/java/openapi/src/com/intellij/psi/PsiTypeVisitor.java +++ b/java/openapi/src/com/intellij/psi/PsiTypeVisitor.java @@ -48,4 +48,8 @@ public class PsiTypeVisitor { public A visitEllipsisType(PsiEllipsisType ellipsisType) { return visitArrayType(ellipsisType); } + + public A visitDisjunctionType(PsiDisjunctionType disjunctionType) { + return visitType(disjunctionType); + } } diff --git a/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java b/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java index cad7a05a0836..bbe345501d62 100644 --- a/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/openapi/src/com/intellij/psi/util/TypeConversionUtil.java @@ -24,6 +24,7 @@ import com.intellij.psi.*; import com.intellij.psi.infos.ClassCandidateInfo; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; +import com.intellij.util.Function; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; @@ -33,10 +34,7 @@ import gnu.trove.TObjectIntHashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; +import java.util.*; public class TypeConversionUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.TypeConversionUtil"); @@ -75,6 +73,7 @@ public class TypeConversionUtil { TYPE_TO_RANK_MAP.put(PsiType.BOOLEAN, BOOL_RANK); } + private TypeConversionUtil() { } /** * @return true if fromType can be casted to toType @@ -1077,6 +1076,10 @@ public class TypeConversionUtil { return type != null && isPrimitiveWrapper(type.getCanonicalText()); } + public static boolean isComposite(final PsiType type) { + return type instanceof PsiDisjunctionType || type instanceof PsiIntersectionType; + } + public static PsiType typeParameterErasure(@NotNull PsiTypeParameter typeParameter) { return typeParameterErasure(typeParameter, PsiSubstitutor.EMPTY); } @@ -1122,9 +1125,10 @@ public class TypeConversionUtil { return erasure(type, PsiSubstitutor.EMPTY); } - public static PsiType erasure(PsiType type, final PsiSubstitutor beforeSubstitutor) { + public static PsiType erasure(final PsiType type, final PsiSubstitutor beforeSubstitutor) { if (type == null) return null; return type.accept(new PsiTypeVisitor() { + @Override public PsiType visitClassType(PsiClassType classType) { final PsiClass aClass = classType.resolve(); if (aClass instanceof PsiTypeParameter) { @@ -1135,14 +1139,17 @@ public class TypeConversionUtil { } } + @Override public PsiType visitWildcardType(PsiWildcardType wildcardType) { return wildcardType.getExtendsBound().accept(this); } + @Override public PsiType visitPrimitiveType(PsiPrimitiveType primitiveType) { return primitiveType; } + @Override public PsiType visitEllipsisType(PsiEllipsisType ellipsisType) { final PsiType componentType = ellipsisType.getComponentType(); final PsiType newComponentType = componentType.accept(this); @@ -1150,12 +1157,21 @@ public class TypeConversionUtil { return new PsiArrayType(newComponentType); } + @Override public PsiType visitArrayType(PsiArrayType arrayType) { final PsiType componentType = arrayType.getComponentType(); final PsiType newComponentType = componentType.accept(this); if (newComponentType == componentType) return arrayType; return newComponentType.createArrayType(); } + + @Override + public PsiType visitDisjunctionType(PsiDisjunctionType disjunctionType) { + final List erased = ContainerUtil.map(disjunctionType.getDisjunctions(), new Function() { + @Override public PsiType fun(PsiType psiType) { return erasure(psiType, beforeSubstitutor); } + }); + return new PsiDisjunctionType(erased, disjunctionType.getManager()); + } }); } @@ -1539,6 +1555,5 @@ public class TypeConversionUtil { } return new ClassCandidateInfo(clazz, result.getSubstitutor()); - } } diff --git a/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java b/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java index 9d74773385d4..cbe0eb8c9a30 100644 --- a/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java +++ b/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java @@ -300,9 +300,4 @@ public abstract class BaseProjectViewTestCase extends TestSourceBasedTestCase { protected String getTestDataPath() { return PathManagerEx.getTestDataPath(getClass()); } - - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17(); - } } diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java index f7a308580bac..d168a632b97c 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java @@ -29,7 +29,7 @@ import java.io.IOException; public interface JavaCodeInsightTestFixture extends CodeInsightTestFixture { JavaPsiFacade getJavaFacade(); - PsiClass addClass(@NotNull @NonNls final String classText) throws IOException; + PsiClass addClass(@NotNull @NonNls final String classText); @NotNull PsiClass findClass(@NotNull @NonNls String name); diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java index 4861b0c9ffa4..106fd70128fa 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java @@ -19,8 +19,6 @@ import com.intellij.lang.Language; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleType; -import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; @@ -42,15 +40,10 @@ import java.io.File; * @author peter */ public abstract class LightCodeInsightFixtureTestCase extends UsefulTestCase{ - public static final LightProjectDescriptor JAVA_1_4 = new LightProjectDescriptor() { - @Override - public ModuleType getModuleType() { - return StdModuleTypes.JAVA; - } - + public static final LightProjectDescriptor JAVA_1_4 = new DefaultLightProjectDescriptor() { @Override public Sdk getSdk() { - return JavaSdkImpl.getMockJdk17(); + return JavaSdkImpl.getMockJdk14(); } @Override @@ -58,32 +51,12 @@ public abstract class LightCodeInsightFixtureTestCase extends UsefulTestCase{ } }; public static final LightProjectDescriptor JAVA_1_5 = new DefaultLightProjectDescriptor() { - @Override - public ModuleType getModuleType() { - return StdModuleTypes.JAVA; - } - - @Override - public Sdk getSdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - @Override public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_5); } }; public static final LightProjectDescriptor JAVA_1_6 = new DefaultLightProjectDescriptor() { - @Override - public ModuleType getModuleType() { - return StdModuleTypes.JAVA; - } - - @Override - public Sdk getSdk() { - return JavaSdkImpl.getMockJdk17("java 1.6"); - } - @Override public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_6); diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java index c14dff95cc19..d6ae873272de 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java @@ -27,8 +27,6 @@ import com.intellij.testFramework.fixtures.TempDirTestFixture; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import java.io.IOException; - /** * @author yole */ @@ -44,7 +42,7 @@ public class JavaCodeInsightTestFixtureImpl extends CodeInsightTestFixtureImpl i } @Override - public PsiClass addClass(@NotNull @NonNls final String classText) throws IOException { + public PsiClass addClass(@NotNull @NonNls final String classText) { assertInitialized(); final PsiClass psiClass = addClass(getTempDirPath(), classText); final VirtualFile file = psiClass.getContainingFile().getVirtualFile(); diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java index e78a22b41e22..d4e85df6c728 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java @@ -53,5 +53,5 @@ public class JavaTestFixtureFactoryImpl extends JavaTestFixtureFactory { } } - private static final LightProjectDescriptor ourJavaProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_1_4; + private static final LightProjectDescriptor ourJavaProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_1_6; } diff --git a/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java b/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java index bcaa7001c08d..93ce3b0c5364 100644 --- a/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java +++ b/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.NonNls; import javax.swing.*; public abstract class ModuleType { - public static ModuleType EMPTY; + public static final ModuleType EMPTY; private final String myId; diff --git a/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java b/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java index cd72d658f331..c0339cb46e4c 100644 --- a/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java +++ b/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java @@ -66,11 +66,11 @@ public abstract class PsiElementPattern pattern) { - return afterLeafSkipping(psiElement().whitespaceCommentOrError(), pattern); + return afterLeafSkipping(psiElement().whitespaceCommentEmptyOrError(), pattern); } public Self beforeLeaf(@NotNull final ElementPattern pattern) { - return beforeLeafSkipping(psiElement().whitespaceCommentOrError(), pattern); + return beforeLeafSkipping(psiElement().whitespaceCommentEmptyOrError(), pattern); } public Self whitespace() { @@ -81,6 +81,10 @@ public abstract class PsiElementPattern pattern) { return withChildren(collection(PsiElement.class).filter(not(psiElement().whitespace()), collection(PsiElement.class).first(pattern))); } diff --git a/platform/lang-api/src/com/intellij/util/SequentialTask.java b/platform/lang-api/src/com/intellij/util/SequentialTask.java new file mode 100644 index 000000000000..96fc7732b123 --- /dev/null +++ b/platform/lang-api/src/com/intellij/util/SequentialTask.java @@ -0,0 +1,48 @@ +/* + * 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.util; + +/** + * Defines general contract for processing that may be executed by parts, i.e. it remembers the state after every iteration + * and allows to resume the processing any time. + * + * @author Denis Zhdanov + * @since 2/14/11 9:15 AM + */ +public interface SequentialTask { + + /** + * Callback method that is assumed to be called before the processing. + */ + void prepare(); + + /** + * @return true if the processing is complete; false otherwise + */ + boolean isDone(); + + /** + * Asks current task to perform one more processing iteration. + * + * @return true if the processing is done; false otherwise + */ + boolean iteration(); + + /** + * Asks current task to stop the processing (if any). + */ + void stop(); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java index 3e1b737f88a5..085cb6e2aeb4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatAndOptimizeImportsProcessor.java @@ -28,8 +28,8 @@ import org.jetbrains.annotations.NotNull; * @author max */ public class ReformatAndOptimizeImportsProcessor extends AbstractLayoutCodeProcessor { - private static final String PROGRESS_TEXT = CodeInsightBundle.message("progress.text.reformatting.code"); - private static final String COMMAND_NAME = CodeInsightBundle.message("process.reformat.code"); + private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text"); + private static final String COMMAND_NAME = CodeInsightBundle.message("progress.reformat.code.prepare"); private final OptimizeImportsProcessor myOptimizeImportsProcessor; private final ReformatCodeProcessor myReformatCodeProcessor; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java index e3d357609dba..32c786dad77a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java @@ -31,7 +31,7 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.ReformatCodeProcessor"); private final TextRange myRange; - private static final String PROGRESS_TEXT = CodeInsightBundle.message("progress.text.reformatting.code"); + private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text"); private static final String COMMAND_NAME = CodeInsightBundle.message("process.reformat.code"); public ReformatCodeProcessor(Project project) { 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 a6bb506cbe7b..9336b40c3c3b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -38,6 +38,7 @@ 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.PsiFile; @@ -102,7 +103,6 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } }; private final Semaphore myDuringCompletionSemaphore = new Semaphore(); - private static final boolean ourHintAutopopup = "true".equals(System.getProperty("hint.autopopup", "false")); private volatile int myCount; @@ -336,7 +336,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } } - if (isAutopopupCompletion() && ourHintAutopopup) { + if (isAutopopupCompletion() && showHintAutopopup()) { myLookup.setHintMode(true); } else { @@ -348,6 +348,10 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement updateFocus(); } + public static boolean showHintAutopopup() { + return "true".equals(Registry.stringValue("hint.autopopup")); + } + final boolean isInsideIdentifier() { return getIdentifierEndOffset() != getSelectionEndOffset(); } @@ -466,14 +470,19 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement if (isAutopopupCompletion() && !myLookup.isSelectionTouched() && !myLookup.isCalculating()) { myLookup.refreshUi(); final List items = myLookup.getItems(); - if (!items.isEmpty() && ourHintAutopopup) { - return false; - } for (LookupElement item : items) { if (!(item.getPrefixMatcher().getPrefix() + myLookup.getAdditionalPrefix()).equals(item.getLookupString())) { return false; } + + if (showHintAutopopup()) { + final LookupElementPresentation presentation = new LookupElementPresentation(); + item.renderElement(presentation); + if (StringUtil.isNotEmpty(presentation.getTailText())) { + return false; + } + } } myLookup.hideLookup(false); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java index 1cf7cfa90d96..ad76f7e76f2f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -91,10 +91,12 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { } - 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; + 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; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java index f747e3e324d2..5c459cde6457 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoComponent.java @@ -67,7 +67,6 @@ class ParameterInfoComponent extends JPanel{ myObjects = objects; setLayout(new GridBagLayout()); - setBorder(BorderFactory.createCompoundBorder(LineBorder.createGrayLineBorder(), BorderFactory.createEmptyBorder(0, 5, 0, 5))); setBackground(BACKGROUND_COLOR); myHandler = handler; @@ -314,7 +313,9 @@ class ParameterInfoComponent extends JPanel{ Dimension normalPreferredSize = super.getPreferredSize(); // some fonts (for example, Arial Black Cursiva) have NORMAL characters wider than BOLD characters - return new Dimension(Math.max(boldPreferredSize.width, normalPreferredSize.width), Math.max(boldPreferredSize.height, normalPreferredSize.height)); + + return new Dimension(Math.max(boldPreferredSize.width, normalPreferredSize.width), + Math.max(boldPreferredSize.height, normalPreferredSize.height)); } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java index a4f49b76467a..42e363939a57 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/ComparingClassifier.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.lookup; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -71,7 +72,7 @@ public abstract class ComparingClassifier extends Classifier { @Override public void describeItems(LinkedHashMap map) { final TreeMap> treeMap = groupByWeights(new ArrayList(map.keySet())); - if (treeMap.size() > 1) { + if (treeMap.size() > 1 || ApplicationManager.getApplication().isUnitTestMode()) { for (Map.Entry> entry: treeMap.entrySet()){ for (T t : entry.getValue()) { final StringBuilder builder = map.get(t); 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 419d88935ad3..8c443306c5f5 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()) { + if (lookup == null || !lookup.isFocused() || lookup.isHintMode()) { 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 a8699b9454c8..badc854bea87 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()) { + if (lookup == null || !lookup.isFocused() || lookup.isHintMode()) { myOriginalHandler.execute(editor, dataContext); return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index f606603161fe..bbba75b5f69b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -198,7 +198,7 @@ public class LookupCellRenderer implements ListCellRenderer { return text.substring(0, i) + ELLIPSIS; } - private static Color getTailTextColor(boolean isSelected, LookupElementPresentation presentation, Color defaultForeground) { + public static Color getTailTextColor(boolean isSelected, LookupElementPresentation presentation, Color defaultForeground) { if (presentation.isTailGrayed()) { return getGrayedForeground(isSelected); } 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 68e544cc82f8..c9085877ff6b 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 @@ -67,6 +67,7 @@ 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.*; @@ -341,6 +342,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { if (!ApplicationManager.getApplication().isUnitTestMode()) { ApplicationManager.getApplication().assertIsDispatchThread(); } + assert !myDisposed; final Pair,Iterable>> snapshot = myModel.getModelSnapshot(); @@ -387,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)) { + if (isFocused() && (!isExactPrefixItem(model.iterator().next()) || mySelectionTouched) && !isHintMode()) { restoreSelection(oldSelected, hasPreselected, oldInvariant); } else { @@ -484,6 +486,10 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { myHintMode = hintMode; } + public boolean isHintMode() { + return myHintMode; + } + private static LookupElementPresentation renderItemApproximately(LookupElement item) { final LookupElementPresentation p = new LookupElementPresentation(); item.renderElement(p); @@ -1131,11 +1137,10 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { } else if (myHintMode) { final int itemTextPadding = 2; - final int borderWidth = 1; - final JPanel hintComponent = createAutopopupHintComponent(itemTextPadding, borderWidth); + final JPanel hintComponent = createAutopopupHintComponent(itemTextPadding); Point bestPoint = calculatePosition(hintComponent); - bestPoint.x += myCellRenderer.getIconIndent() - itemTextPadding - borderWidth; + bestPoint.x += myCellRenderer.getIconIndent() - itemTextPadding; Point editorPoint = SwingUtilities.convertPoint( editor.getComponent().getRootPane().getLayeredPane(), bestPoint, @@ -1150,21 +1155,19 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { panel.add(hintComponent); myAutopopupHint = new LightweightHint(panel); myAutopopupHint.setForceShowAsPopup(true); - myAutopopupHint.setForceLightweightPopup(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); } - //todo[kirillk] comment the following line - HintManagerImpl.adjustEditorHintPosition(myAutopopupHint, editor, bestPoint); } } - private JPanel createAutopopupHintComponent(int itemTextPadding, int borderWidth) { - int maxAutopopupItems = 10; + private JPanel createAutopopupHintComponent(int itemTextPadding) { + int maxAutopopupItems = 7; JPanel pane = new JPanel(new GridBagLayout()); pane.setBackground(HintUtil.INFORMATION_COLOR); @@ -1183,51 +1186,75 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable { c.ipadx = itemTextPadding; c.fill = GridBagConstraints.HORIZONTAL; - final SimpleColoredComponent comp = new SimpleColoredComponent(); - comp.setFont(editorFont); - final int style = presentation.isItemTextBold() ? Font.BOLD : Font.PLAIN; - myCellRenderer.renderItemName(element, LookupCellRenderer.FOREGROUND_COLOR, false, style, - StringUtil.notNullize(presentation.getItemText()), comp); - final JPanel p1 = new JPanel(new BorderLayout()); - p1.setBackground(pane.getBackground()); - p1.add(comp, BorderLayout.WEST); - final JLabel label = new JLabel(presentation.getTailText()); - label.setFont(label.getFont().deriveFont(Font.PLAIN, editorFont.getSize())); - p1.add(label, BorderLayout.CENTER); - pane.add(p1, c); - } + { + final GridBagLayout gridBagLayout = new GridBagLayout(); + final JPanel row = new JPanel(gridBagLayout); + row.setBackground(pane.getBackground()); - { - final GridBagConstraints c = new GridBagConstraints(); - c.gridx = 1; - c.gridy = i; - c.fill = GridBagConstraints.HORIZONTAL; - final JLabel comp = new JLabel(" " + StringUtil.notNullize(presentation.getTypeText()) + " "); - comp.setFont(comp.getFont().deriveFont(Font.PLAIN, editorFont.getSize())); - comp.setHorizontalAlignment(SwingConstants.RIGHT); - pane.add(comp, c); + GridBagConstraints c1 = new GridBagConstraints(); + c1.anchor = GridBagConstraints.BASELINE; + + final SimpleColoredComponent nameLabel = new SimpleColoredComponent(); + 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); + row.add(nameLabel, c1); + + c1 = new GridBagConstraints(); + c1.weightx = 1; + c1.anchor = GridBagConstraints.BASELINE; + c1.fill = GridBagConstraints.HORIZONTAL; + final JLabel tailLabel = new JLabel(presentation.getTailText()); + tailLabel.setFont(tailLabel.getFont().deriveFont(Font.PLAIN, editorFont.getSize())); + tailLabel.setForeground(LookupCellRenderer.getTailTextColor(false, presentation, tailLabel.getForeground())); + row.add(tailLabel, c1); + + c1 = new GridBagConstraints(); + c1.fill = GridBagConstraints.NONE; + final JLabel typeLabel = new JLabel(" " + StringUtil.notNullize(presentation.getTypeText()) + " "); + typeLabel.setFont(typeLabel.getFont().deriveFont(Font.PLAIN, editorFont.getSize())); + row.add(typeLabel, c1); + + pane.add(row, c); + } } } - if (items.size() > maxAutopopupItems) { - { - final GridBagConstraints c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = maxAutopopupItems; - c.gridwidth = 2; - c.ipadx = 5; - c.ipady = 2; - c.fill = GridBagConstraints.HORIZONTAL; - final String moreText = " ... (" + - KeymapUtil - .getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION)) + - " for more suggestions)"; - pane.add(new JLabel(moreText), c); + { + final GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = maxAutopopupItems; + c.gridwidth = 2; + c.ipadx = 5; + c.ipady = 2; + c.fill = GridBagConstraints.HORIZONTAL; + final JPanel ad = new JPanel(new BorderLayout()); + ad.setBorder(BorderFactory.createCompoundBorder(new MatteBorder(1, 0, 0, 0, Color.lightGray), new EmptyBorder(0, 2, 0, 7))); + ad.setOpaque(false); + + if (items.size() > maxAutopopupItems) { + final String ctrlSpace = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION)); + if (StringUtil.isNotEmpty(ctrlSpace)) { + final String moreText = ctrlSpace + " for more"; + final JLabel moreLabel = new JLabel(moreText); + moreLabel.setFont(moreLabel.getFont().deriveFont(Font.PLAIN, editorFont.getSize())); + ad.add(moreLabel, BorderLayout.WEST); + } } + + final String tab = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM_REPLACE)); + if (StringUtil.isNotEmpty(tab)) { + final String enter = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CHOOSE_LOOKUP_ITEM)); + String message = tab + (isFocused() ? ", " + enter : "") + " for the first item"; + final JLabel fstLabel = new JLabel(message); + fstLabel.setFont(fstLabel.getFont().deriveFont(Font.PLAIN, editorFont.getSize())); + ad.add(fstLabel, BorderLayout.EAST); + } + pane.add(ad, c); } - //pane.setBorder(new LineBorder(Color.darkGray, borderWidth)); return pane; } 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 d1d4690cce1a..54c84064dc0a 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 @@ -44,7 +44,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.REPLACE_SELECT_CHAR); + lookup.finishLookup(lookup.isHintMode() ? Lookup.NORMAL_SELECT_CHAR : Lookup.REPLACE_SELECT_CHAR); } @Override 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 e12c24eb94cc..af25959298ce 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -497,7 +497,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { if (file != myFile.getVirtualFile()) return; if (myConsoleEditor != null) { queueUiUpdate(false); - for (FileEditor fileEditor : source.getAllEditors()) { + for (FileEditor fileEditor : source.getAllEditors(file)) { if (!(fileEditor instanceof TextEditor)) continue; final Editor editor = ((TextEditor)fileEditor).getEditor(); registerActionShortcuts(editor.getComponent()); diff --git a/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java b/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java index ac214de42679..6f4571eb3502 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/ConsoleExecuteActionHandler.java @@ -57,11 +57,15 @@ public class ConsoleExecuteActionHandler { } public void processLine(String line) { + sendLine(line + "\n"); + } + + public void sendLine(String line) { //final Charset charset = myProcessHandler.getCharset(); final OutputStream outputStream = myProcessHandler.getProcessInput(); try { //byte[] bytes = (line + "\n").getBytes(charset.name()); - byte[] bytes = (line + "\n").getBytes(); + byte[] bytes = line.getBytes(); outputStream.write(bytes); outputStream.flush(); } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index fde74bf81261..dc3eef7c724c 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -658,8 +658,10 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo private boolean tryToFindNextUsageViaEditorSearchComponent(Editor editor, boolean forwardOrBackward) { if (editor.getHeaderComponent() instanceof EditorSearchComponent) { EditorSearchComponent searchComponent = (EditorSearchComponent)editor.getHeaderComponent(); - searchComponent.moveCursor(forwardOrBackward); - return true; + if (searchComponent.hasMatches()) { + searchComponent.moveCursor(forwardOrBackward); + return true; + } } return false; } diff --git a/platform/lang-impl/src/com/intellij/find/impl/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/LivePreview.java index 6c1f8a346b1d..e092ac5293fe 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/LivePreview.java +++ b/platform/lang-impl/src/com/intellij/find/impl/LivePreview.java @@ -224,12 +224,17 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele myShouldStop = false; myLivePreviewAlarm.cancelAllRequests(); if (updateEditorReference() != null) { - myLivePreviewAlarm.addRequest(new Runnable() { + Runnable request = new Runnable() { @Override public void run() { updateInBackground(); } - }, myUserActivityDelay); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + request.run(); + } else { + myLivePreviewAlarm.addRequest(request, myUserActivityDelay); + } } } @@ -270,7 +275,7 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele } }); if (mySearchResults != null) { - ApplicationManager.getApplication().invokeLater(new Runnable() { + Runnable highlightUsagesBlock = new Runnable() { @Override public void run() { doInternalCleanUp(); @@ -280,7 +285,12 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele myContinuation = null; } } - }); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + highlightUsagesBlock.run(); + } else { + ApplicationManager.getApplication().invokeLater(highlightUsagesBlock); + } } } @@ -297,9 +307,31 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele private void highlightUsages(TextRange oldCursorRange) { if (myEditor == null || myShouldStop) return; - LiveOccurrence firstVisibleOccurrence = null; - LiveOccurrence firstOccurrence = null; + for (LiveOccurrence o : mySearchResults) { + for (TextRange textRange : o.getSecondaryRanges()) { + highlightRange(textRange, OTHER_TARGETS_ATTRIBUTES, myHighlighters); + } + highlightRange(o.getPrimaryRange(), MAIN_TARGET_ATTRIBUTES, myHighlighters); + } + + if (!tryToRepairOldCursor(oldCursorRange)) { + LiveOccurrence afterCaret = firstOccurrenceAfterCaret(); + if (afterCaret != null) { + setCursor(afterCaret); + } else { + LiveOccurrence occurrence = firstVisibleOccurrence(); + if (occurrence != null) { + setCursor(occurrence); + } + } + } + } + + @Nullable + private LiveOccurrence firstVisibleOccurrence() { int offset = Integer.MAX_VALUE; + LiveOccurrence firstOccurrence = null; + LiveOccurrence firstVisibleOccurrence = null; for (LiveOccurrence o : mySearchResults) { if (insideVisibleArea(myEditor, o.getPrimaryRange())) { if (firstVisibleOccurrence == null || o.getPrimaryRange().getStartOffset() < firstVisibleOccurrence.getPrimaryRange().getStartOffset()) { @@ -310,16 +342,22 @@ public class LivePreview extends DocumentAdapter implements ReplacementView.Dele offset = o.getPrimaryRange().getStartOffset(); firstOccurrence = o; } + } + return firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence; + } - for (TextRange textRange : o.getSecondaryRanges()) { - highlightRange(textRange, OTHER_TARGETS_ATTRIBUTES, myHighlighters); + @Nullable + private LiveOccurrence firstOccurrenceAfterCaret() { + LiveOccurrence afterCaret = null; + int caret = myEditor.getCaretModel().getOffset(); + for (LiveOccurrence occurrence : mySearchResults) { + if (occurrence.getPrimaryRange().getStartOffset() >= caret) { + if (afterCaret == null || occurrence.getPrimaryRange().getStartOffset() < afterCaret.getPrimaryRange().getStartOffset() ) { + afterCaret = occurrence; + } } - highlightRange(o.getPrimaryRange(), MAIN_TARGET_ATTRIBUTES, myHighlighters); - } - - if (!tryToRepairOldCursor(oldCursorRange)) { - setCursor(firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence); } + return afterCaret; } private boolean tryToRepairOldCursor(TextRange oldCursorRange) { diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 72421e87eefb..19f37c372305 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -99,16 +99,24 @@ class FormatProcessor { }); private final HashSet myAlignAgain = new HashSet(); + @NotNull + private final FormattingProgressIndicator myProgressIndicator; + private WhiteSpace myLastWhiteSpace; private boolean myDisposed; private CodeStyleSettings.IndentOptions myJavaIndentOptions; + + @NotNull + private State myCurrentState; public FormatProcessor(final FormattingDocumentModel docModel, Block rootBlock, CodeStyleSettings settings, CodeStyleSettings.IndentOptions indentOptions, - @Nullable FormatTextRanges affectedRanges) { - this(docModel, rootBlock, settings, indentOptions, affectedRanges, -1); + @Nullable FormatTextRanges affectedRanges, + @NotNull FormattingProgressIndicator progressIndicator) + { + this(docModel, rootBlock, settings, indentOptions, affectedRanges, -1, progressIndicator); } public FormatProcessor(final FormattingDocumentModel docModel, @@ -116,22 +124,13 @@ class FormatProcessor { CodeStyleSettings settings, CodeStyleSettings.IndentOptions indentOptions, @Nullable FormatTextRanges affectedRanges, - int interestingOffset) { + int interestingOffset, + @NotNull FormattingProgressIndicator progressIndicator) + { + myProgressIndicator = progressIndicator; myIndentOption = indentOptions; mySettings = settings; - final InitialInfoBuilder builder = InitialInfoBuilder.buildBlocks(rootBlock, - docModel, - affectedRanges, - indentOptions, - interestingOffset); - myInfos = builder.getBlockToInfoMap(); - myRootBlockWrapper = builder.getRootBlockWrapper(); - myFirstTokenBlock = builder.getFirstTokenBlock(); - myLastTokenBlock = builder.getLastTokenBlock(); - myCurrentBlock = myFirstTokenBlock; - myTextRangeToWrapper = buildTextRangeToInfoMap(myFirstTokenBlock); - myLastWhiteSpace = new WhiteSpace(getLastBlock().getEndOffset(), false); - myLastWhiteSpace.append(docModel.getTextLength(), docModel, indentOptions); + myCurrentState = new WrapBlocksState(rootBlock, docModel, affectedRanges, interestingOffset); } private LeafBlockWrapper getLastBlock() { @@ -153,21 +152,78 @@ class FormatProcessor { } public void format(FormattingModel model) { - formatWithoutRealModifications(); - performModifications(model); + format(model, false); } - @SuppressWarnings({"WhileLoopSpinsOnField"}) - public void formatWithoutRealModifications() { - while (true) { - myAlignAgain.clear(); - myCurrentBlock = myFirstTokenBlock; - while (myCurrentBlock != null) { - processToken(); - } - if (myAlignAgain.isEmpty()) return; - reset(); + /** + * Asks current processor to perform formatting. + *

+ * There are two processing approaches at the moment: + *

+   * 
    + *
  • perform formatting during the current method call;
  • + *
  • + * split the whole formatting process to the set of fine-grained tasks and execute them sequentially during + * subsequent {@link #iteration()} calls; + *
  • + *
+ *
+ *

+ * Here is rationale for the second approach - formatting may introduce changes to the underlying document and IntelliJ IDEA + * is designed in a way that write access is allowed from EDT only. That means that every time we execute particular action + * from EDT we have no chance of performing any other actions from EDT simultaneously (e.g. we may want to show progress bar + * that reflects current formatting state but the progress bar can' bet updated if formatting is performed during a single long + * method call). So, we can interleave formatting iterations with GUI state updates. + * + * @param model target formatting model + * @param sequentially flag that indicates what kind of processing should be used + */ + public void format(FormattingModel model, boolean sequentially) { + if (sequentially) { + AdjustWhiteSpacesState adjustState = new AdjustWhiteSpacesState(); + adjustState.setNext(new ApplyChangesState(model)); + myCurrentState.setNext(adjustState); } + else { + formatWithoutRealModifications(sequentially); + performModifications(model, sequentially); + } + } + + /** + * Asks current processor to perform processing iteration + * + * @return true if the processing is finished; false otherwise + * @see #format(FormattingModel, boolean) + */ + public boolean iteration() { + if (myCurrentState.isDone()) { + return true; + } + myCurrentState.iteration(); + return myCurrentState.isDone(); + } + + /** + * Asks current processor to stop any active sequential processing if any. + */ + public void stopSequentialProcessing() { + myCurrentState.stop(); + } + + public void formatWithoutRealModifications() { + formatWithoutRealModifications(false); + } + + @SuppressWarnings({"WhileLoopSpinsOnField"}) + public void formatWithoutRealModifications(boolean sequentially) { + myCurrentState.setNext(new AdjustWhiteSpacesState()); + + if (sequentially) { + return; + } + + doIterationsSynchronously(FormattingStateId.PROCESSING_BLOCKS); } private void reset() { @@ -181,71 +237,38 @@ class FormatProcessor { } public void performModifications(FormattingModel model) { + performModifications(model, false); + } + + public void performModifications(FormattingModel model, boolean sequentially) { assert !myDisposed; - final List blocksToModify = collectBlocksToModify(); - - // call doModifications static method to ensure no access to state - // thus we may clear formatting state - reset(); - - myInfos = null; - myRootBlockWrapper = null; - myTextRangeToWrapper = null; - myPreviousDependencies = null; - myLastWhiteSpace = null; - myFirstTokenBlock = null; - myLastTokenBlock = null; - myDisposed = true; - - //for GeneralCodeFormatterTest - if (myJavaIndentOptions == null) { - myJavaIndentOptions = mySettings.getIndentOptions(StdFileTypes.JAVA); + myCurrentState.setNext(new ApplyChangesState(model)); + + if (sequentially) { + return; } - doModify(blocksToModify, model, myIndentOption, myJavaIndentOptions); + doIterationsSynchronously(FormattingStateId.APPLYING_CHANGES); } + /** + * Perform iterations against the {@link #myCurrentState current state} until it's {@link FormattingStateId type} + * is {@link FormattingStateId#getPreviousStates() less} or equal to the given state. + * + * @param state target state to process + */ + private void doIterationsSynchronously(@NotNull FormattingStateId state) { + while ((myCurrentState.getStateId() == state || state.getPreviousStates().contains(myCurrentState.getStateId())) + && !myCurrentState.isDone()) + { + myCurrentState.iteration(); + } + } + public void setJavaIndentOptions(final CodeStyleSettings.IndentOptions javaIndentOptions) { myJavaIndentOptions = javaIndentOptions; } - private static void doModify(final List blocksToModify, final FormattingModel model, - CodeStyleSettings.IndentOptions indentOption, CodeStyleSettings.IndentOptions javaOptions) { - final int blocksToModifyCount = blocksToModify.size(); - DocumentEx updatedDocument = null; - - try { - final boolean bulkReformat = blocksToModifyCount > 50; - updatedDocument = bulkReformat ? getAffectedDocument(model) : null; - if (updatedDocument != null) { - updatedDocument.setInBulkUpdate(true); - } - - if (blocksToModifyCount > BULK_REPLACE_OPTIMIZATION_CRITERIA) { - if (applyChangesAtBulkMode(blocksToModify, model, indentOption)) { - return; - } - } - - int shift = 0; - for (int i = 0; i < blocksToModifyCount; ++i) { - final LeafBlockWrapper block = blocksToModify.get(i); - shift = replaceWhiteSpace(model, block, shift, block.getWhiteSpace().generateWhiteSpace(indentOption), javaOptions); - - // block could be gc'd - block.getParent().dispose(); - block.dispose(); - blocksToModify.set(i, null); - } - } - finally { - if (updatedDocument != null) { - updatedDocument.setInBulkUpdate(false); - } - model.commitChanges(); - } - } - /** * Decides whether applying formatter changes should be applied incrementally one-by-one or merge result should be * constructed locally and the whole document text should be replaced. Performs such single bulk change if necessary. @@ -256,6 +279,7 @@ class FormatProcessor { * @return true if given changes are applied to the document (i.e. no further processing is required); * false otherwise */ + @SuppressWarnings({"deprecation"}) private static boolean applyChangesAtBulkMode(final List blocksToModify, final FormattingModel model, CodeStyleSettings.IndentOptions indentOption) { @@ -326,6 +350,7 @@ class FormatProcessor { return shift; } + @NotNull private List collectBlocksToModify() { List blocksToModify = new ArrayList(); @@ -449,10 +474,8 @@ class FormatProcessor { boolean wrapIsPresent = whiteSpace.containsLineFeeds(); final ArrayList wraps = myCurrentBlock.getWraps(); - final int wrapsCount = wraps.size(); - - for (int i = 0; i < wrapsCount; ++i) { - wraps.get(i).processNextEntry(myCurrentBlock.getStartOffset()); + for (WrapImpl wrap : wraps) { + wrap.processNextEntry(myCurrentBlock.getStartOffset()); } final WrapImpl wrap = getWrapToBeUsed(wraps); @@ -489,8 +512,7 @@ class FormatProcessor { myWrapCandidate = null; } else { - for (int i = 0; i < wrapsCount; ++i) { - final WrapImpl wrap1 = wraps.get(i); + for (final WrapImpl wrap1 : wraps) { if (isCandidateToBeWrapped(wrap1) && canReplaceWrapCandidate(wrap1)) { myWrapCandidate = myCurrentBlock; } @@ -870,7 +892,6 @@ class FormatProcessor { } if (myWrapCandidate == myCurrentBlock) return wraps.get(0); - final int wrapsCount = wraps.size(); for (final WrapImpl wrap : wraps) { if (!isSuitableInTheCurrentPosition(wrap)) continue; if (wrap.isIsActive()) return wrap; @@ -1265,6 +1286,9 @@ class FormatProcessor { processToken(); if (myCurrentBlock == null) { myCurrentBlock = myLastTokenBlock; + if (myCurrentBlock != null) { + myProgressIndicator.afterProcessingBlock(myCurrentBlock); + } break; } } @@ -1302,6 +1326,228 @@ class FormatProcessor { } } } + + private abstract class State { + private final FormattingStateId myStateId; + + private State myNextState; + private boolean myDone; + protected State(FormattingStateId stateId) { + myStateId = stateId; + } + + public void iteration() { + if (!isDone()) { + doIteration(); + } + shiftStateIfNecessary(); + } + + public boolean isDone() { + return myDone; + } + + protected void setDone(boolean done) { + myDone = done; + } + + public void setNext(@NotNull State state) { + if (getStateId() == state.getStateId() || (myNextState != null && myNextState.getStateId() == state.getStateId())) { + return; + } + myNextState = state; + shiftStateIfNecessary(); + } + + public FormattingStateId getStateId() { + return myStateId; + } + + public void stop() { + } + + protected abstract void doIteration(); + protected abstract void prepare(); + + private void shiftStateIfNecessary() { + if (isDone() && myNextState != null) { + myCurrentState = myNextState; + myNextState = null; + myCurrentState.prepare(); + } + } + } + + private class WrapBlocksState extends State { + + private final InitialInfoBuilder myWrapper; + private final FormattingDocumentModel myModel; + + WrapBlocksState(@NotNull Block root, + @NotNull FormattingDocumentModel model, + @Nullable final FormatTextRanges affectedRanges, + int interestingOffset) + { + super(FormattingStateId.WRAPPING_BLOCKS); + myModel = model; + myWrapper = InitialInfoBuilder.prepareToBuildBlocksSequentially( + root, model, affectedRanges, myIndentOption, interestingOffset, myProgressIndicator + ); + } + + @Override + protected void prepare() { + } + + @Override + public void doIteration() { + if (isDone()) { + return; + } + + setDone(myWrapper.iteration()); + if (!isDone()) { + return; + } + + myInfos = myWrapper.getBlockToInfoMap(); + myRootBlockWrapper = myWrapper.getRootBlockWrapper(); + myFirstTokenBlock = myWrapper.getFirstTokenBlock(); + myLastTokenBlock = myWrapper.getLastTokenBlock(); + myCurrentBlock = myFirstTokenBlock; + myTextRangeToWrapper = buildTextRangeToInfoMap(myFirstTokenBlock); + myLastWhiteSpace = new WhiteSpace(getLastBlock().getEndOffset(), false); + myLastWhiteSpace.append(myModel.getTextLength(), myModel, myIndentOption); + } + } + + private class AdjustWhiteSpacesState extends State { + + AdjustWhiteSpacesState() { + super(FormattingStateId.PROCESSING_BLOCKS); + } + + @Override + protected void prepare() { + } + + @Override + protected void doIteration() { + LeafBlockWrapper blockToProcess = myCurrentBlock; + processToken(); + if (blockToProcess != null) { + myProgressIndicator.afterProcessingBlock(blockToProcess); + } + + if (myCurrentBlock != null) { + return; + } + + if (myAlignAgain.isEmpty()) { + setDone(true); + } + else { + myAlignAgain.clear(); + myCurrentBlock = myFirstTokenBlock; + } + } + } + + private class ApplyChangesState extends State { + + private final FormattingModel myModel; + private List myBlocksToModify; + private int myShift; + private int myIndex; + private boolean myResetBulkUpdateState; + + private ApplyChangesState(FormattingModel model) { + super(FormattingStateId.APPLYING_CHANGES); + myModel = model; + } + + @Override + protected void prepare() { + myBlocksToModify = collectBlocksToModify(); + // call doModifications static method to ensure no access to state + // thus we may clear formatting state + reset(); + + myInfos = null; + myRootBlockWrapper = null; + myTextRangeToWrapper = null; + myPreviousDependencies = null; + myLastWhiteSpace = null; + myFirstTokenBlock = null; + myLastTokenBlock = null; + myDisposed = true; + + if (myBlocksToModify.isEmpty()) { + setDone(true); + return; + } + + //for GeneralCodeFormatterTest + if (myJavaIndentOptions == null) { + myJavaIndentOptions = mySettings.getIndentOptions(StdFileTypes.JAVA); + } + + myProgressIndicator.beforeApplyingFormatChanges(myBlocksToModify); + + final int blocksToModifyCount = myBlocksToModify.size(); + final boolean bulkReformat = blocksToModifyCount > 50; + DocumentEx updatedDocument = bulkReformat ? getAffectedDocument(myModel) : null; + if (updatedDocument != null) { + updatedDocument.setInBulkUpdate(true); + myResetBulkUpdateState = true; + } + if (blocksToModifyCount > BULK_REPLACE_OPTIMIZATION_CRITERIA && applyChangesAtBulkMode(myBlocksToModify, myModel, myIndentOption)) { + setDone(true); + } + } + + @Override + protected void doIteration() { + LeafBlockWrapper blockWrapper = myBlocksToModify.get(myIndex); + myShift = replaceWhiteSpace( + myModel, blockWrapper, myShift, blockWrapper.getWhiteSpace().generateWhiteSpace(myIndentOption), myJavaIndentOptions + ); + myProgressIndicator.afterApplyingChange(blockWrapper); + // block could be gc'd + blockWrapper.getParent().dispose(); + blockWrapper.dispose(); + myBlocksToModify.set(myIndex, null); + myIndex++; + + if (myIndex >= myBlocksToModify.size()) { + setDone(true); + } + } + + @Override + protected void setDone(boolean done) { + super.setDone(done); + + if (myResetBulkUpdateState) { + DocumentEx document = getAffectedDocument(myModel); + if (document != null) { + document.setInBulkUpdate(false); + myResetBulkUpdateState = false; + } + } + + if (done) { + myModel.commitChanges(); + } + } + + @Override + public void stop() { + if (myIndex > 0) { + myModel.commitChanges(); + } + } + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterEx.java b/platform/lang-impl/src/com/intellij/formatting/FormatterEx.java index b081bcd8ac57..1ac8053de72d 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterEx.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterEx.java @@ -18,10 +18,11 @@ package com.intellij.formatting; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class FormatterEx{ @@ -113,6 +114,8 @@ public abstract class FormatterEx{ CodeStyleSettings.IndentOptions indentOptions, TextRange affectedRange); + public abstract void setProgressIndicator(@NotNull FormattingProgressIndicatorImpl progressIndicator); + public interface IndentInfoStorage { void saveIndentInfo(IndentInfo info, int startOffset); diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java index 57d279aa0fb6..02a7cc6ff350 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java @@ -16,16 +16,21 @@ package com.intellij.formatting; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.FormattingDocumentModelImpl; import com.intellij.psi.formatter.PsiBasedFormattingModel; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.SequentialTask; import com.intellij.util.text.CharArrayUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -42,6 +47,8 @@ public class FormatterImpl extends FormatterEx { private static final Logger LOG = Logger.getInstance("#com.intellij.formatting.FormatterImpl"); + private FormattingProgressIndicatorImpl myProgressIndicator; + private int myIsDisabledCount = 0; private final IndentImpl NONE_INDENT = new IndentImpl(IndentImpl.Type.NONE, false, false); private final IndentImpl myAbsoluteNoneIndent = new IndentImpl(IndentImpl.Type.NONE, true, false); @@ -82,20 +89,31 @@ public class FormatterImpl extends FormatterEx public Indent getNoneIndent() { return NONE_INDENT; } + + @Override + public void setProgressIndicator(@NotNull FormattingProgressIndicatorImpl progressIndicator) { + myProgressIndicator = progressIndicator; + } + public void format(final FormattingModel model, final CodeStyleSettings settings, final CodeStyleSettings.IndentOptions indentOptions, final CodeStyleSettings.IndentOptions javaIndentOptions, - final FormatTextRanges affectedRanges) throws IncorrectOperationException { - disableFormatting(); - try { - FormatProcessor processor = new FormatProcessor(model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, - affectedRanges); - processor.setJavaIndentOptions(javaIndentOptions); - processor.format(model); - } finally { - enableFormatting(); - } + final FormatTextRanges affectedRanges) throws IncorrectOperationException + { + SequentialTask task = new MyFormattingTask() { + @NotNull + @Override + protected FormatProcessor buildProcessor() { + FormatProcessor processor = new FormatProcessor( + model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, affectedRanges, FormattingProgressIndicator.EMPTY + ); + processor.setJavaIndentOptions(javaIndentOptions); + processor.format(model); + return processor; + } + }; + execute(task); } public Wrap createWrap(WrapType type, boolean wrapFirstElement) { @@ -125,43 +143,110 @@ public class FormatterImpl extends FormatterEx return new DependantSpacingImpl(minOffset, maxOffset, dependence, keepLineBreaks, keepBlankLines); } - public void format(FormattingModel model, - CodeStyleSettings settings, - CodeStyleSettings.IndentOptions indentOptions, - FormatTextRanges affectedRanges) throws IncorrectOperationException { - disableFormatting(); - try { - FormatProcessor processor = - new FormatProcessor(model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, affectedRanges); - processor.format(model); - } finally { - enableFormatting(); - } - + @NotNull + private FormattingProgressIndicator getProgressIndicator() { + FormattingProgressIndicator result = myProgressIndicator; + return result == null ? FormattingProgressIndicator.EMPTY : result; + } + + public void format(final FormattingModel model, + final CodeStyleSettings settings, + final CodeStyleSettings.IndentOptions indentOptions, + final FormatTextRanges affectedRanges) throws IncorrectOperationException { + SequentialTask task = new MyFormattingTask() { + @NotNull + @Override + protected FormatProcessor buildProcessor() { + FormatProcessor processor = new FormatProcessor( + model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, affectedRanges, getProgressIndicator() + ); + processor.format(model, true); + return processor; + } + }; + execute(task); } - public void formatWithoutModifications(FormattingDocumentModel model, - Block rootBlock, - CodeStyleSettings settings, - CodeStyleSettings.IndentOptions indentOptions, - TextRange affectedRange) throws IncorrectOperationException { - disableFormatting(); - try { - new FormatProcessor(model, rootBlock, settings, indentOptions, new FormatTextRanges(affectedRange, true)).formatWithoutRealModifications(); - } finally { - enableFormatting(); - } + public void formatWithoutModifications(final FormattingDocumentModel model, + final Block rootBlock, + final CodeStyleSettings settings, + final CodeStyleSettings.IndentOptions indentOptions, + final TextRange affectedRange) throws IncorrectOperationException + { + SequentialTask task = new MyFormattingTask() { + @NotNull + @Override + protected FormatProcessor buildProcessor() { + FormatProcessor result = new FormatProcessor( + model, rootBlock, settings, indentOptions, new FormatTextRanges(affectedRange, true), FormattingProgressIndicator.EMPTY + ); + result.formatWithoutRealModifications(); + return result; + } + }; + execute(task); + } + /** + * Execute given sequential formatting task. Two approaches are possible: + *

+   * 
    + *
  • + * synchronous - the task is completely executed during the current method processing; + *
  • + *
  • + * asynchronous - the task is executed at background thread under the progress dialog; + *
  • + *
+ *
+ * + * @param task task to execute + */ + private void execute(@NotNull SequentialTask task) { + disableFormatting(); + Application application = ApplicationManager.getApplication(); + if (myProgressIndicator == null || !application.isDispatchThread() || application.isUnitTestMode()) { + try { + task.prepare(); + while (!task.isDone()) { + task.iteration(); + } + } + finally { + enableFormatting(); + myProgressIndicator = null; + } + } + else { + myProgressIndicator.setTask(task); + myProgressIndicator.addCallback(FormattingProgressIndicator.EventType.SUCCESS, new Runnable() { + @Override + public void run() { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + // Reset current progress indicator. + myProgressIndicator = null; + enableFormatting(); + } + }); + } + }); + ProgressManager.getInstance().run(myProgressIndicator); + } } public IndentInfo getWhiteSpaceBefore(final FormattingDocumentModel model, final Block block, final CodeStyleSettings settings, final CodeStyleSettings.IndentOptions indentOptions, - final TextRange affectedRange, final boolean mayChangeLineFeeds) { + final TextRange affectedRange, final boolean mayChangeLineFeeds) + { disableFormatting(); try { - final FormatProcessor processor = new FormatProcessor(model, block, settings, indentOptions, new FormatTextRanges(affectedRange, true)); + final FormatProcessor processor = buildProcessorAndWrapBlocks( + model, block, settings, indentOptions, new FormatTextRanges(affectedRange, true) + ); final LeafBlockWrapper blockBefore = processor.getBlockAfter(affectedRange.getStartOffset()); LOG.assertTrue(blockBefore != null); WhiteSpace whiteSpace = blockBefore.getWhiteSpace(); @@ -187,8 +272,9 @@ public class FormatterImpl extends FormatterEx try { final FormattingDocumentModel documentModel = model.getDocumentModel(); final Block block = model.getRootBlock(); - final FormatProcessor processor = new FormatProcessor(documentModel, block, settings, indentOptions, - new FormatTextRanges(rangeToAdjust, true)); + final FormatProcessor processor = buildProcessorAndWrapBlocks( + documentModel, block, settings, indentOptions, new FormatTextRanges(rangeToAdjust, true) + ); LeafBlockWrapper tokenBlock = processor.getFirstTokenBlock(); while (tokenBlock != null) { final WhiteSpace whiteSpace = tokenBlock.getWhiteSpace(); @@ -215,8 +301,9 @@ public class FormatterImpl extends FormatterEx try { final FormattingDocumentModel documentModel = model.getDocumentModel(); final Block block = model.getRootBlock(); - final FormatProcessor processor = new FormatProcessor(documentModel, block, settings, - settings.getIndentOptions(fileType), null); + final FormatProcessor processor = buildProcessorAndWrapBlocks( + documentModel, block, settings, settings.getIndentOptions(fileType), null + ); LeafBlockWrapper tokenBlock = processor.getFirstTokenBlock(); while (tokenBlock != null) { final WhiteSpace whiteSpace = tokenBlock.getWhiteSpace(); @@ -256,9 +343,9 @@ public class FormatterImpl extends FormatterEx try { final FormattingDocumentModel documentModel = model.getDocumentModel(); final Block block = model.getRootBlock(); - final FormatProcessor processor = new FormatProcessor(documentModel, block, settings, indentOptions, - new FormatTextRanges(affectedRange, true), - offset); + final FormatProcessor processor = buildProcessorAndWrapBlocks( + documentModel, block, settings, indentOptions, new FormatTextRanges(affectedRange, true), offset + ); final LeafBlockWrapper blockAfterOffset = processor.getBlockAfter(offset); @@ -276,6 +363,54 @@ public class FormatterImpl extends FormatterEx } } + /** + * Delegates to + * {@link #buildProcessorAndWrapBlocks(FormattingDocumentModel, Block, CodeStyleSettings, CodeStyleSettings.IndentOptions, FormatTextRanges, int)} + * with '-1' as an interested offset. + * + * @param docModel + * @param rootBlock + * @param settings + * @param indentOptions + * @param affectedRanges + * @return + */ + private static FormatProcessor buildProcessorAndWrapBlocks(final FormattingDocumentModel docModel, + Block rootBlock, + CodeStyleSettings settings, + CodeStyleSettings.IndentOptions indentOptions, + @Nullable FormatTextRanges affectedRanges) + { + return buildProcessorAndWrapBlocks(docModel, rootBlock, settings, indentOptions, affectedRanges, -1); + } + + /** + * Builds {@link FormatProcessor} instance and asks it to wrap all {@link Block code blocks} + * {@link FormattingModel#getRootBlock() derived from the given model}. + * + * @param docModel target model + * @param rootBlock root block to process + * @param settings code style settings to use + * @param indentOptions indent options to use + * @param affectedRanges ranges to reformat + * @param interestingOffset interesting offset; '-1' if no particular offset has a special interest + * @return format processor instance with wrapped {@link Block code blocks} + */ + @SuppressWarnings({"StatementWithEmptyBody"}) + private static FormatProcessor buildProcessorAndWrapBlocks(final FormattingDocumentModel docModel, + Block rootBlock, + CodeStyleSettings settings, + CodeStyleSettings.IndentOptions indentOptions, + @Nullable FormatTextRanges affectedRanges, + int interestingOffset) + { + FormatProcessor processor = new FormatProcessor( + docModel, rootBlock, settings, indentOptions, affectedRanges, interestingOffset, FormattingProgressIndicator.EMPTY + ); + while (!processor.iteration()) ; + return processor; + } + private static int adjustLineIndent( final int offset, final FormattingDocumentModel documentModel, @@ -323,9 +458,9 @@ public class FormatterImpl extends FormatterEx final TextRange affectedRange) { final FormattingDocumentModel documentModel = model.getDocumentModel(); final Block block = model.getRootBlock(); - final FormatProcessor processor = new FormatProcessor(documentModel, block, settings, indentOptions, - new FormatTextRanges(affectedRange, true), offset); - + final FormatProcessor processor = buildProcessorAndWrapBlocks( + documentModel, block, settings, indentOptions, new FormatTextRanges(affectedRange, true), offset + ); final LeafBlockWrapper blockAfterOffset = processor.getBlockAfter(offset); if (blockAfterOffset != null) { @@ -398,8 +533,9 @@ public class FormatterImpl extends FormatterEx @Nullable final IndentInfoStorage indentInfoStorage) { disableFormatting(); try { - final FormatProcessor processor = new FormatProcessor(model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, - new FormatTextRanges(affectedRange, true)); + final FormatProcessor processor = buildProcessorAndWrapBlocks( + model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, new FormatTextRanges(affectedRange, true) + ); LeafBlockWrapper current = processor.getFirstTokenBlock(); while (current != null) { WhiteSpace whiteSpace = current.getWhiteSpace(); @@ -462,8 +598,9 @@ public class FormatterImpl extends FormatterEx final TextRange affectedRange) { disableFormatting(); try { - final FormatProcessor processor = new FormatProcessor(model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, - new FormatTextRanges(affectedRange, true)); + final FormatProcessor processor = buildProcessorAndWrapBlocks( + model.getDocumentModel(), model.getRootBlock(), settings, indentOptions, new FormatTextRanges(affectedRange, true) + ); LeafBlockWrapper current = processor.getFirstTokenBlock(); while (current != null) { WhiteSpace whiteSpace = current.getWhiteSpace(); @@ -489,8 +626,10 @@ public class FormatterImpl extends FormatterEx final CodeStyleSettings settings, final CodeStyleSettings.IndentOptions indentOptions) { final Block block = model.getRootBlock(); - final FormatProcessor processor = new FormatProcessor(model.getDocumentModel(), block, settings, indentOptions, - new FormatTextRanges(affectedRange, true)); + + final FormatProcessor processor = buildProcessorAndWrapBlocks( + model.getDocumentModel(), block, settings, indentOptions, new FormatTextRanges(affectedRange, true) + ); LeafBlockWrapper current = processor.getFirstTokenBlock(); while (current != null) { WhiteSpace whiteSpace = current.getWhiteSpace(); @@ -601,4 +740,33 @@ public class FormatterImpl extends FormatterEx myIsDisabledCount--; } } + + private abstract static class MyFormattingTask implements SequentialTask { + + private FormatProcessor myProcessor; + private boolean myDone; + + @Override + public void prepare() { + myProcessor = buildProcessor(); + } + + @Override + public boolean isDone() { + return myDone; + } + + @Override + public boolean iteration() { + return myDone = myProcessor.iteration(); + } + + @Override + public void stop() { + myProcessor.stopSequentialProcessing(); + } + + @NotNull + protected abstract FormatProcessor buildProcessor(); + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormattingProgressIndicator.java b/platform/lang-impl/src/com/intellij/formatting/FormattingProgressIndicator.java new file mode 100644 index 000000000000..4b75d3d91616 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/formatting/FormattingProgressIndicator.java @@ -0,0 +1,121 @@ +/* + * 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.formatting; + +import com.intellij.util.SequentialTask; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * Defines common interface for formatting-aware progress indicator. + * + * @author Denis Zhdanov + * @since 2/10/11 3:38 PM + */ +public interface FormattingProgressIndicator { + + enum EventType { SUCCESS, CANCEL } + + /** + * Notifies current indicator that particular {@link Block code block} is wrapped. + * + * @param wrapped wrapped code block + * @see FormattingStateId#WRAPPING_BLOCKS + */ + void afterWrappingBlock(@NotNull LeafBlockWrapper wrapped); + + /** + * Notifies current indicator that given {@link LeafBlockWrapper wrapped code block} is processed, i.e. its + * {@link AbstractBlockWrapper#getWhiteSpace() white space} is adjusted as necessary. + * + * @param block processed wrapped block which white space if adjusted + * @see FormattingStateId#PROCESSING_BLOCKS + */ + void afterProcessingBlock(@NotNull LeafBlockWrapper block); + + /** + * Notifies current indicator that changes from the given {@link LeafBlockWrapper wrapped code blocks} are about to be flushed + * to the underlying document. + * + * @param modifiedBlocks blocks with modified {@link AbstractBlockWrapper#getWhiteSpace() white spaces} which are about + * to be flushed to the underlying document + * @see FormattingStateId#APPLYING_CHANGES + */ + void beforeApplyingFormatChanges(@NotNull Collection modifiedBlocks); + + /** + * Notifies current indicator that change from the given {@link LeafBlockWrapper wrapped code block} is successfully flushed + * to the underlying document. + * + * @param block {@link LeafBlockWrapper wrapped code block} which change is successfully flushed to the underlying document + * @see FormattingStateId#APPLYING_CHANGES + */ + void afterApplyingChange(@NotNull LeafBlockWrapper block); + + /** + * Allows to define an actual formatting task to process. + *

+ * I.e. the general idea is that given indicator is provided with the task which will be executed from EDT + * {@link SequentialTask#iteration() part by part} until the task {@link SequentialTask#isDone() is finished}. + * That 'part-by-part' processing is assumed to update current indicator (call 'beforeXxx()' + * and 'afterXxx()' methods). + * + * @param task formatter task to process + */ + void setTask(@Nullable SequentialTask task); + + /** + * Allows to register callback for the target event type. + * + * @param eventType target event type + * @param callback callback to register for the given event type + * @return true if given callback is successfully registered for the given event type; + * false otherwise + */ + boolean addCallback(@NotNull EventType eventType, @NotNull Runnable callback); + + /** + * Null object for {@link FormattingProgressIndicator}. + */ + FormattingProgressIndicator EMPTY = new FormattingProgressIndicator() { + @Override + public void afterWrappingBlock(@NotNull LeafBlockWrapper wrapped) { + } + + @Override + public void afterProcessingBlock(@NotNull LeafBlockWrapper block) { + } + + @Override + public void beforeApplyingFormatChanges(@NotNull Collection modifiedBlocks) { + } + + @Override + public void afterApplyingChange(@NotNull LeafBlockWrapper block) { + } + + @Override + public void setTask(@Nullable SequentialTask task) { + } + + @Override + public boolean addCallback(@NotNull EventType eventType, @NotNull Runnable callback) { + return false; + } + }; +} diff --git a/platform/lang-impl/src/com/intellij/formatting/FormattingProgressIndicatorImpl.java b/platform/lang-impl/src/com/intellij/formatting/FormattingProgressIndicatorImpl.java new file mode 100644 index 000000000000..1a57f2c4a1bc --- /dev/null +++ b/platform/lang-impl/src/com/intellij/formatting/FormattingProgressIndicatorImpl.java @@ -0,0 +1,304 @@ +/* + * 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.formatting; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.ide.IdeBundle; +import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.util.SequentialTask; +import com.intellij.util.containers.HashSet; +import com.intellij.util.ui.UIUtil; +import gnu.trove.TObjectIntHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Formatting progressable task. + * + * @author Denis Zhdanov + * @since 2/10/11 3:00 PM + */ +public class FormattingProgressIndicatorImpl extends Task.Modal implements FormattingProgressIndicator { + + private static final Logger LOG = Logger.getInstance("#" + FormattingProgressIndicatorImpl.class.getName()); + + /** + * We want to perform formatting by big chunks at EDT. However, there is a possible case that particular formatting iteration + * is executed in short amount of time. Hence, we may want to execute more than one formatting action during single EDT iteration. + * Current collection contains mappings between min amount of time allowed for particular state iteration processing from EDT. + */ + private static final TObjectIntHashMap ITERATION_MIN_TIMES_MILLIS = new TObjectIntHashMap(); + static { + ITERATION_MIN_TIMES_MILLIS.put(FormattingStateId.WRAPPING_BLOCKS, 500); + ITERATION_MIN_TIMES_MILLIS.put(FormattingStateId.PROCESSING_BLOCKS, 500); + ITERATION_MIN_TIMES_MILLIS.put(FormattingStateId.APPLYING_CHANGES, 1000); + assert ITERATION_MIN_TIMES_MILLIS.size() == FormattingStateId.values().length; + } + + /** + * Holds max allowed progress bar value (defined at ProgressWindow.MyDialog.initDialog()). + */ + private static final double MAX_PROGRESS_VALUE = 1; + private static final double TOTAL_WEIGHT; + static { + double weight = 0; + for (FormattingStateId state : FormattingStateId.values()) { + weight += state.getProgressWeight(); + } + TOTAL_WEIGHT = weight; + } + + private final Map> myCallbacks = new HashMap>(); + + private final WeakReference myFile; + private final WeakReference myDocument; + private final int myFileTextLength; + + @NotNull + private FormattingStateId myLastState = FormattingStateId.WRAPPING_BLOCKS; + private long myDocumentModificationStampBefore = -1; + private volatile boolean myRunning = true; + + private ProgressIndicator myIndicator; + private SequentialTask myTask; + private int myBlocksToModifyNumber; + private int myModifiedBlocksNumber; + + public FormattingProgressIndicatorImpl(@Nullable Project project, @NotNull PsiFile file, @NotNull Document document) { + super(project, getTitle(file), true); + myFile = new WeakReference(file.getVirtualFile()); + myDocument = new WeakReference(document); + myFileTextLength = file.getTextLength(); + addCallback(EventType.CANCEL, new MyCancelCallback()); + } + + @NotNull + private static String getTitle(@NotNull PsiFile file) { + VirtualFile virtualFile = file.getOriginalFile().getVirtualFile(); + if (virtualFile == null) { + return CodeInsightBundle.message("reformat.progress.common.text"); + } + else { + return CodeInsightBundle.message("reformat.progress.file.with.known.name.text", virtualFile.getName()); + } + } + + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + doRun(indicator); + } + catch (Exception e) { + LOG.info("Unexpected exception occurred during reformatting file " + myFile, e); + } + finally { + if (myIndicator != null) { + myIndicator.stop(); + } + } + } + + @SuppressWarnings({"SSBasedInspection"}) + public void doRun(@NotNull ProgressIndicator indicator) throws InvocationTargetException, InterruptedException { + final SequentialTask task = myTask; + if (task == null) { + return; + } + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + Document document = myDocument.get(); + if (document != null) { + myDocumentModificationStampBefore = document.getModificationStamp(); + } + task.prepare(); + } + }); + + // We need to sync background thread and EDT here in order to avoid situation when event queue is full of processing requests. + final Lock lock = new ReentrantLock(); + final Condition condition = lock.newCondition(); + myIndicator = indicator; + + while (myRunning && !task.isDone()) { + if (indicator.isCanceled()) { + task.stop(); + break; + } + lock.lock(); + try { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + lock.lock(); + try { + long start = System.currentTimeMillis(); + while (!task.isDone() && System.currentTimeMillis() - start < ITERATION_MIN_TIMES_MILLIS.get(myLastState)) { + task.iteration(); + } + } + finally { + condition.signal(); + lock.unlock(); + } + } + }); + if (!task.isDone()) { + condition.await(); + } + } + finally { + lock.unlock(); + } + } + } + + @Override + public boolean addCallback(@NotNull EventType eventType, @NotNull Runnable callback) { + return getCallbacks(eventType).add(callback); + } + + @Override + public void onSuccess() { + super.onSuccess(); + for (Runnable callback : getCallbacks(EventType.SUCCESS)) { + callback.run(); + } + } + + @Override + public void onCancel() { + super.onCancel(); + for (Runnable callback : getCallbacks(EventType.CANCEL)) { + callback.run(); + } + } + + private Collection getCallbacks(@NotNull EventType eventType) { + Collection result = myCallbacks.get(eventType); + if (result == null) { + myCallbacks.put(eventType, result = new HashSet()); + } + return result; + } + + @Override + public void afterWrappingBlock(@NotNull LeafBlockWrapper wrapped) { + update(FormattingStateId.WRAPPING_BLOCKS, MAX_PROGRESS_VALUE * wrapped.getEndOffset() / myFileTextLength); + } + + @Override + public void afterProcessingBlock(@NotNull LeafBlockWrapper block) { + update(FormattingStateId.PROCESSING_BLOCKS, MAX_PROGRESS_VALUE * block.getEndOffset() / myFileTextLength); + } + + @Override + public void beforeApplyingFormatChanges(@NotNull Collection modifiedBlocks) { + myBlocksToModifyNumber = modifiedBlocks.size(); + updateTextIfNecessary(FormattingStateId.APPLYING_CHANGES); + setCancelText(IdeBundle.message("action.stop")); + } + + @Override + public void afterApplyingChange(@NotNull LeafBlockWrapper block) { + if (myModifiedBlocksNumber++ >= myBlocksToModifyNumber) { + return; + } + + update(FormattingStateId.APPLYING_CHANGES, MAX_PROGRESS_VALUE * myModifiedBlocksNumber / myBlocksToModifyNumber); + } + + @Override + public void setTask(@Nullable SequentialTask task) { + myTask = task; + } + + /** + * Updates current progress state if necessary. + * + * @param state current state + * @param completionRate completion rate of the given state. Is assumed to belong to [0; 1] interval + */ + private void update(@NotNull FormattingStateId state, double completionRate) { + if (myIndicator == null) { + return; + } + + updateTextIfNecessary(state); + + myLastState = state; + double newFraction = 0; + for (FormattingStateId prevState : state.getPreviousStates()) { + newFraction += MAX_PROGRESS_VALUE * prevState.getProgressWeight() / TOTAL_WEIGHT; + } + newFraction += completionRate * state.getProgressWeight() / TOTAL_WEIGHT; + + // We don't bother about imprecise floating point arithmetic here because that is enough for progress representation. + double currentFraction = myIndicator.getFraction(); + if (newFraction - currentFraction < MAX_PROGRESS_VALUE / 100) { + return; + } + + myIndicator.setFraction(newFraction); + } + + private void updateTextIfNecessary(@NotNull FormattingStateId currentState) { + if (myLastState != currentState && myIndicator != null) { + myIndicator.setText(currentState.getDescription()); + } + } + + private class MyCancelCallback implements Runnable { + @Override + public void run() { + myRunning = false; + VirtualFile file = myFile.get(); + Document document = myDocument.get(); + if (file == null || document == null || myDocumentModificationStampBefore < 0) { + return; + } + FileEditor editor = FileEditorManager.getInstance(myProject).getSelectedEditor(file); + if (editor == null) { + return; + } + + UndoManager manager = UndoManager.getInstance(myProject); + while (manager.isUndoAvailable(editor) && document.getModificationStamp() != myDocumentModificationStampBefore) { + manager.undo(editor); + } + } + } +} diff --git a/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java b/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java new file mode 100644 index 000000000000..5d4aa1c801d2 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java @@ -0,0 +1,92 @@ +/* + * 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.formatting; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import org.jetbrains.annotations.NotNull; + +import java.util.EnumSet; +import java.util.Set; + +/** + * Enumerates formatting processing states. + * + * @author Denis Zhdanov + * @since 2/10/11 2:50 PM + */ +public enum FormattingStateId { + + /** + * Corresponds to {@link InitialInfoBuilder#buildFrom(Block, int, CompositeBlockWrapper, WrapImpl, Block, boolean)}. + *

+ * I.e. the first thing formatter does retrieval of all {@link Block code blocks} from target {@link FormattingModel model} + * and wrapping them in order to be able to store information about modified white spaces. That processing may trigger + * blocks construction because most of our formatting models do that lazily, i.e. they define the + * {@link FormattingModel#getRootBlock() root block} and build its sub-blocks only on the {@link Block#getSubBlocks() first request}. + */ + WRAPPING_BLOCKS(2), + + /** + * This element corresponds to the state when formatter sequentially processes {@link AbstractBlockWrapper wrapped code blocks} + * and modifies their {@link WhiteSpace white spaces} according to the current {@link CodeStyleSettings code style settings}. + */ + PROCESSING_BLOCKS(1), + + /** + * This element corresponds to formatting phase when all {@link AbstractBlockWrapper wrapped code blocks} are processed and it's + * time to apply the changes to the underlying document. + */ + APPLYING_CHANGES(10); + + private final String myDescription; + private final double myWeight; + + FormattingStateId(double weight) { + myWeight = weight; + myDescription = CodeInsightBundle.message("progress.reformat.stage." + toString().replace('_', '.').toLowerCase()); + } + + /** + * @return human-readable textual description of the current state id + */ + public String getDescription() { + return myDescription; + } + + /** + * @return 'weight' of the current state. Basically, it's assumed that every processing iteration of the state + * with greater weight is executed longer that processing iteration of the state with the lower weight + */ + public double getProgressWeight() { + return myWeight; + } + + /** + * @return collection of formatting states that are assumed to be executed prior to the current one + */ + @NotNull + public Set getPreviousStates() { + Set result = EnumSet.noneOf(FormattingStateId.class); + for (FormattingStateId state : values()) { + if (state == this) { + break; + } + result.add(state); + } + return result; + } +} diff --git a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java index 962be9631800..48ddfa3c3e24 100644 --- a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java @@ -24,9 +24,12 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.FormattingDocumentModelImpl; import com.intellij.psi.formatter.ReadOnlyBlockInformationProvider; import com.intellij.psi.impl.DebugUtil; +import com.intellij.util.containers.Stack; import gnu.trove.THashMap; import org.apache.commons.collections.Unmodifiable; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -39,47 +42,71 @@ import java.util.Map; class InitialInfoBuilder { private static final Logger LOG = Logger.getInstance("#com.intellij.formatting.InitialInfoBuilder"); - private WhiteSpace myCurrentWhiteSpace; - private final FormattingDocumentModel myModel; - private final FormatTextRanges myAffectedRanges; - private final int myPositionOfInterest; private final Map myResult = new THashMap(); - private CompositeBlockWrapper myRootBlockWrapper; - private LeafBlockWrapper myPreviousBlock; - private LeafBlockWrapper myFirstTokenBlock; - private LeafBlockWrapper myLastTokenBlock; - private SpacingImpl myCurrentSpaceProperty; + + private final FormattingDocumentModel myModel; + private final FormatTextRanges myAffectedRanges; + private final int myPositionOfInterest; + @NotNull + private final FormattingProgressIndicator myProgressIndicator; private final CodeStyleSettings.IndentOptions myOptions; + + private final Stack myStates = new Stack(); + + private WhiteSpace myCurrentWhiteSpace; + private CompositeBlockWrapper myRootBlockWrapper; + private LeafBlockWrapper myPreviousBlock; + private LeafBlockWrapper myFirstTokenBlock; + private LeafBlockWrapper myLastTokenBlock; + private SpacingImpl myCurrentSpaceProperty; private ReadOnlyBlockInformationProvider myReadOnlyBlockInformationProvider; private InitialInfoBuilder(final FormattingDocumentModel model, final FormatTextRanges affectedRanges, final CodeStyleSettings.IndentOptions options, - final int positionOfInterest - ) { + final int positionOfInterest, + @NotNull FormattingProgressIndicator progressIndicator) + { myModel = model; myAffectedRanges = affectedRanges; + myProgressIndicator = progressIndicator; myCurrentWhiteSpace = new WhiteSpace(0, true); myOptions = options; myPositionOfInterest = positionOfInterest; } - public static InitialInfoBuilder buildBlocks(Block root, - FormattingDocumentModel model, - final FormatTextRanges affectedRanges, - final CodeStyleSettings.IndentOptions options, - int interestingOffset) { - final InitialInfoBuilder builder = new InitialInfoBuilder(model, affectedRanges, options, interestingOffset); - final AbstractBlockWrapper wrapper = builder.buildFrom(root, 0, null, null, null, true); - wrapper.setIndent((IndentImpl)Indent.getNoneIndent()); + public static InitialInfoBuilder prepareToBuildBlocksSequentially(Block root, + FormattingDocumentModel model, + final FormatTextRanges affectedRanges, + final CodeStyleSettings.IndentOptions options, + int interestingOffset, + @NotNull FormattingProgressIndicator progressIndicator) + { + InitialInfoBuilder builder = new InitialInfoBuilder(model, affectedRanges, options, interestingOffset, progressIndicator); + builder.buildFrom(root, 0, null, null, null, true); return builder; } + /** + * Asks current builder to wrap one more remaining {@link Block code block} (if any). + * + * @return true if all blocks are wrapped; false otherwise + */ + public boolean iteration() { + if (myStates.isEmpty()) { + return true; + } + + State state = myStates.peek(); + doIteration(state); + return myStates.isEmpty(); + } + /** * Wraps given root block and all of its descendants and returns root block wrapper. *

* This method performs necessary infrastructure actions and delegates actual processing to - * {@link #processCompositeBlock(Block, CompositeBlockWrapper, int, WrapImpl, boolean)} and + * {@link #buildCompositeBlock(Block, CompositeBlockWrapper, int, WrapImpl, boolean)} and * {@link #processSimpleBlock(Block, CompositeBlockWrapper, boolean, int, Block)}. * * @param rootBlock block to wrap @@ -147,67 +174,74 @@ class InitialInfoBuilder { } return wrapper; } - return processCompositeBlock(rootBlock, parent, index, currentWrapParent, rootBlockIsRightBlock); + return buildCompositeBlock(rootBlock, parent, index, currentWrapParent, rootBlockIsRightBlock); } finally { myReadOnlyBlockInformationProvider = previousProvider; } } - private AbstractBlockWrapper processCompositeBlock(final Block rootBlock, - final CompositeBlockWrapper parent, - final int index, - final WrapImpl currentWrapParent, - boolean rootBlockIsRightBlock - ) { - final CompositeBlockWrapper info = new CompositeBlockWrapper(rootBlock, myCurrentWhiteSpace, parent); + private CompositeBlockWrapper buildCompositeBlock(final Block rootBlock, + final CompositeBlockWrapper parent, + final int index, + final WrapImpl currentWrapParent, + boolean rootBlockIsRightBlock) + { + final CompositeBlockWrapper wrappedRootBlock = new CompositeBlockWrapper(rootBlock, myCurrentWhiteSpace, parent); if (index == 0) { - info.arrangeParentTextRange(); + wrappedRootBlock.arrangeParentTextRange(); } - if (myRootBlockWrapper == null) myRootBlockWrapper = info; + if (myRootBlockWrapper == null) { + myRootBlockWrapper = wrappedRootBlock; + myRootBlockWrapper.setIndent((IndentImpl)Indent.getNoneIndent()); + } boolean blocksMayBeOfInterest = false; if (myPositionOfInterest != -1) { - myResult.put(info, rootBlock); + myResult.put(wrappedRootBlock, rootBlock); blocksMayBeOfInterest = true; } - - Block previous = null; - List subBlocks = rootBlock.getSubBlocks(); - final int subBlocksCount = subBlocks.size(); - List list = new ArrayList(subBlocksCount); final boolean blocksAreReadOnly = rootBlock instanceof ReadOnlyBlockContainer || blocksMayBeOfInterest; - - for (int i = 0; i < subBlocksCount; i++) { - final Block block = subBlocks.get(i); - if (previous != null) { - myCurrentSpaceProperty = (SpacingImpl)rootBlock.getSpacing(previous, block); - } - - boolean childBlockIsRightBlock = false; - - if (i == subBlocksCount - 1 && rootBlockIsRightBlock) { - childBlockIsRightBlock = true; - } - - final AbstractBlockWrapper wrapper = buildFrom(block, i, info, currentWrapParent, rootBlock, childBlockIsRightBlock); - list.add(wrapper); - - if (wrapper.getIndent() == null) { - wrapper.setIndent((IndentImpl)block.getIndent()); - } - previous = block; - - if (!blocksAreReadOnly && !(subBlocks instanceof Unmodifiable) && !(subBlocks instanceof ImmutableCollection)) { - subBlocks.set(i, null); // to prevent extra strong refs during model building - } - } - setDefaultIndents(list); - info.setChildren(list); - return info; + + State state = new State(rootBlock, wrappedRootBlock, currentWrapParent, blocksAreReadOnly, rootBlockIsRightBlock); + myStates.push(state); + return wrappedRootBlock; } + private void doIteration(@NotNull State state) { + List subBlocks = state.parentBlock.getSubBlocks(); + final int subBlocksCount = subBlocks.size(); + int childBlockIndex = state.getIndexOfChildBlockToProcess(); + final Block block = subBlocks.get(childBlockIndex); + if (state.previousBlock != null) { + myCurrentSpaceProperty = (SpacingImpl)state.parentBlock.getSpacing(state.previousBlock, block); + } + + boolean childBlockIsRightBlock = false; + + if (childBlockIndex == subBlocksCount - 1 && state.parentBlockIsRightBlock) { + childBlockIsRightBlock = true; + } + + final AbstractBlockWrapper wrapper = buildFrom( + block, childBlockIndex, state.wrappedBlock, state.parentBlockWrap, state.parentBlock, childBlockIsRightBlock + ); + + if (wrapper.getIndent() == null) { + wrapper.setIndent((IndentImpl)block.getIndent()); + } + if (!state.readOnly && !(subBlocks instanceof Unmodifiable) && !(subBlocks instanceof ImmutableCollection)) { + subBlocks.set(childBlockIndex, null); // to prevent extra strong refs during model building + } + + if (state.childBlockProcessed(block, wrapper)) { + while (!myStates.isEmpty() && myStates.peek().isProcessed()) { + myStates.pop(); + } + } + } + private void setDefaultIndents(final List list) { if (!list.isEmpty()) { for (AbstractBlockWrapper wrapper : list) { @@ -222,9 +256,19 @@ class InitialInfoBuilder { final CompositeBlockWrapper parent, final boolean readOnly, final int index, - Block parentBlock + Block parentBlock) + { + LeafBlockWrapper result = doProcessSimpleBlock(rootBlock, parent, readOnly, index, parentBlock); + myProgressIndicator.afterWrappingBlock(result); + return result; + } - ) { + private LeafBlockWrapper doProcessSimpleBlock(final Block rootBlock, + final CompositeBlockWrapper parent, + final boolean readOnly, + final int index, + Block parentBlock) + { final LeafBlockWrapper info = new LeafBlockWrapper(rootBlock, parent, myCurrentWhiteSpace, myModel, myOptions, myPreviousBlock, readOnly); if (index == 0) { @@ -334,4 +378,70 @@ class InitialInfoBuilder { LOG.error(buffer); } + + /** + * We want to wrap {@link Block code blocks} sequentially, hence, need to store a processing state and continure from the point + * where we stopped the processing last time. + *

+ * Current class defines common contract for the state required for such a processing. + */ + private class State { + + public final Block parentBlock; + public final WrapImpl parentBlockWrap; + public final CompositeBlockWrapper wrappedBlock; + public final boolean readOnly; + public final boolean parentBlockIsRightBlock; + + public Block previousBlock; + + private final List myWrappedChildren = new ArrayList(); + + State(@NotNull Block parentBlock, @NotNull CompositeBlockWrapper wrappedBlock, @Nullable WrapImpl parentBlockWrap, + boolean readOnly, boolean parentBlockIsRightBlock) + { + this.parentBlock = parentBlock; + this.wrappedBlock = wrappedBlock; + this.parentBlockWrap = parentBlockWrap; + this.readOnly = readOnly; + this.parentBlockIsRightBlock = parentBlockIsRightBlock; + } + + /** + * @return index of the first non-processed {@link Block#getSubBlocks() child block} of the {@link #parentBlock target block} + */ + public int getIndexOfChildBlockToProcess() { + return myWrappedChildren.size(); + } + + /** + * Notifies current state that child block is processed. + * + * @return true if all child blocks of the block denoted by the current state are processed; + * false otherwise + */ + public boolean childBlockProcessed(@NotNull Block child, @NotNull AbstractBlockWrapper wrappedChild) { + myWrappedChildren.add(wrappedChild); + previousBlock = child; + + int subBlocksNumber = parentBlock.getSubBlocks().size(); + if (myWrappedChildren.size() > subBlocksNumber) { + return true; + } + else if (myWrappedChildren.size() == subBlocksNumber) { + setDefaultIndents(myWrappedChildren); + wrappedBlock.setChildren(myWrappedChildren); + return true; + } + return false; + } + + /** + * @return true if current state is processed (basically, if all {@link Block#getSubBlocks() child blocks}) + * of the {@link #parentBlock target block} are processed; false otherwise + */ + public boolean isProcessed() { + return myWrappedChildren.size() == parentBlock.getSubBlocks().size(); + } + } } diff --git a/platform/lang-impl/src/com/intellij/openapi/module/EmptyModuleType.java b/platform/lang-impl/src/com/intellij/openapi/module/EmptyModuleType.java index bae94974ff90..4465fc0bc1e1 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/EmptyModuleType.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/EmptyModuleType.java @@ -27,12 +27,13 @@ public class EmptyModuleType extends ModuleType { private static final Icon NODE_ICON_OPEN = IconLoader.getIcon("/nodes/ModuleOpen.png"); private static final Icon NODE_ICON_CLOSED = IconLoader.getIcon("/nodes/ModuleClosed.png"); @NonNls public static final String EMPTY_MODULE = "EMPTY_MODULE"; - private static final EmptyModuleType ourInstance = new EmptyModuleType(); + //private static final EmptyModuleType ourInstance = new EmptyModuleType(); public static EmptyModuleType getInstance() { - return ourInstance; + return (EmptyModuleType)ModuleType.EMPTY; } + @SuppressWarnings({"UnusedDeclaration"}) // implicitly instantiated from ModuleType public EmptyModuleType() { this(EMPTY_MODULE); } diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java b/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java index ca0295ebca2d..8d01f291fc81 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -137,7 +138,13 @@ public class DocumentBasedFormattingModel implements FormattingModel { } public void commitChanges() { - PsiDocumentManager.getInstance(myProject).commitDocument(myDocument); + CodeEditUtil.allowToMarkNodesForPostponedFormatting(false); + try { + PsiDocumentManager.getInstance(myProject).commitDocument(myDocument); + } + finally { + CodeEditUtil.allowToMarkNodesForPostponedFormatting(true); + } } private int shiftIndentInside(final TextRange elementRange, final int shift) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java index b4fd690afdd1..0237d6756ade 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeEditUtil.java @@ -47,6 +47,12 @@ public class CodeEditUtil { private static final Key INDENT_INFO = new Key("INDENT_INFO"); private static final Key REFORMAT_BEFORE_KEY = new Key("REFORMAT_BEFORE_KEY"); private static final Key REFORMAT_KEY = new Key("REFORMAT_KEY"); + private static final ThreadLocal ALLOW_TO_MARK_NODES_TO_REFORMAT = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return Boolean.TRUE; + } + }; public static final Key OUTER_OK = new Key("OUTER_OK"); @@ -430,6 +436,34 @@ public class CodeEditUtil { * @param value true if the element should be reformatted; false otherwise */ public static void markToReformat(final ASTNode node, boolean value) { - node.putCopyableUserData(REFORMAT_KEY, value ? true : null); + if (ALLOW_TO_MARK_NODES_TO_REFORMAT.get()) { + node.putCopyableUserData(REFORMAT_KEY, value ? true : null); + } + } + + /** + * We allow to mark particular {@link ASTNode AST nodes} to be reformatted later (e.g. we may want method definition and calls + * to be reformatted when we perform 'change method signature' refactoring. Hence, we mark corresponding expressions + * to be reformatted). + *

+ * For convenience that is made automatically on AST/PSI level, i.e. every time target element change it automatically marks itself + * to be reformatted. + *

+ * However, there is a possible case that particular element is changed because of formatting, hence, there is no need to mark + * itself for postponed formatting one more time. This method allows to configure allowance of reformat markers processing + * for the calling thread. I.e. this method may be called with 'false' as an argument, hence, all further attempts + * to {@link #markToReformat(ASTNode, boolean) mark node for postponed formatting} will have no effect until current method is + * called with 'true' as an argument. Hence, following usage scenario is expected: + *

    + *
  1. this method is called with 'false' argument;
  2. + *
  3. formatting is performed at dedicated 'try' block;
  4. + *
  5. this method is called with 'false' argument from 'finally' section;
  6. + *
+ * + * @param allow flag that defines if new reformat markers can be added from the current thread + * @see #markToReformat(ASTNode, boolean) + */ + public static void allowToMarkNodesForPostponedFormatting(boolean allow) { + ALLOW_TO_MARK_NODES_TO_REFORMAT.set(allow); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index a6d8152bc3ff..4708ab4c5307 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java @@ -187,7 +187,9 @@ public class CodeFormatterFacade { document, project, mySettings, file.getFileType(), file); - FormatterEx.getInstanceEx().format(model, mySettings, mySettings.getIndentOptions(file.getFileType()), ranges); + FormatterEx formatter = FormatterEx.getInstanceEx(); + formatter.setProgressIndicator(new FormattingProgressIndicatorImpl(project, file, document)); + formatter.format(model, mySettings, mySettings.getIndentOptions(file.getFileType()), ranges); for (FormatTextRanges.FormatTextRange range : textRanges) { TextRange textRange = range.getTextRange(); wrapLongLinesIfNecessary(file, document, textRange.getStartOffset(), textRange.getEndOffset()); 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 9babf16bbf86..d54a659b2deb 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -1052,11 +1052,26 @@ public class FileBasedIndex implements ApplicationComponent { } } - private Set getUnsavedOrTransactedDocuments() { + private Set getUnsavedOrTransactedDocuments(Project project) { Set docs = new HashSet(Arrays.asList(myFileDocumentManager.getUnsavedDocuments())); synchronized (myTransactionMap) { docs.addAll(myTransactionMap.keySet()); } + + if (project != null) { + // filter out foreign documents + Iterator iterator = docs.iterator(); + ProjectLocator projectLocator = ProjectLocator.getInstance(); + while (iterator.hasNext()) { + Document document = iterator.next(); + VirtualFile virtualFile = myFileDocumentManager.getFile(document); + if (virtualFile == null) continue; + Project guessed = projectLocator.guessProjectForFile(virtualFile); + if (guessed != null && guessed != project) { + iterator.remove(); + } + } + } return docs; } @@ -1066,7 +1081,7 @@ public class FileBasedIndex implements ApplicationComponent { return; // no need to index unsaved docs } - final Set documents = getUnsavedOrTransactedDocuments(); + final Set documents = getUnsavedOrTransactedDocuments(project); if (!documents.isEmpty()) { // now index unsaved data final StorageGuard.Holder guard = setDataBufferingEnabled(true); @@ -1075,8 +1090,8 @@ public class FileBasedIndex implements ApplicationComponent { assert semaphore != null : "Semaphore for unsaved data indexing was not initialized for index " + indexId; - boolean allDocsProcessed = true; semaphore.down(); + boolean allDocsProcessed = true; try { for (Document document : documents) { allDocsProcessed &= indexUnsavedDocument(document, indexId, project, filter); @@ -1215,14 +1230,13 @@ public class FileBasedIndex implements ApplicationComponent { public static final Key VIRTUAL_FILE = new Key("Context virtual file"); @Nullable - private PsiFile findDominantPsiForDocument(final Document document, @Nullable Project project) { + private PsiFile findDominantPsiForDocument(@NotNull Document document, @Nullable Project project) { synchronized (myTransactionMap) { - if (myTransactionMap.containsKey(document)) { - return myTransactionMap.get(document); - } + PsiFile psiFile = myTransactionMap.get(document); + if (psiFile != null) return psiFile; } - return project == null? null : findLatestKnownPsiForUncomittedDocument(document, project); + return project == null ? null : findLatestKnownPsiForUncomittedDocument(document, project); } private final StorageGuard myStorageLock = new StorageGuard(); @@ -1873,7 +1887,7 @@ public class FileBasedIndex implements ApplicationComponent { } @Nullable - private static PsiFile findLatestKnownPsiForUncomittedDocument(Document doc, Project project) { + private static PsiFile findLatestKnownPsiForUncomittedDocument(@NotNull Document doc, @NotNull Project project) { return PsiDocumentManager.getInstance(project).getCachedPsiFile(doc); } diff --git a/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java b/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java index ab25345b030f..c60a76a73da0 100644 --- a/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java +++ b/platform/lang-impl/testSrc/com/intellij/lang/PsiBuilderQuickTest.java @@ -17,6 +17,7 @@ package com.intellij.lang; import com.intellij.lang.impl.PsiBuilderImpl; import com.intellij.lexer.LexerBase; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.psi.TokenType; @@ -64,7 +65,7 @@ public class PsiBuilderQuickTest { @BeforeClass public static void setUp() { - if (ApplicationManagerEx.getApplication() == null) { + if (ApplicationManager.getApplication() == null) { if (myMockApp == null) { myMockApp = createMock(ApplicationEx.class); expect(myMockApp.isInternal()).andReturn(true); @@ -466,7 +467,7 @@ public class PsiBuilderQuickTest { " PsiElement(OTHER)('}')\n"); } - private static abstract class MyLazyElementType extends ILazyParseableElementType implements ILightLazyParseableElementType { + private abstract static class MyLazyElementType extends ILazyParseableElementType implements ILightLazyParseableElementType { protected MyLazyElementType(@NonNls String debugName) { super(debugName, Language.ANY); } diff --git a/platform/platform-api/src/com/intellij/execution/configurations/CommandLineTokenizer.java b/platform/platform-api/src/com/intellij/execution/configurations/CommandLineTokenizer.java new file mode 100644 index 000000000000..0fc5654e909f --- /dev/null +++ b/platform/platform-api/src/com/intellij/execution/configurations/CommandLineTokenizer.java @@ -0,0 +1,87 @@ +package com.intellij.execution.configurations; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * Splits input String to tokens being aware of quoted tokens, + * usually used for splitting command line to separate arguments that may contain space symbols. + * Escaped symbols are not handled so there's no way to get token that itself contains quotation mark. + */ +public class CommandLineTokenizer extends StringTokenizer { + + private static String DEFAULT_DELIMITERS = " \t\n\r\f"; + // keep source level 1.4 + private List myTokens = new ArrayList(); + private int myCurrentToken = 0; + + public CommandLineTokenizer(String str) { + super(str, DEFAULT_DELIMITERS, true); + parseTokens(); + } + + public CommandLineTokenizer(String str, String delim) { + super(str, delim, true); + parseTokens(); + } + + public boolean hasMoreTokens() { + return myCurrentToken < myTokens.size(); + } + + public String nextToken() { + return (String) myTokens.get(myCurrentToken++); + } + + public int countTokens() { + return myTokens.size() - myCurrentToken; + } + + + public String nextToken(String delim) { + throw new UnsupportedOperationException(); + } + + private void parseTokens() { + String token; + while ((token = nextTokenInternal()) != null) { + myTokens.add(token); + } + } + + private String nextTokenInternal() { + String nextToken; + do { + if (super.hasMoreTokens()) { + nextToken = super.nextToken(); + } else { + nextToken = null; + } + } while (nextToken != null && nextToken.length() == 1 && DEFAULT_DELIMITERS.indexOf(nextToken.charAt(0)) >= 0); + + if (nextToken == null) { + return null; + } + + int i; + int quotationMarks = 0; + final StringBuffer buffer = new StringBuffer(); + + do { + while ((i = nextToken.indexOf('"')) >= 0) { + quotationMarks++; + buffer.append(nextToken.substring(0, i)); + nextToken = nextToken.substring(i + 1); + } + buffer.append(nextToken); + if (quotationMarks % 2 == 1 && super.hasMoreTokens()) { + nextToken = super.nextToken(); + } else { + nextToken = null; + } + } while (nextToken != null); + + return buffer.toString(); + } +} \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/execution/process/CommandLineArgumentsProvider.java b/platform/platform-api/src/com/intellij/execution/process/CommandLineArgumentsProvider.java index 4bd59d27ff5d..f708e6a6c553 100644 --- a/platform/platform-api/src/com/intellij/execution/process/CommandLineArgumentsProvider.java +++ b/platform/platform-api/src/com/intellij/execution/process/CommandLineArgumentsProvider.java @@ -17,23 +17,25 @@ package com.intellij.execution.process; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.Nullable; +import java.util.Collections; import java.util.Map; /** * @author Roman.Chernyatchik, oleg */ -public abstract class CommandLineArgumentsProvider { +public class CommandLineArgumentsProvider { /** * @return Commands to execute (one command corresponds to one add argument) */ - public abstract String[] getArguments(); + public String[] getArguments() { return ArrayUtil.EMPTY_STRING_ARRAY; } - public abstract boolean passParentEnvs(); + public boolean passParentEnvs() { return false; } @Nullable - public abstract Map getAdditionalEnvs(); + public Map getAdditionalEnvs() { return Collections.emptyMap(); } public String getCommandLineString() { diff --git a/platform/platform-api/src/com/intellij/execution/util/ExecutableValidator.java b/platform/platform-api/src/com/intellij/execution/util/ExecutableValidator.java index 0bf4efa93977..212ca37c6cae 100644 --- a/platform/platform-api/src/com/intellij/execution/util/ExecutableValidator.java +++ b/platform/platform-api/src/com/intellij/execution/util/ExecutableValidator.java @@ -122,8 +122,13 @@ public abstract class ExecutableValidator { } public boolean showDialog() { - ExecutableDialog dialog = new ExecutableDialog(myProject, this); - dialog.show(); + final ExecutableDialog dialog = new ExecutableDialog(myProject, this); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + dialog.show(); + } + }); if (dialog.isOK()) { saveCurrentExecutable(dialog.getPath()); return true; diff --git a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDescriptor.java b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDescriptor.java index 5cdede04c27a..17e83681136a 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDescriptor.java +++ b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDescriptor.java @@ -33,12 +33,12 @@ import java.util.List; import java.util.Map; public class FileChooserDescriptor implements Cloneable{ - private final boolean myChooseFiles; - private final boolean myChooseFolders; - private final boolean myChooseJars; - private final boolean myChooseJarsAsFiles; - private final boolean myChooseJarContents; - private final boolean myChooseMultiple; + private boolean myChooseFiles; + private boolean myChooseFolders; + private boolean myChooseJars; + private boolean myChooseJarsAsFiles; + private boolean myChooseJarContents; + private boolean myChooseMultiple; private String myTitle = UIBundle.message("file.chooser.default.title"); private String myDescription; @@ -74,6 +74,15 @@ public class FileChooserDescriptor implements Cloneable{ myChooseMultiple = chooseMultiple; } + public FileChooserDescriptor() { + this(false, false, false, false, false, false); + } + + public FileChooserDescriptor chooseFolders() { + myChooseFolders = true; + return this; + } + public final String getTitle() { return myTitle; } diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java index 6c0a2151931e..6d708c9103cd 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java @@ -141,7 +141,7 @@ public abstract class FileEditorManager { /** * Adds specified listener * @param listener listener to be added - * @deprecated Use MessageBus instead + * @deprecated Use MessageBus instead: see {@link FileEditorManagerListener#FILE_EDITOR_MANAGER} */ public abstract void addFileEditorManagerListener(@NotNull FileEditorManagerListener listener); diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index aff4263398ee..eb099fce193a 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -433,7 +433,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { } g.setColor(color); - final int textBaseline = (getHeight() - metrics.getHeight()) / 2 + metrics.getAscent(); + final int textBaseline = getTextBaseLine(metrics, getHeight()); if (!attributes.isSearchMatch()) g.drawString(fragment, xOffset, textBaseline); @@ -497,6 +497,16 @@ public class SimpleColoredComponent extends JComponent implements Accessible { } } + @Override + public int getBaseline(int width, int height) { + super.getBaseline(width, height); + return getTextBaseLine(getFontMetrics(getFont()), height); + } + + private static int getTextBaseLine(FontMetrics metrics, final int height) { + return (height - metrics.getHeight()) / 2 + metrics.getAscent(); + } + private static void checkCanPaint(Graphics g) { if (UIUtil.isPrinting(g)) return; diff --git a/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java b/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java index 60e026f93b3e..b1d095ac5870 100644 --- a/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java +++ b/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java @@ -17,15 +17,18 @@ package com.intellij.util.concurrency; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.Pair; import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; +import java.util.*; /** *

QueueProcessor processes elements which are being added to a queue via {@link #add(Object)} and {@link #addFirst(Object)} methods.

@@ -48,6 +51,7 @@ public class QueueProcessor { private final ThreadToUse myThreadToUse; private final Condition myDeathCondition; + private final Map myModalityState; /** * Constructs a QueueProcessor with the given processor and autostart setting. @@ -65,6 +69,7 @@ public class QueueProcessor { myStarted = autostart; myThreadToUse = threadToUse; myDeathCondition = deathCondition; + myModalityState = new HashMap(); myContinuationContext = new Runnable() { @Override @@ -85,6 +90,11 @@ public class QueueProcessor { this(wrappingProcessor(processor), autostart, ThreadToUse.POOLED, deathCondition); } + public void add(T t, ModalityState state) { + myModalityState.put(new MyOverrideEquals(t), state); + doAdd(t, false); + } + private static PairConsumer wrappingProcessor(final Consumer processor) { return new PairConsumer() { @Override @@ -176,7 +186,12 @@ public class QueueProcessor { }; final Application application = ApplicationManager.getApplication(); if (ThreadToUse.AWT.equals(myThreadToUse)) { - application.invokeLater(runnable); + final ModalityState state = myModalityState.remove(new MyOverrideEquals(item)); + if (state != null) { + application.invokeLater(runnable, state); + } else { + application.invokeLater(runnable); + } } else { application.executeOnPooledThread(runnable); } @@ -193,4 +208,22 @@ public class QueueProcessor { AWT, POOLED } + + private static class MyOverrideEquals { + private final Object myDelegate; + + private MyOverrideEquals(Object delegate) { + myDelegate = delegate; + } + + @Override + public int hashCode() { + return myDelegate.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return ((MyOverrideEquals) obj).myDelegate == myDelegate; + } + } } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java index e8abfbfcd70b..c9291dc10394 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java @@ -369,7 +369,7 @@ public class HintManagerImpl extends HintManager implements Disposable { p = rectangle.getLocation(); SwingUtilities.convertPointFromScreen(p, layeredPane); } - else if ((layeredPane.getWidth() < p.x + size.width) && !hintInfo.isAwtTooltip()) { + else if ((layeredPane.getWidth() < p.x + size.width) && !hintInfo.isAwtTooltip() && !hint.isRealPopup()) { p.x = Math.max(0, layeredPane.getWidth() - size.width); } diff --git a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java index 7d4d43dd76c1..4de43e5babbb 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java @@ -472,7 +472,8 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener if (prefSizeOriginal.width > fitWidth) { setSize(new Dimension(fitWidth, Integer.MAX_VALUE)); Dimension fixedWidthSize = super.getPreferredSize(); - prefSize.set(new Dimension(fitWidth, fixedWidthSize.height)); + Dimension minSize = super.getMinimumSize(); + prefSize.set(new Dimension(fitWidth > minSize.width ? fitWidth : minSize.width, fixedWidthSize.height)); } else { prefSize.set(new Dimension(prefSizeOriginal)); diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java index 42fbeae96ca5..3be56bce173b 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java @@ -38,6 +38,7 @@ import com.intellij.openapi.util.Iconable; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; @@ -588,7 +589,12 @@ public class Switcher extends AnAction implements DumbAware { } else if (value instanceof VirtualFile) { final VirtualFile file = (VirtualFile)value; - FileEditorManager.getInstance(project).openFile(file, true, true); + IdeFocusManager.getInstance(project).doWhenFocusSettlesDown(new Runnable() { + @Override + public void run() { + FileEditorManager.getInstance(project).openFile(file, true, true); + } + }); } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java b/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java index 1f4967964880..e9f22adf8b75 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/ActionInstallPlugin.java @@ -85,7 +85,7 @@ public class ActionInstallPlugin extends AnAction implements DumbAware { else if (descr instanceof IdeaPluginDescriptorImpl) { pluginNode = new PluginNode(descr.getPluginId()); pluginNode.setName(descr.getName()); - pluginNode.setDepends(Arrays.asList(descr.getDependentPluginIds())); + pluginNode.setDepends(Arrays.asList(descr.getDependentPluginIds()), descr.getOptionalDependentPluginIds()); pluginNode.setSize("-1"); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginNode.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginNode.java index c5fcd1d51e6c..3bbc90df1de1 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginNode.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginNode.java @@ -56,6 +56,7 @@ public class PluginNode implements IdeaPluginDescriptor { private String url; private long date = Long.MAX_VALUE; private List depends; + private PluginId[] myOptionalDependencies; private int status = STATUS_UNKNOWN; private boolean loaded = false; @@ -221,8 +222,9 @@ public class PluginNode implements IdeaPluginDescriptor { return depends; } - public void setDepends(List depends) { + public void setDepends(List depends, PluginId[] optionalDependencies) { this.depends = depends; + myOptionalDependencies = optionalDependencies; } @@ -258,7 +260,7 @@ public class PluginNode implements IdeaPluginDescriptor { @Nullable public PluginId[] getOptionalDependentPluginIds() { - return null; + return myOptionalDependencies; } @Nullable diff --git a/platform/platform-impl/src/com/intellij/ide/util/ChooseElementsDialog.java b/platform/platform-impl/src/com/intellij/ide/util/ChooseElementsDialog.java index 19e701b5fffb..c7a73dbbd8c9 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/ChooseElementsDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/util/ChooseElementsDialog.java @@ -88,10 +88,18 @@ public abstract class ChooseElementsDialog extends DialogWrapper { init(); } + public List showAndGetResult() { + show(); + return getChosenElements(); + } + protected abstract String getItemText(T item); + @Nullable + protected abstract Icon getItemIcon(T item); + public List getChosenElements() { - return myChooser.getSelectedElements(); + return isOK() ? myChooser.getSelectedElements() : Collections.emptyList(); } public void selectElements(@NotNull List elements) { @@ -130,7 +138,4 @@ public abstract class ChooseElementsDialog extends DialogWrapper { } }; } - - @Nullable - protected abstract Icon getItemIcon(T item); } diff --git a/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java b/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java index 19703b9bbe16..04f695012f0e 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java +++ b/platform/platform-impl/src/com/intellij/ide/util/ElementsChooser.java @@ -34,6 +34,9 @@ import java.awt.event.KeyEvent; import java.util.*; import java.util.List; +/** + * @see ChooseElementsDialog + */ public class ElementsChooser extends JPanel implements ComponentWithEmptyText, ComponentWithExpandableItems { private JBTable myTable = null; private MyTableModel myTableModel = null; @@ -42,7 +45,7 @@ public class ElementsChooser extends JPanel implements ComponentWithEmptyText private final Map myElementToPropertiesMap = new HashMap(); private final Map myDisabledMap = new HashMap(); - public static interface ElementsMarkListener { + public interface ElementsMarkListener { void elementMarkChanged(T element, boolean isMarked); } diff --git a/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java new file mode 100644 index 000000000000..e90aa6a7b251 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesAction.java @@ -0,0 +1,67 @@ +/* + * 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.internal.focus; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.openapi.wm.impl.FocusManagerImpl; +import com.intellij.openapi.wm.impl.FocusRequestInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class FocusTracesAction extends AnAction implements DumbAware { + private static boolean myActive = false; + + public static boolean isActive() { + return myActive; + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = e.getData(PlatformDataKeys.PROJECT); + final IdeFocusManager manager = IdeFocusManager.getGlobalInstance(); + if (! (manager instanceof FocusManagerImpl)) return; + final FocusManagerImpl focusManager = (FocusManagerImpl)manager; + + myActive = !myActive; + + if (!myActive) { + final List requests = focusManager.getRequests(); + new FocusTracesDialog(project, new ArrayList(requests)).show(); + requests.clear(); + } + } + + @Override + public void update(AnActionEvent e) { + final Presentation presentation = e.getPresentation(); + if (myActive) { + presentation.setText("Stop Focus Tracing"); + } else { + presentation.setText("Start Focus Tracing"); + } + presentation.setEnabled(e.getData(PlatformDataKeys.PROJECT) != null); + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesDialog.form b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesDialog.form new file mode 100644 index 000000000000..9dc1d1074339 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesDialog.form @@ -0,0 +1,54 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesDialog.java b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesDialog.java new file mode 100644 index 000000000000..b44576067612 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/internal/focus/FocusTracesDialog.java @@ -0,0 +1,159 @@ +/* + * 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.internal.focus; + +import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.wm.impl.FocusRequestInfo; +import com.intellij.ui.table.JBTable; +import com.intellij.util.ui.UIUtil; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class FocusTracesDialog extends DialogWrapper { + private JTextPane myStacktrace; + private JBTable myRequestsTable; + private JPanel myRootPanel; + private final List myRequests; + private static final String[] COLUMNS = {"Time", "Forced", "Component"}; + + public FocusTracesDialog(Project project, ArrayList requests) { + super(project); + myRequests = requests; + setTitle("Focus Traces"); + init(); + final String[][] data = new String[requests.size()][]; + for (int i = 0; i < data.length; i++) { + final FocusRequestInfo r = requests.get(i); + data[i] = new String[]{r.getDate(), String.valueOf(r.isForced()), String.valueOf(r.getComponent())}; + } + myRequestsTable.setModel(new DefaultTableModel(data, COLUMNS)); + final ListSelectionListener selectionListener = new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + final int index = myRequestsTable.getSelectedRow(); + if (-1 < index && index < myRequests.size()) { + myStacktrace.setText(myRequests.get(index).getStackTrace()); + } + else { + myStacktrace.setText(""); + } + } + }; + myRequestsTable.getSelectionModel().addListSelectionListener(selectionListener); + final TableColumnModel columnModel = myRequestsTable.getColumnModel(); + columnModel.getColumn(0).setMaxWidth(120); + columnModel.getColumn(1).setMaxWidth(60); + columnModel.getSelectionModel().addListSelectionListener(selectionListener); + columnModel.setColumnSelectionAllowed(false); + myRequestsTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + myRequestsTable.changeSelection(0, 0, false, true); + } + + @Override + protected String getDimensionServiceKey() { + return "ide.internal.focus.trace.dialog"; + } + + @Override + protected JComponent createCenterPanel() { + return myRootPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myRequestsTable; + } + + @Override + protected Action[] createActions() { + return new Action[] {getOKAction(), getCopyStackTraceAction()}; + } + + private Action getCopyStackTraceAction() { + return new AbstractAction("&Copy stacktrace") { + @Override + public void actionPerformed(ActionEvent e) { + CopyPasteManager.getInstance().setContents(new StringSelection(myStacktrace.getText())); + } + }; + } + + @Override + public void show() { + final BorderDrawer drawer = new BorderDrawer(); + drawer.start(); + super.show(); + drawer.setDone(); + } + + class BorderDrawer extends Thread { + Component prev = null; + private volatile boolean running = true; + BorderDrawer() { + super("Focus Border Drawer"); + } + + @Override + public void run() { + try { + while (running) { + sleep(100); + paintBorder(); + } + if (prev != null) { + prev.repaint(); + } + } + catch (InterruptedException e) {// + } + } + + private void paintBorder() { + final int row = FocusTracesDialog.this.myRequestsTable.getSelectedRow(); + if (row != -1) { + final FocusRequestInfo info = FocusTracesDialog.this.myRequests.get(row); + if (prev != null && prev != info.getComponent()) { + prev.repaint(); + } + prev = info.getComponent(); + if (prev != null && prev.isDisplayable()) { + final Graphics g = prev.getGraphics(); + g.setColor(Color.RED); + final Dimension sz = prev.getSize(); + UIUtil.drawDottedRectangle(g, 1, 1, sz.width - 2, sz.height - 2); + } + } + } + + public void setDone() { + running = false; + } + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistence.java b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistence.java index b5021df47287..2b5586ec17c4 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistence.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistence.java @@ -24,9 +24,10 @@ public abstract class ApplicationStatisticsPersistence { @NotNull public Map> getApplicationData(@NotNull GroupDescriptor groupDescriptor) { - final Map> map = myApplicationData.get(groupDescriptor); - - return map == null ? new HashMap>(): map; + if (!myApplicationData.containsKey(groupDescriptor)) { + myApplicationData.put(groupDescriptor, new HashMap>()); + } + return myApplicationData.get(groupDescriptor); } @NotNull diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java index fb8d0fd6bffe..23b03085c414 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java @@ -16,10 +16,12 @@ package com.intellij.internal.statistic.persistence; +import com.intellij.ide.AppLifecycleListener; import com.intellij.internal.statistic.AbstractApplicationUsagesCollector; import com.intellij.internal.statistic.UsagesCollector; import com.intellij.internal.statistic.beans.GroupDescriptor; import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ApplicationComponent; @@ -30,9 +32,11 @@ import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerListener; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.containers.HashSet; +import com.intellij.util.messages.MessageBus; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -52,6 +56,8 @@ import java.util.Set; ) public class ApplicationStatisticsPersistenceComponent extends ApplicationStatisticsPersistence implements ApplicationComponent, PersistentStateComponent { + private boolean persistOnClosing = true; + private static final String TOKENIZER = ","; @NonNls @@ -152,6 +158,11 @@ public class ApplicationStatisticsPersistenceComponent extends ApplicationStatis } public void initComponent() { + onAppClosing(); + onProjectClosing(); + } + + private void onProjectClosing() { ProjectManager.getInstance().addProjectManagerListener(new ProjectManagerListener() { @Override public void projectOpened(Project project) { @@ -169,16 +180,56 @@ public class ApplicationStatisticsPersistenceComponent extends ApplicationStatis @Override public void projectClosing(Project project) { if (project != null) { - for (UsagesCollector usagesCollector : Extensions.getExtensions(UsagesCollector.EP_NAME)) { - if (usagesCollector instanceof AbstractApplicationUsagesCollector) { - ((AbstractApplicationUsagesCollector) usagesCollector).persistProjectUsages(project); - } + if (persistOnClosing) { + doPersistProjectUsages(project); } } } }); } + private static void doPersistProjectUsages(@NotNull Project project) { + for (UsagesCollector usagesCollector : Extensions.getExtensions(UsagesCollector.EP_NAME)) { + if (usagesCollector instanceof AbstractApplicationUsagesCollector) { + ((AbstractApplicationUsagesCollector) usagesCollector).persistProjectUsages(project); + } + } + } + + private void onAppClosing() { + final MessageBus messageBus = ApplicationManager.getApplication().getMessageBus(); + + messageBus.connect().subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener() { + @Override + public void appFrameCreated(String[] commandLineArgs, @NotNull Ref willOpenProject) { + } + + @Override + public void appStarting(Project projectFromCommandLine) { + } + + @Override + public void projectFrameClosed() { + } + + @Override + public void projectOpenFailed() { + } + + @Override + public void welcomeScreenDisplayed() { + } + + @Override + public void appClosing() { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + doPersistProjectUsages(project); + } + persistOnClosing = false; + } + }); + } + public void disposeComponent() { } } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index c32c952d4cb2..eee3ef34f7d8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -1209,6 +1209,11 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application @Override public String toString() { - return "Application"; + return "Application" + + (isDisposed() ? " (Disposed)" : "") + + (isUnitTestMode() ? " (Unit test)" : "") + + (isInternal() ? " (Internal)" : "") + + (isHeadlessEnvironment() ? " (Headless)" : "") + + (isCommandLine() ? " (Command line)" : ""); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index 0cecdf25f2d8..6d90ee6f7eb6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -41,6 +41,7 @@ import com.intellij.util.pico.IdeaPicoContainer; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.picocontainer.*; import org.picocontainer.defaults.CachingComponentAdapter; import org.picocontainer.defaults.ConstructorInjectionComponentAdapter; @@ -211,7 +212,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements } public T getComponent(Class interfaceClass) { - assert !myDisposeCompleted : "Already disposed"; + assert !myDisposeCompleted : "Already disposed: "+this; return getComponent(interfaceClass, null); } @@ -375,9 +376,14 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements } public boolean isDisposed() { - return myDisposed; + return myDisposed || temporarilyDisposed; } + private volatile boolean temporarilyDisposed = false; + @TestOnly + public void setTemporarilyDisposed(boolean disposed) { + temporarilyDisposed = disposed; + } public void initComponents() { createComponents(); @@ -391,7 +397,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements protected void boostrapPicoContainer() { myPicoContainer = createPicoContainer(); - myMessageBus = MessageBusFactory.newMessageBus(this, myParentComponentManager != null ? myParentComponentManager.getMessageBus() : null); + myMessageBus = MessageBusFactory.newMessageBus(this, myParentComponentManager == null ? null : myParentComponentManager.getMessageBus()); final MutablePicoContainer picoContainer = getPicoContainer(); picoContainer.registerComponentInstance(MessageBus.class, myMessageBus); /* diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 09442c02bd0f..e003cb69d206 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -5552,7 +5552,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi maxWidth = Math.max(maxWidth, myLineWidths.getQuick(i)); } - mySize = new Dimension(maxWidth, getLineHeight() * getVisibleLineCount()); + mySize = new Dimension(maxWidth, getLineHeight() * Math.max(getVisibleLineCount(), 1)); myIsDirty = false; } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java index 1d1e2b5a0e29..dd2c56c12d81 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/BackgroundTaskQueue.java @@ -17,13 +17,20 @@ package com.intellij.openapi.progress; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.PairConsumer; import com.intellij.util.concurrency.QueueProcessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; /** * Runs backgroundable tasks one by one. @@ -37,21 +44,22 @@ import com.intellij.util.concurrency.QueueProcessor; public class BackgroundTaskQueue { private static final Logger LOG = Logger.getInstance(BackgroundTaskQueue.class.getName()); //private final Project myProject; - private final QueueProcessor myProcessor; + private final QueueProcessor>> myProcessor; private Boolean myForcedTestMode; - public BackgroundTaskQueue(final Project project, String title) { + public BackgroundTaskQueue(@Nullable Project project, @NotNull String title) { this(project, title, null); } - public BackgroundTaskQueue(final Project project, String title, final Boolean forcedHeadlessMode) { + public BackgroundTaskQueue(@Nullable final Project project, @NotNull String title, final Boolean forcedHeadlessMode) { final boolean headless = forcedHeadlessMode != null ? forcedHeadlessMode : ApplicationManager.getApplication().isHeadlessEnvironment(); - myProcessor = new QueueProcessor(headless ? + myProcessor = new QueueProcessor>>(headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project), true, headless ? QueueProcessor.ThreadToUse.POOLED : QueueProcessor.ThreadToUse.AWT, new Condition() { @Override public boolean value(Object o) { - return (! ApplicationManager.getApplication().isUnitTestMode()) && (! project.isOpen()) || project.isDisposed(); + if (project == null) return ApplicationManager.getApplication().isDisposed(); + return !ApplicationManager.getApplication().isUnitTestMode() && !project.isOpen() || project.isDisposed(); } }); } @@ -65,23 +73,28 @@ public class BackgroundTaskQueue { } public void run(Task.Backgroundable task) { + run(task, null, null); + } + + public void run(Task.Backgroundable task, final ModalityState state, final Getter pi) { if (isTestMode()) { // test tasks are executed in this thread without the progress manager RunBackgroundable.runIfBackgroundThread(task, new EmptyProgressIndicator(), null); } else { - myProcessor.add(task); + myProcessor.add(new Pair>(task, pi), state); } } - private static class BackgroundableHeadlessRunner implements PairConsumer { + private static class BackgroundableHeadlessRunner implements PairConsumer>, Runnable> { @Override - public void consume(Task.Backgroundable backgroundable, Runnable runnable) { + public void consume(Pair> pair, Runnable runnable) { + final Task.Backgroundable backgroundable = pair.getFirst(); // synchronously ProgressManager.getInstance().run(backgroundable); runnable.run(); } } - private static class BackgroundableUnderProgressRunner implements PairConsumer { + private static class BackgroundableUnderProgressRunner implements PairConsumer>, Runnable> { private final String myTitle; private final Project myProject; @@ -91,7 +104,8 @@ public class BackgroundTaskQueue { } @Override - public void consume(final Task.Backgroundable backgroundable, final Runnable runnable) { + public void consume(final Pair> pair, final Runnable runnable) { + final Task.Backgroundable backgroundable = pair.getFirst(); final ProgressIndicator[] pi = new ProgressIndicator[1]; final boolean taskTitleIsEmpty = StringUtil.isEmptyOrSpaces(backgroundable.getTitle()); @@ -109,7 +123,12 @@ public class BackgroundTaskQueue { pm.runProcessWithProgressSynchronously(wrappedTask, taskTitleIsEmpty ? myTitle : backgroundable.getTitle(), backgroundable.isCancellable(), myProject); } else { - pi[0] = new BackgroundableProcessIndicator(backgroundable); + if (pair.getSecond() != null) { + pi[0] = pair.getSecond().get(); + } + if (pi[0] == null) { + pi[0] = new BackgroundableProcessIndicator(backgroundable); + } if (taskTitleIsEmpty) { ((BackgroundableProcessIndicator) pi[0]).setTitle(myTitle); } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindow.java b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindow.java index 4a8682c16c7d..c055dd7739a8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindow.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindow.java @@ -51,26 +51,34 @@ import java.io.File; public class ProgressWindow extends BlockingProgressIndicator implements Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.util.ProgressWindow"); + /** + * This constant defines default delay for showing progress dialog (in millis). + * + * @see #setDelayInMillis(int) + */ + public static final int DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS = 300; + private static final int UPDATE_INTERVAL = 50; //msec. 20 frames per second. private MyDialog myDialog; - private final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + private final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); private final Alarm myInstallFunAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); private final Alarm myShowWindowAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); private final Project myProject; private final boolean myShouldShowCancel; - private String myCancelText; + private String myCancelText; private String myTitle = null; private boolean myStoppedAlready = false; protected final FocusTrackback myFocusTrackback; - private boolean myStarted = false; + private boolean myStarted = false; private boolean myBackgrounded = false; private boolean myWasShown; private String myProcessId = ""; @Nullable private volatile Runnable myBackgroundHandler; + private int myDelayInMillis = DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS; public ProgressWindow(boolean shouldShowCancel, Project project) { this(shouldShowCancel, false, project); @@ -84,7 +92,11 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa this(shouldShowCancel, shouldShowBackground, project, null, cancelText); } - public ProgressWindow(boolean shouldShowCancel, boolean shouldShowBackground, @Nullable Project project, JComponent parentComponent, String cancelText) { + public ProgressWindow(boolean shouldShowCancel, + boolean shouldShowBackground, + @Nullable Project project, + JComponent parentComponent, + String cancelText) { myProject = project; myShouldShowCancel = shouldShowCancel; myCancelText = cancelText; @@ -120,40 +132,59 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa myStarted = true; } + /** + * There is a possible case that many short (in terms of time) progress tasks are executed in a small amount of time. + * Problem: UI blinks and looks ugly if we show progress dialog for every such task (every dialog disappears shortly). + * Solution is to postpone showing progress dialog in assumption that the task may be already finished when it's + * time to show the dialog. + *

+ * Default value is {@link #DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS} + * + * @param delayInMillis new delay time in milliseconds + */ + public void setDelayInMillis(int delayInMillis) { + myDelayInMillis = delayInMillis; + } + private synchronized boolean isStarted() { return myStarted; } protected void prepareShowDialog() { - SwingUtilities.invokeLater(new Runnable() { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override public void run() { - myShowWindowAlarm.addRequest(new Runnable() { - public void run() { + // We know at least about one use-case the requires special treatment here: many short (in terms of time) progress tasks are + // executed in a small amount of time. Problem: UI blinks and looks ugly if we show progress dialog that disappears shortly + // for each of them. Solution is to postpone the tasks of showing progress dialog. Hence, it will not be shown at all + // if the task is already finished when the time comes. + Timer timer = new Timer(myDelayInMillis, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { if (isRunning()) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (myDialog != null) { - final DialogWrapper popup = myDialog.myPopup; - if (popup != null) { - myFocusTrackback.registerFocusComponent(new FocusTrackback.ComponentQuery() { - public Component getComponent() { - return popup.getPreferredFocusedComponent(); - } - }); - if (popup.isShowing()) { - myWasShown = true; - } + if (myDialog != null) { + final DialogWrapper popup = myDialog.myPopup; + if (popup != null) { + myFocusTrackback.registerFocusComponent(new FocusTrackback.ComponentQuery() { + @SuppressWarnings({"ConstantConditions"}) + public Component getComponent() { + return popup.getPreferredFocusedComponent(); } + }); + if (popup.isShowing()) { + myWasShown = true; } } - }); + } showDialog(); } else { Disposer.dispose(ProgressWindow.this); } } - }, 300, getModalityState()); + }); + timer.setRepeats(false); + timer.start(); } }); } @@ -204,7 +235,7 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { Runnable installer = new Runnable() { public void run() { - if (isRunning() && !isCanceled() && getFraction() < 0.15 && myDialog!=null) { + if (isRunning() && !isCanceled() && getFraction() < 0.15 && myDialog != null) { final JComponent cmp = ProgressManager.getInstance().getProvidedFunComponent(myProject, getProcessId()); if (cmp != null) { setFunComponent(cmp); @@ -237,7 +268,8 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa myDialog.hide(); if (myDialog.wasShown()) { myFocusTrackback.restoreFocus(); - } else { + } + else { myFocusTrackback.consume(); } } @@ -378,18 +410,18 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa private JProgressBar myProgressBar; private boolean myRepaintedFlag = true; - private JPanel myFunPanel; - private TitlePanel myTitlePanel; - private DialogWrapper myPopup; - private final Window myParentWindow; - private Point myLastClicked; + private JPanel myFunPanel; + private TitlePanel myTitlePanel; + private DialogWrapper myPopup; + private final Window myParentWindow; + private Point myLastClicked; public MyDialog(boolean shouldShowBackground, Project project, String cancelText) { Window parentWindow = WindowManager.getInstance().suggestParentWindow(project); if (parentWindow == null) { parentWindow = WindowManagerEx.getInstanceEx().getMostRecentFocusedWindow(); } - myParentWindow =parentWindow; + myParentWindow = parentWindow; initDialog(shouldShowBackground, cancelText); } @@ -448,7 +480,6 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa } } }); - } public void dispose() { @@ -470,7 +501,7 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa }); } - public void changeCancelButtonText(String text){ + public void changeCancelButtonText(String text) { myCancelButton.setText(text); } @@ -550,7 +581,9 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa myPopup.close(DialogWrapper.CANCEL_EXIT_CODE); } - myPopup = myParentWindow.isShowing() ? new MyDialogWrapper(myParentWindow, myShouldShowCancel) : new MyDialogWrapper(myProject, myShouldShowCancel); + myPopup = myParentWindow.isShowing() + ? new MyDialogWrapper(myParentWindow, myShouldShowCancel) + : new MyDialogWrapper(myProject, myShouldShowCancel); myPopup.setUndecorated(true); SwingUtilities.invokeLater(new Runnable() { @@ -606,7 +639,8 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa catch (GlassPaneDialogWrapperPeer.GlasspanePeerUnavailableException e) { return super.createPeer(parent, canBeParent); } - } else { + } + else { return super.createPeer(parent, canBeParent); } } @@ -620,7 +654,8 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa catch (GlassPaneDialogWrapperPeer.GlasspanePeerUnavailableException e) { return super.createPeer(canBeParent, toolkitModalIfPossible); } - } else { + } + else { return super.createPeer(canBeParent, toolkitModalIfPossible); } } @@ -634,7 +669,8 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa catch (GlassPaneDialogWrapperPeer.GlasspanePeerUnavailableException e) { return super.createPeer(project, canBeParent); } - } else { + } + else { return super.createPeer(project, canBeParent); } } @@ -642,7 +678,7 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa protected void init() { super.init(); setUndecorated(true); - myPanel.setBorder(PopupBorder.Factory.create(true)); + myPanel.setBorder(PopupBorder.Factory.create(true, true)); } protected boolean isProgressDialog() { @@ -659,7 +695,7 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa } @Nullable - protected Border createContentPaneBorder() { + protected Border createContentPaneBorder() { return null; } } @@ -670,7 +706,7 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa myDialog.setShouldShowBackground(backgroundHandler != null); } - public void setCancelButtonText(String text){ + public void setCancelButtonText(String text) { if (myDialog != null) { myDialog.changeCancelButtonText(text); } @@ -691,7 +727,8 @@ public class ProgressWindow extends BlockingProgressIndicator implements Disposa if (wnd != null) { // Can be null if just hidden wnd.pack(); } - } else if (myDialog.myPopup != null) { + } + else if (myDialog.myPopup != null) { myDialog.myPopup.validate(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java index 2adaf0e140b1..dafbeb029bb8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/ex/ProjectEx.java @@ -37,5 +37,5 @@ public interface ProjectEx extends Project { void checkUnknownMacros(final boolean showDialog); - void setProjectName(String name); + void setProjectName(@NotNull String name); } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index f26b222bd078..5ce29e80bfb2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -103,7 +103,7 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx { if (!isDefault() && projectName != null && getStateStore().getStorageScheme().equals(StorageScheme.DIRECTORY_BASED)) myOldName = ""; // new project } - public void setProjectName(final String projectName) { + public void setProjectName(@NotNull String projectName) { if (!projectName.equals(myName)) { myOldName = myName; myName = projectName; @@ -454,8 +454,9 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx { @Override public String toString() { return "Project " - + (isDisposed() ? "(Disposed) " : "") - + (isDefault() ? "(Default) " : "'" + getLocation()+"'") + + (isDisposed() ? "(Disposed) " : "'" + getLocation()+"'") + + (isDefault() ? " (Default)" : "") + + " " + myName ; } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusManagerImpl.java index c685df5286fc..8ea3b8bdbf78 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusManagerImpl.java @@ -16,12 +16,14 @@ package com.intellij.openapi.wm.impl; import com.intellij.ide.IdeEventQueue; +import com.intellij.internal.focus.FocusTracesAction; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.EdtRunnable; @@ -60,6 +62,8 @@ public class FocusManagerImpl extends IdeFocusManager implements Disposable { private FocusCommand myFocusCommandOnAppActivation; private ActionCallback myCallbackOnActivation; + private final boolean isInternalMode = ApplicationManagerEx.getApplicationEx().isInternal(); + private List myRequests = new ArrayList(); private final IdeEventQueue myQueue; private final KeyProcessorConext myKeyProcessorContext = new KeyProcessorConext(); @@ -156,6 +160,9 @@ public class FocusManagerImpl extends IdeFocusManager implements Disposable { @NotNull public ActionCallback requestFocus(@NotNull final FocusCommand command, final boolean forced) { + if (isInternalMode) { + recordCommand(command, new Throwable(), forced); + } final ActionCallback result = new ActionCallback(); if (!forced) { @@ -183,6 +190,16 @@ public class FocusManagerImpl extends IdeFocusManager implements Disposable { return result; } + public List getRequests() { + return myRequests; + } + + private void recordCommand(FocusCommand command, Throwable trace, boolean forced) { + if (FocusTracesAction.isActive()) { + myRequests.add(new FocusRequestInfo(command.getDominationComponent(), trace, forced)); + } + } + private void _requestFocus(final FocusCommand command, final boolean forced, final ActionCallback result) { if (checkForRejectOrByPass(command, forced, result)) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusRequestInfo.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusRequestInfo.java new file mode 100644 index 000000000000..a1dccc18630a --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FocusRequestInfo.java @@ -0,0 +1,56 @@ +/* + * 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.wm.impl; + +import com.intellij.util.ExceptionUtil; + +import java.awt.*; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author Konstantin Bulenkov + */ +public final class FocusRequestInfo { + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); + private final String when; + private final Throwable trace; + private final boolean forced; + private Component component; + + public FocusRequestInfo(Component c, Throwable trace, boolean forced) { + this.forced = forced; + this.trace = trace; + when = DATE_FORMAT.format(new Date()); + component = c; + } + + public String getStackTrace() { + return ExceptionUtil.getThrowableText(trace); + } + + public boolean isForced() { + return forced; + } + + public String getDate() { + return when; + } + + public Component getComponent() { + return component; + } +} diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index 92373029be56..c13aca602281 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -78,7 +78,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi private MyComponent myComp; private JLayeredPane myLayeredPane; - private Position myPosition; + private AbstractPosition myPosition; private Point myTargetPoint; private final boolean myHideOnFrameResize; @@ -226,7 +226,13 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } public void show(final RelativePoint target, final Balloon.Position position) { - Position pos = BELOW; + AbstractPosition pos = getAbstractPositionFor(position); + + show(target, pos); + } + + private static AbstractPosition getAbstractPositionFor(Position position) { + AbstractPosition pos = BELOW; switch (position) { case atLeft: pos = AT_LEFT; @@ -241,12 +247,11 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi pos = ABOVE; break; } - - show(target, pos); + return pos; } public void show(PositionTracker tracker, Balloon.Position position) { - Position pos = BELOW; + AbstractPosition pos = BELOW; switch (position) { case atLeft: pos = AT_LEFT; @@ -266,11 +271,11 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } - private void show(RelativePoint target, Position position) { + private void show(RelativePoint target, AbstractPosition position) { show(new PositionTracker.Static(target), position); } - private void show(PositionTracker tracker, Position position) { + private void show(PositionTracker tracker, AbstractPosition position) { assert !myDisposed : "Balloon is already disposed"; if (isVisible()) return; @@ -279,7 +284,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi myTracker = tracker; myTracker.init(this); - Position originalPreferred = position; + AbstractPosition originalPreferred = position; JRootPane root = null; JDialog dialog = IJSwingUtilities.findParentOfType(tracker.getComponent(), JDialog.class); @@ -324,9 +329,9 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi Rectangle2D currentSquare = lp.createIntersection(rec); double maxSquare = currentSquare.getWidth() * currentSquare.getHeight(); - Position targetPosition = myPosition; + AbstractPosition targetPosition = myPosition; - for (Position eachPosition : myPosition.getOtherPositions()) { + for (AbstractPosition eachPosition : myPosition.getOtherPositions()) { Rectangle2D eachIntersection = lp.createIntersection(getRecForPosition(eachPosition, false)); double eachSquare = eachIntersection.getWidth() * eachIntersection.getHeight(); if (maxSquare < eachSquare) { @@ -383,7 +388,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi }, this); } - private Rectangle getRecForPosition(Position position, boolean adjust) { + private Rectangle getRecForPosition(AbstractPosition position, boolean adjust) { Dimension size = getContentSizeFor(position); Rectangle rec = new Rectangle(new Point(0, 0), size); @@ -398,7 +403,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi return rec; } - private Dimension getContentSizeFor(Position position) { + private Dimension getContentSizeFor(AbstractPosition position) { Insets insets = position.createBorder(this).getBorderInsets(); if (insets == null) { insets = new Insets(0, 0, 0, 0); @@ -514,18 +519,23 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi return 3; } - int getPointerWidth(Position position) { + int getPointerWidth(AbstractPosition position) { return position.isTopBottomPointer() ? 14 : 11; } - int getNormalInset() { + public static int getNormalInset() { return 3; } - int getPointerLength(Position position) { + static int getPointerLength(AbstractPosition position) { return position.isTopBottomPointer() ? 10 : 8; } + public static int getPointerLength(Position position) { + return getPointerLength((getAbstractPositionFor(position))); + } + + public void hide() { Disposer.dispose(this); @@ -596,14 +606,14 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } } - public abstract static class Position { + public abstract static class AbstractPosition { abstract EmptyBorder createBorder(final BalloonImpl balloon); abstract void setRecToRelativePosition(Rectangle rec, Point targetPoint); - abstract int getChangeShift(Position original, int xShift, int yShift); + abstract int getChangeShift(AbstractPosition original, int xShift, int yShift); public void updateBounds(final BalloonImpl balloon) { balloon.myComp._setBounds(getUpdatedBounds(balloon.myLayeredPane.getSize(), @@ -690,8 +700,8 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi protected abstract Rectangle getPointlessContentRec(Rectangle bounds, int pointerLength); - public Set getOtherPositions() { - HashSet all = new HashSet(); + public Set getOtherPositions() { + HashSet all = new HashSet(); all.add(BELOW); all.add(ABOVE); all.add(AT_RIGHT); @@ -705,13 +715,13 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi public abstract Point getShiftedPoint(Point targetPoint, int shift); } - public static final Position BELOW = new Below(); - public static final Position ABOVE = new Above(); - public static final Position AT_RIGHT = new AtRight(); - public static final Position AT_LEFT = new AtLeft(); + public static final AbstractPosition BELOW = new Below(); + public static final AbstractPosition ABOVE = new Above(); + public static final AbstractPosition AT_RIGHT = new AtRight(); + public static final AbstractPosition AT_LEFT = new AtLeft(); - private static class Below extends Position { + private static class Below extends AbstractPosition { @Override @@ -720,7 +730,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - int getChangeShift(Position original, int xShift, int yShift) { + int getChangeShift(AbstractPosition original, int xShift, int yShift) { return original == ABOVE ? yShift : 0; } @@ -772,15 +782,15 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } - private static class Above extends Position { + private static class Above extends AbstractPosition { @Override public Point getShiftedPoint(Point targetPoint, int shift) { - return new Point(targetPoint.x, targetPoint.y - shift); + return new Point(targetPoint.x, targetPoint.y + shift); } @Override - int getChangeShift(Position original, int xShift, int yShift) { + int getChangeShift(AbstractPosition original, int xShift, int yShift) { return original == BELOW ? -yShift : 0; } @@ -834,7 +844,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } } - private static class AtRight extends Position { + private static class AtRight extends AbstractPosition { @Override public Point getShiftedPoint(Point targetPoint, int shift) { @@ -842,7 +852,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - int getChangeShift(Position original, int xShift, int yShift) { + int getChangeShift(AbstractPosition original, int xShift, int yShift) { return original == AT_LEFT ? xShift : 0; } @@ -892,7 +902,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } } - private static class AtLeft extends Position { + private static class AtLeft extends AbstractPosition { @Override public Point getShiftedPoint(Point targetPoint, int shift) { @@ -900,7 +910,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi } @Override - int getChangeShift(Position original, int xShift, int yShift) { + int getChangeShift(AbstractPosition original, int xShift, int yShift) { return original == AT_RIGHT ? -xShift : 0; } diff --git a/platform/platform-impl/src/com/intellij/ui/LightweightHint.java b/platform/platform-impl/src/com/intellij/ui/LightweightHint.java index 8743c13f8324..900089dc08a2 100644 --- a/platform/platform-impl/src/com/intellij/ui/LightweightHint.java +++ b/platform/platform-impl/src/com/intellij/ui/LightweightHint.java @@ -20,16 +20,17 @@ import com.intellij.ide.IdeTooltip; import com.intellij.ide.IdeTooltipManager; import com.intellij.ide.TooltipEvent; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.actionSystem.EditorAction; +import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.wm.ex.LayoutFocusTraversalPolicyExt; import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.popup.AbstractPopup; +import com.intellij.ui.components.panels.OpaquePanel; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.border.LineBorder; import javax.swing.event.EventListenerList; import java.awt.*; import java.awt.event.ActionEvent; @@ -179,13 +180,26 @@ public class LightweightHint extends UserDataHolderBase implements Hint { } else { myIsRealPopup = true; - myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myComponent, myFocusRequestor) + Point actualPoint = new Point(x, y); + JComponent actualComponent = new OpaquePanel(new BorderLayout()); + actualComponent.add(myComponent, BorderLayout.CENTER); + if (myHintHint.isAwtTooltip()) { + fixActualPoint(actualPoint); + + + int inset = BalloonImpl.getNormalInset(); + actualComponent.setBorder(new LineBorder(hintHint.getTextBackground(), inset)); + actualComponent.setBackground(hintHint.getTextBackground()); + actualComponent.validate(); + } + + myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(actualComponent, myFocusRequestor) .setRequestFocus(myFocusRequestor != null) .setResizable(myResizable) .setMovable(myTitle != null) .setTitle(myTitle) .setModalContext(false) - .setShowShadow(!myForceLightweightPopup && myForceShowAsPopup) + .setShowShadow(isRealPopup()) .setCancelKeyEnabled(false) .setCancelOnClickOutside(myCancelOnClickOutside) .setCancelOnOtherWindowOpen(myCancelOnOtherWindowOpen) @@ -193,7 +207,30 @@ public class LightweightHint extends UserDataHolderBase implements Hint { .createPopup(); beforeShow(); - myPopup.show(new RelativePoint(myParentComponent, new Point(x, y))); + myPopup.show(new RelativePoint(myParentComponent, new Point(actualPoint.x, actualPoint.y))); + } + } + + private void fixActualPoint(Point actualPoint) { + if (!myHintHint.isAwtTooltip()) return; + if (!myIsRealPopup) return; + + Dimension size = myComponent.getPreferredSize(); + Balloon.Position position = myHintHint.getPreferredPosition(); + int shift = BalloonImpl.getPointerLength(position); + switch (position) { + case below: + actualPoint.y += shift; + break; + case above: + actualPoint.y -= (shift + size.height); + break; + case atLeft: + actualPoint.x -= (shift + size.width); + break; + case atRight: + actualPoint.y += shift; + break; } } @@ -205,7 +242,17 @@ public class LightweightHint extends UserDataHolderBase implements Hint { if (hintHint.isAwtTooltip()) { Dimension size = component.getPreferredSize(); Dimension paneSize = pane.getSize(); - return size.width < paneSize.width && size.height < paneSize.height; + + Point target = desiredLocation.getPointOn(pane).getPoint(); + Balloon.Position pos = hintHint.getPreferredPosition(); + int pointer = BalloonImpl.getPointerLength(pos) + BalloonImpl.getNormalInset(); + if (pos == Balloon.Position.above || pos == Balloon.Position.below) { + boolean hieghtFit = target.y - size.height - pointer > 0 || target.y + size.height + pointer < paneSize.height; + return hieghtFit && size.width + pointer < paneSize.width; + } else { + boolean widthFit = target.x - size.width - pointer > 0 || target.x + size.width + pointer < paneSize.width; + return widthFit && size.height + pointer < paneSize.height; + } } else { final Rectangle lpRect = new Rectangle(pane.getLocationOnScreen().x, pane.getLocationOnScreen().y, pane.getWidth(), pane.getHeight()); Rectangle componentRect = new Rectangle(desiredLocation.getScreenPoint().x, @@ -241,7 +288,7 @@ public class LightweightHint extends UserDataHolderBase implements Hint { } public final boolean isRealPopup() { - return myIsRealPopup; + return myIsRealPopup | myForceShowAsPopup; } public void hide() { @@ -298,7 +345,9 @@ public class LightweightHint extends UserDataHolderBase implements Hint { private void updateBounds(int x, int y, boolean updateLocation) { setSize(myComponent.getPreferredSize()); if (updateLocation) { - setLocation(new RelativePoint(myParentComponent, new Point(x, y))); + Point point = new Point(x, y); + fixActualPoint(point); + setLocation(new RelativePoint(myParentComponent, point)); } } diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index 87d293e51546..ad17e1a026f7 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -16,7 +16,6 @@ package com.intellij.ui.popup; import com.intellij.codeInsight.hint.HintUtil; -import com.intellij.ide.ui.UISettings; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.JBAwtEventQueue; @@ -27,7 +26,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.impl.ShadowBorderPainter; import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; @@ -50,17 +48,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.*; -import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import static com.intellij.openapi.ui.impl.ShadowBorderPainter.*; - public class AbstractPopup implements JBPopup { private static final Logger LOG = Logger.getInstance("#com.intellij.ui.popup.AbstractPopup"); @@ -196,7 +190,7 @@ public class AbstractPopup implements JBPopup { myProject = project; myComponent = component; - myPopupBorder = PopupBorder.Factory.create(true); + myPopupBorder = PopupBorder.Factory.create(true, showShadow); myShadowed = showShadow; myPaintShadow = showShadow && !SystemInfo.isMac && !movable && !resizable && Registry.is("ide.popup.dropShadow"); myContent = createContentPanel(resizable, myPopupBorder, isToDrawMacCorner() && resizable); @@ -301,7 +295,7 @@ public class AbstractPopup implements JBPopup { @NotNull protected MyContentPanel createContentPanel(final boolean resizable, PopupBorder border, boolean isToDrawMacCorner) { - return new MyContentPanel(resizable, border, isToDrawMacCorner, myPaintShadow); + return new MyContentPanel(resizable, border, isToDrawMacCorner); } public static boolean isToDrawMacCorner() { @@ -1030,40 +1024,15 @@ public class AbstractPopup implements JBPopup { public static class MyContentPanel extends JPanel { private final boolean myResizable; private final boolean myDrawMacCorner; - private final boolean myPaintShadow; public MyContentPanel(final boolean resizable, final PopupBorder border, boolean drawMacCorner) { - this(resizable, border, drawMacCorner, false); - } - - public MyContentPanel(final boolean resizable, final PopupBorder border, boolean drawMacCorner, boolean shadowed) { super(new BorderLayout()); myResizable = resizable; myDrawMacCorner = drawMacCorner; - myPaintShadow = shadowed && !UISettings.isRemoteDesktopConnected(); - if (myPaintShadow) { - setOpaque(false); - setBorder(new EmptyBorder(POPUP_TOP_SIZE, POPUP_SIDE_SIZE, POPUP_BOTTOM_SIZE, POPUP_SIDE_SIZE) { - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - border.paintBorder(c, g, - x + POPUP_SIDE_SIZE - 1, - y + POPUP_TOP_SIZE - 1, - width - 2 * POPUP_SIDE_SIZE + 2, - height - POPUP_TOP_SIZE - POPUP_BOTTOM_SIZE + 2); - } - }); - } - else { - setBorder(border); - } + setBorder(border); } public void paint(Graphics g) { - if (myPaintShadow) { - paintShadow(g); - } - super.paint(g); if (myResizable && myDrawMacCorner) { @@ -1073,21 +1042,6 @@ public class AbstractPopup implements JBPopup { this); } } - - private void paintShadow(final Graphics g) { - BufferedImage capture = null; - try { - final Point onScreen = getLocationOnScreen(); - capture = new Robot().createScreenCapture( - new Rectangle(onScreen.x, onScreen.y, getWidth() + 2 * POPUP_SIDE_SIZE, getHeight() + POPUP_TOP_SIZE + POPUP_BOTTOM_SIZE)); - final BufferedImage shadow = ShadowBorderPainter.createPopupShadow(this, getWidth(), getHeight()); - ((Graphics2D)capture.getGraphics()).drawImage(shadow, null, null); - } - catch (Exception e) { - LOG.info(e); - } - if (capture != null) g.drawImage(capture, 0, 0, null); - } } public boolean isCancelOnClickOutside() { diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index d5bb8acb132e..544a4802fd9c 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -12,10 +12,15 @@ reformat.option.selected.text=&Selected text reformat.option.all.files.in.directory=&All files in directory {0} reformat.option.include.subdirectories=&Include subdirectories reformat.option.optimize.imports=&Optimize imports +reformat.progress.file.with.known.name.text=Reformatting {0} +reformat.progress.common.text=Reformatting code... process.optimize.imports=Optimize Imports progress.text.optimizing.imports=Optimizing imports... +progress.reformat.code.prepare=Preparing to reformat +progress.reformat.stage.wrapping.blocks=Preparing... +progress.reformat.stage.processing.blocks=Calculating changes... +progress.reformat.stage.applying.changes=Storing changes... process.reformat.code=Reformat Code -progress.text.reformatting.code=Reformatting code... dialog.reformat.files.title=Reformat Files dialog.reformat.files.optimize.imports.checkbox=&Optimize imports dialog.reformat.files.reformat.selected.files.label=Reformat selected files? diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 7e58a12cb257..e7786120e6e3 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -116,4 +116,6 @@ vcs.show.history.numbers=true navbar.updateMergeTime=250 navbar.userActivityMergeTime=500 -inspectionGadgets.telemetry.enabled=false \ No newline at end of file +inspectionGadgets.telemetry.enabled=false + +hint.autopopup=false \ No newline at end of file diff --git a/platform/platform-resources/src/componentSets/PlatformComponents.xml b/platform/platform-resources/src/componentSets/PlatformComponents.xml index 8913d4536489..51b1d2960dc1 100644 --- a/platform/platform-resources/src/componentSets/PlatformComponents.xml +++ b/platform/platform-resources/src/componentSets/PlatformComponents.xml @@ -8,6 +8,9 @@ com.intellij.openapi.components.impl.ServiceManagerImpl + + com.intellij.openapi.util.registry.RegistryState + com.intellij.openapi.project.impl.ProjectStoreClassProvider com.intellij.openapi.components.impl.stores.PlatformProjectStoreClassProvider diff --git a/platform/platform-resources/src/componentSets/PlatformLangComponents.xml b/platform/platform-resources/src/componentSets/PlatformLangComponents.xml index 8b66914a36fd..31eee9d568f8 100644 --- a/platform/platform-resources/src/componentSets/PlatformLangComponents.xml +++ b/platform/platform-resources/src/componentSets/PlatformLangComponents.xml @@ -8,6 +8,9 @@ com.intellij.openapi.components.impl.ServiceManagerImpl + + com.intellij.openapi.util.registry.RegistryState + com.intellij.openapi.project.impl.ProjectStoreClassProvider com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 0edd287cb336..f448f143b688 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -441,6 +441,10 @@ + + + + diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java index e5ce8f978436..7726ada0f3e8 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTestRunnerResultsForm.java @@ -465,6 +465,9 @@ public class SMTestRunnerResultsForm extends TestResultsPanel implements TestFra SMRunnerUtil.runInEventDispatchThread(new Runnable() { public void run() { + if (myTreeBuilder.isDisposed()) { + return; + } myTreeBuilder.select(testProxy, null); } }, ModalityState.NON_MODAL); diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java index dc9b834fcea3..58a0170ccdec 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java @@ -25,7 +25,7 @@ import com.intellij.testFramework.LightProjectDescriptor; public class FileUrlLocationTest extends SMLightFixtureTestCase { @Override protected LightProjectDescriptor getProjectDescriptor() { - return ourDescriptor; + return LightProjectDescriptor.EMPTY_PROJECT_DESCRIPTOR; } public void testSpecNavigation() throws Throwable { diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/SMLightFixtureTestCase.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/SMLightFixtureTestCase.java index 0019a618db55..03bc6b5c967b 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/SMLightFixtureTestCase.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/SMLightFixtureTestCase.java @@ -15,12 +15,7 @@ */ package com.intellij.execution.testframework.sm; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ContentEntry; -import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.psi.PsiFile; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.PlatformTestCase; @@ -43,22 +38,6 @@ public abstract class SMLightFixtureTestCase extends UsefulTestCase { PlatformTestCase.initPlatformLangPrefix(); } - protected static final LightProjectDescriptor ourDescriptor = new LightProjectDescriptor() { - @Override - public ModuleType getModuleType() { - return ModuleType.EMPTY; - } - - @Override - public Sdk getSdk() { - return null; - } - - @Override - public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { - //Do nothing - } - }; protected CodeInsightTestFixture myFixture; @Override diff --git a/platform/testFramework/src/com/intellij/mock/MockProject.java b/platform/testFramework/src/com/intellij/mock/MockProject.java index 51edbd17e8f0..afe7d9274caf 100644 --- a/platform/testFramework/src/com/intellij/mock/MockProject.java +++ b/platform/testFramework/src/com/intellij/mock/MockProject.java @@ -38,7 +38,7 @@ public class MockProject extends MockComponentManager implements ProjectEx { } @Override - public void setProjectName(String name) { + public void setProjectName(@NotNull String name) { } @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index cd1da081ce42..22becea304f7 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -55,6 +55,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.project.ex.ProjectManagerEx; +import com.intellij.openapi.project.impl.ProjectImpl; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.*; import com.intellij.openapi.startup.StartupManager; @@ -87,6 +88,7 @@ import com.intellij.util.containers.CollectionFactory; import com.intellij.util.indexing.FileBasedIndex; import com.intellij.util.indexing.IndexableFileSet; import com.intellij.util.messages.MessageBusConnection; +import com.intellij.util.ui.UIUtil; import gnu.trove.THashMap; import junit.framework.TestCase; import org.jetbrains.annotations.NonNls; @@ -98,7 +100,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.PrintStream; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -340,6 +341,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da if (ourProject == null || !ourProjectDescriptor.equals(descriptor)) { initProject(descriptor); } + ((ProjectImpl)ourProject).setTemporarilyDisposed(false); ProjectManagerEx.getInstanceEx().setCurrentTestProject(ourProject); @@ -490,17 +492,12 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).clearUncommitedDocuments(); ((HintManagerImpl)HintManager.getInstance()).cleanup(); - Runnable runnable = new Runnable() { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { ((UndoManagerImpl)UndoManager.getGlobalInstance()).dropHistoryInTests(); } - }; - if (ApplicationManager.getApplication().isDispatchThread()) { - runnable.run(); - } else { - SwingUtilities.invokeAndWait(runnable); - } + }); TemplateDataLanguageMappings.getInstance(project).cleanupForNextTest(); @@ -514,6 +511,9 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da if (checkForEditors) { checkEditorsReleased(); } + if (isLight(project)) { + ((ProjectImpl)project).setTemporarilyDisposed(true); // mark temporarily as disposed so that rogue component trying to access it will fail + } } public static void checkEditorsReleased() { @@ -654,6 +654,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da public static synchronized void closeAndDeleteProject() { if (ourProject != null) { + ((ProjectImpl)ourProject).setTemporarilyDisposed(false); final VirtualFile projFile = ((ProjectEx)ourProject).getStateStore().getProjectFile(); final File projectFile = projFile == null ? null : VfsUtil.virtualToIoFile(projFile); if (!ourProject.isDisposed()) Disposer.dispose(ourProject); @@ -674,20 +675,12 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { @Override public void run() { - try { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - closeAndDeleteProject(); - } - }); - } - catch (InterruptedException e) { - e.printStackTrace(); - } - catch (InvocationTargetException e) { - e.printStackTrace(); - } + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + closeAndDeleteProject(); + } + }); } }); } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java b/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java index 737cf97e5ef9..d0a714175025 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightProjectDescriptor.java @@ -15,6 +15,7 @@ */ package com.intellij.testFramework; +import com.intellij.openapi.module.EmptyModuleType; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.projectRoots.Sdk; @@ -28,4 +29,20 @@ public interface LightProjectDescriptor { ModuleType getModuleType(); Sdk getSdk(); void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry); + + LightProjectDescriptor EMPTY_PROJECT_DESCRIPTOR = new LightProjectDescriptor() { + @Override + public ModuleType getModuleType() { + return EmptyModuleType.getInstance(); + } + + @Override + public Sdk getSdk() { + return null; + } + + @Override + public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { + } + }; } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 09431aaf29fe..53c481f95d52 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -288,7 +288,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } public static void cleanupApplicationCaches(Project project) { - if (project != null) { + if (project != null && !project.isDisposed()) { ((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests(); ((PsiManagerEx)PsiManager.getInstance(project)).getFileManager().cleanupForNextTest(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/TempDirTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/TempDirTestFixture.java index dd2ffcc03a7a..faa86b4415ee 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/TempDirTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/TempDirTestFixture.java @@ -28,7 +28,7 @@ import java.io.IOException; */ public interface TempDirTestFixture extends IdeaTestFixture { - VirtualFile copyFile(VirtualFile file, String targetPath); + VirtualFile copyFile(@NotNull VirtualFile file, String targetPath); VirtualFile copyAll(String dataDir, String targetDir); diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java index 921c00a8a5d4..128066fd5d95 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java @@ -16,12 +16,6 @@ package com.intellij.testFramework.fixtures.impl; -import com.intellij.openapi.module.EmptyModuleType; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleType; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.ContentEntry; -import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.builders.EmptyModuleFixtureBuilder; import com.intellij.testFramework.builders.ModuleFixtureBuilder; @@ -69,13 +63,14 @@ public class IdeaTestFixtureFactoryImpl extends IdeaTestFixtureFactory { @Override public TestFixtureBuilder createLightFixtureBuilder() { - return new LightTestFixtureBuilderImpl(new LightIdeaTestFixtureImpl(ourEmptyProjectDescriptor)); + return new LightTestFixtureBuilderImpl(new LightIdeaTestFixtureImpl( + LightProjectDescriptor.EMPTY_PROJECT_DESCRIPTOR)); } @Override public TestFixtureBuilder createLightFixtureBuilder(@Nullable LightProjectDescriptor projectDescriptor) { if (projectDescriptor == null) { - projectDescriptor = ourEmptyProjectDescriptor; + projectDescriptor = LightProjectDescriptor.EMPTY_PROJECT_DESCRIPTOR; } return new LightTestFixtureBuilderImpl(new LightIdeaTestFixtureImpl(projectDescriptor)); } @@ -105,20 +100,4 @@ public class IdeaTestFixtureFactoryImpl extends IdeaTestFixtureFactory { return new ModuleFixtureImpl(this); } } - - private static final LightProjectDescriptor ourEmptyProjectDescriptor = new LightProjectDescriptor() { - @Override - public ModuleType getModuleType() { - return EmptyModuleType.getInstance(); - } - - @Override - public Sdk getSdk() { - return null; - } - - @Override - public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { - } - }; } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTempDirTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTempDirTestFixtureImpl.java index ad0934eb4242..9a9aefddc574 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTempDirTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTempDirTestFixtureImpl.java @@ -54,7 +54,7 @@ public class LightTempDirTestFixtureImpl extends BaseFixture implements TempDirT } @Override - public VirtualFile copyFile(final VirtualFile file, final String targetPath) { + public VirtualFile copyFile(@NotNull final VirtualFile file, final String targetPath) { final String path = PathUtil.getParentPath(targetPath); return ApplicationManager.getApplication().runWriteAction(new Computable() { @Override diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/TempDirTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/TempDirTestFixtureImpl.java index 0ed70e8aca83..c0d4a4176917 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/TempDirTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/TempDirTestFixtureImpl.java @@ -40,7 +40,7 @@ public class TempDirTestFixtureImpl extends BaseFixture implements TempDirTestFi private File myTempDir; @Override - public VirtualFile copyFile(VirtualFile file, String targetPath) { + public VirtualFile copyFile(@NotNull VirtualFile file, String targetPath) { try { createTempDirectory(); VirtualFile tempDir = diff --git a/platform/usageView/src/com/intellij/usages/impl/GroupNode.java b/platform/usageView/src/com/intellij/usages/impl/GroupNode.java index cd256daa4a35..583fce9f8caa 100644 --- a/platform/usageView/src/com/intellij/usages/impl/GroupNode.java +++ b/platform/usageView/src/com/intellij/usages/impl/GroupNode.java @@ -26,6 +26,7 @@ import com.intellij.usages.rules.MergeableUsage; import com.intellij.util.ui.UIUtil; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeNode; @@ -43,7 +44,7 @@ public class GroupNode extends Node implements Navigatable, Comparable myUsageNodes = new ArrayList(); private volatile int myRecursiveUsageCount = 0; - public GroupNode(UsageGroup group, int ruleIndex, UsageViewTreeModelBuilder treeModel) { + public GroupNode(@Nullable UsageGroup group, int ruleIndex, @NotNull UsageViewTreeModelBuilder treeModel) { super(treeModel); setUserObject(group); myGroup = group; @@ -73,7 +74,7 @@ public class GroupNode extends Node implements Navigatable, Comparable groupNodes = mySubgroupNodes.values(); for(Iterator iterator = groupNodes.iterator();iterator.hasNext();) { @@ -129,7 +131,11 @@ public class GroupNode extends Node implements Navigatable, Comparable= 0 ? index : -index-1; } - private int indexedBinarySearch(UsageNode key) { + private int indexedBinarySearch(@NotNull UsageNode key) { int low = 0; int high = getChildCount() - 1; @@ -246,7 +254,7 @@ public class GroupNode extends Node implements Navigatable, Comparable infos = getSelectedUsageInfos(); - if (infos != null && myUsagePreviewPanel != null) { - myUsagePreviewPanel.updateLayout(infos); - } + close(); } - }); + }, UsageViewBundle.message("usage.view.cancel.button")); } - }); + + myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(final TreeSelectionEvent e) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + if (isDisposed) return; + List infos = getSelectedUsageInfos(); + if (infos != null && myUsagePreviewPanel != null) { + myUsagePreviewPanel.updateLayout(infos); + } + } + }); + } + }); + } } }); } @@ -659,7 +663,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra } private final TransferToEDTQueue myTransferToEDTQueue; - public void appendUsageLater(Usage usage) { + public void appendUsageLater(@NotNull Usage usage) { myTransferToEDTQueue.offer(usage); } @@ -783,17 +787,19 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra } public void dispose() { - isDisposed = true; - ToolTipManager.sharedInstance().unregisterComponent(myTree); - myModelTracker.removeListener(this); - myUpdateAlarm.cancelAllRequests(); - if (myUsagePreviewPanel != null) { - UsageViewSettings.getInstance().PREVIEW_USAGES_SPLITTER_PROPORTIONS = ((Splitter)myUsagePreviewPanel.getParent()).getProportion(); - myUsagePreviewPanel = null; - } - for (Usage usage : getUsages()) { - if (usage instanceof UsageInfo2UsageAdapter) { - ((UsageInfo2UsageAdapter)usage).dispose(); + synchronized (lock) { + isDisposed = true; + ToolTipManager.sharedInstance().unregisterComponent(myTree); + myModelTracker.removeListener(this); + myUpdateAlarm.cancelAllRequests(); + if (myUsagePreviewPanel != null) { + UsageViewSettings.getInstance().PREVIEW_USAGES_SPLITTER_PROPORTIONS = ((Splitter)myUsagePreviewPanel.getParent()).getProportion(); + myUsagePreviewPanel = null; + } + for (Usage usage : getUsages()) { + if (usage instanceof UsageInfo2UsageAdapter) { + ((UsageInfo2UsageAdapter)usage).dispose(); + } } } } diff --git a/platform/usageView/testSrc/com/intellij/usages/impl/UsageNodeTreeBuilderTest.java b/platform/usageView/testSrc/com/intellij/usages/impl/UsageNodeTreeBuilderTest.java index 0d01f31bbcb5..11fb2df0b0b2 100644 --- a/platform/usageView/testSrc/com/intellij/usages/impl/UsageNodeTreeBuilderTest.java +++ b/platform/usageView/testSrc/com/intellij/usages/impl/UsageNodeTreeBuilderTest.java @@ -18,11 +18,11 @@ package com.intellij.usages.impl; import com.intellij.openapi.fileEditor.FileEditorLocation; import com.intellij.openapi.vcs.FileStatus; +import com.intellij.testFramework.LightPlatformTestCase; import com.intellij.usages.*; import com.intellij.usages.rules.UsageFilteringRule; import com.intellij.usages.rules.UsageGroupingRule; import com.intellij.util.ui.UIUtil; -import junit.framework.TestCase; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -30,12 +30,7 @@ import javax.swing.*; /** * @author max */ -public class UsageNodeTreeBuilderTest extends TestCase { - @Override - protected void setUp() throws Exception { - super.setUp(); - } - +public class UsageNodeTreeBuilderTest extends LightPlatformTestCase { public void testNoGroupingRules() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{2, 3, 0}, new UsageGroupingRule[] {}); @@ -90,14 +85,13 @@ public class UsageNodeTreeBuilderTest extends TestCase { usages[i] = createUsage(indices[i]); } - //DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode("temp")); UsageViewTreeModelBuilder model = new UsageViewTreeModelBuilder(new UsageViewPresentation(), new UsageTarget[0]); GroupNode rootNode = new GroupNode(null, 0, model); model.setRoot(rootNode); UsageNodeTreeBuilder usageNodeTreeBuilder = new UsageNodeTreeBuilder(rules, UsageFilteringRule.EMPTY_ARRAY, rootNode); for (Usage usage : usages) { usageNodeTreeBuilder.appendUsage(usage); - UIUtil.pump(); + UIUtil.dispatchAllInvocationEvents(); } return rootNode; diff --git a/platform/util/src/com/intellij/openapi/util/Disposer.java b/platform/util/src/com/intellij/openapi/util/Disposer.java index 5bf7c49b4097..741916c7f9b8 100644 --- a/platform/util/src/com/intellij/openapi/util/Disposer.java +++ b/platform/util/src/com/intellij/openapi/util/Disposer.java @@ -30,7 +30,16 @@ import java.util.Map; @SuppressWarnings({"SSBasedInspection"}) public class Disposer { - private static final ObjectTree ourTree = new ObjectTree(); + private static final ObjectTree ourTree; + + static { + try { + ourTree = new ObjectTree(); + } + catch (NoClassDefFoundError e) { + throw new RuntimeException("loader=" + Disposer.class.getClassLoader(), e); + } + } private static final ObjectTreeAction ourDisposeAction = new ObjectTreeAction() { public void execute(final Disposable each) { diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 50525a8295f3..078c4ec16588 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -975,6 +975,27 @@ public class StringUtil { }; } + @NotNull + public static Iterable tokenize(@NotNull String s, final StringTokenizer tokenizer) { + return new Iterable() { + public Iterator iterator() { + return new Iterator() { + public boolean hasNext() { + return tokenizer.hasMoreTokens(); + } + + public String next() { + return tokenizer.nextToken(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + @NotNull public static List getWordsIn(@NotNull String text) { List result = new SmartList(); diff --git a/platform/util/src/com/intellij/ui/PopupBorder.java b/platform/util/src/com/intellij/ui/PopupBorder.java index 1eff0a877522..675a7edb52a2 100644 --- a/platform/util/src/com/intellij/ui/PopupBorder.java +++ b/platform/util/src/com/intellij/ui/PopupBorder.java @@ -29,9 +29,9 @@ public interface PopupBorder extends Border { private Factory() { } - public static PopupBorder create(boolean active) { + public static PopupBorder create(boolean active, boolean windowWithShadow) { final BaseBorder border = - SystemInfo.isMac ? new BaseBorder() : new BaseBorder(true, CaptionPanel.getBorderColor(true), CaptionPanel.getBorderColor(false)); + SystemInfo.isMac && windowWithShadow ? new BaseBorder() : new BaseBorder(true, CaptionPanel.getBorderColor(true), CaptionPanel.getBorderColor(false)); border.setActive(active); return border; } diff --git a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java index 8c51af670634..4f374caaa6c0 100644 --- a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java +++ b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java @@ -70,7 +70,7 @@ public class TransferToEDTQueue { myShutUpCondition = shutUpCondition; } - public void offer(final T thing) { + public void offer(@NotNull T thing) { myQueue.offer(thing); scheduleUpdate(); } diff --git a/platform/util/testSrc/com/intellij/util/messages/MessageBusTest.java b/platform/util/testSrc/com/intellij/util/messages/MessageBusTest.java index 0e7dd44b4b2b..a016060a1605 100644 --- a/platform/util/testSrc/com/intellij/util/messages/MessageBusTest.java +++ b/platform/util/testSrc/com/intellij/util/messages/MessageBusTest.java @@ -39,8 +39,8 @@ public class MessageBusTest extends TestCase { void t22(); } - private final static Topic T1 = new Topic("T1", T1Listener.class); - private final static Topic T2 = new Topic("T1", T2Listener.class); + private static final Topic TOPIC1 = new Topic("T1", T1Listener.class); + private static final Topic TOPIC2 = new Topic("T2", T2Listener.class); private class T1Handler implements T1Listener { private final String id; @@ -86,58 +86,57 @@ public class MessageBusTest extends TestCase { } public void testNoListenersSubscribed() { - myBus.syncPublisher(T1).t11(); + myBus.syncPublisher(TOPIC1).t11(); assertEvents(); } public void testSingleMessage() { final MessageBusConnection connection = myBus.connect(); - connection.subscribe(T1, new T1Handler("c")); - myBus.syncPublisher(T1).t11(); + connection.subscribe(TOPIC1, new T1Handler("c")); + myBus.syncPublisher(TOPIC1).t11(); assertEvents("c:t11"); } public void testSingleMessageToTwoConnections() { final MessageBusConnection c1 = myBus.connect(); - c1.subscribe(T1, new T1Handler("c1")); + c1.subscribe(TOPIC1, new T1Handler("c1")); final MessageBusConnection c2 = myBus.connect(); - c2.subscribe(T1, new T1Handler("c2")); + c2.subscribe(TOPIC1, new T1Handler("c2")); - myBus.syncPublisher(T1).t11(); + myBus.syncPublisher(TOPIC1).t11(); assertEvents("c1:t11", "c2:t11"); } public void testTwoMessagesWithSingleSubscription() { final MessageBusConnection connection = myBus.connect(); - connection.subscribe(T1, new T1Handler("c")); - myBus.syncPublisher(T1).t11(); - myBus.syncPublisher(T1).t12(); + connection.subscribe(TOPIC1, new T1Handler("c")); + myBus.syncPublisher(TOPIC1).t11(); + myBus.syncPublisher(TOPIC1).t12(); assertEvents("c:t11", "c:t12"); } public void testTwoMessagesWithDoubleSubscription() { final MessageBusConnection c1 = myBus.connect(); - c1.subscribe(T1, new T1Handler("c1")); + c1.subscribe(TOPIC1, new T1Handler("c1")); final MessageBusConnection c2 = myBus.connect(); - c2.subscribe(T1, new T1Handler("c2")); + c2.subscribe(TOPIC1, new T1Handler("c2")); - myBus.syncPublisher(T1).t11(); - myBus.syncPublisher(T1).t12(); + myBus.syncPublisher(TOPIC1).t11(); + myBus.syncPublisher(TOPIC1).t12(); assertEvents("c1:t11", "c2:t11", "c1:t12", "c2:t12"); } public void testEventFiresAnotherEvent() { - final MessageBusConnection c1 = myBus.connect(); - c1.subscribe(T1, new T1Listener() { + myBus.connect().subscribe(TOPIC1, new T1Listener() { @Override public void t11() { - myLog.add("c1:t11"); - myBus.syncPublisher(T2).t21(); - myLog.add("c1:t11:done"); + myLog.add("inside:t11"); + myBus.syncPublisher(TOPIC2).t21(); + myLog.add("inside:t11:done"); } @Override @@ -146,50 +145,62 @@ public class MessageBusTest extends TestCase { } }); - final MessageBusConnection c2 = myBus.connect(); - c2.subscribe(T1, new T1Handler("c2")); - c2.subscribe(T2, new T2Handler("c2")); + final MessageBusConnection conn = myBus.connect(); + conn.subscribe(TOPIC1, new T1Handler("handler1")); + conn.subscribe(TOPIC2, new T2Handler("handler2")); - myBus.syncPublisher(T1).t12(); - myBus.syncPublisher(T1).t11(); + myBus.syncPublisher(TOPIC1).t12(); + assertEvents("c1:t12", "handler1:t12"); - assertEvents("c1:t12", "c2:t12", "c1:t11", "c2:t11", "c2:t21", "c1:t11:done"); + myBus.syncPublisher(TOPIC1).t11(); + assertEvents("c1:t12\n" + + "handler1:t12\n" + + "inside:t11\n" + + "handler1:t11\n" + + "handler2:t21\n" + + "inside:t11:done"); } public void testConnectionTerminatedInDispatch() { - final MessageBusConnection c1 = myBus.connect(); - c1.subscribe(T1, new T1Listener() { + final MessageBusConnection conn1 = myBus.connect(); + conn1.subscribe(TOPIC1, new T1Listener() { @Override public void t11() { - c1.disconnect(); - myLog.add("c1:t11"); - myBus.syncPublisher(T2).t21(); - myLog.add("c1:t11:done"); + conn1.disconnect(); + myLog.add("inside:t11"); + myBus.syncPublisher(TOPIC2).t21(); + myLog.add("inside:t11:done"); } @Override public void t12() { - myLog.add("c1:t12"); + myLog.add("inside:t12"); } }); - c1.subscribe(T2, new T2Handler("c1")); + conn1.subscribe(TOPIC2, new T2Handler("C1T2Handler")); - final MessageBusConnection c2 = myBus.connect(); - c2.subscribe(T1, new T1Handler("c2")); - c2.subscribe(T2, new T2Handler("c2")); + final MessageBusConnection conn2 = myBus.connect(); + conn2.subscribe(TOPIC1, new T1Handler("C2T1Handler")); + conn2.subscribe(TOPIC2, new T2Handler("C2T2Handler")); - myBus.syncPublisher(T1).t11(); - myBus.syncPublisher(T1).t12(); + myBus.syncPublisher(TOPIC1).t11(); + assertEvents("inside:t11", + "C2T1Handler:t11", + "C2T2Handler:t21", + "inside:t11:done"); + myBus.syncPublisher(TOPIC1).t12(); - assertEvents("c1:t11", "c2:t11", "c2:t21", "c1:t11:done", "c2:t12"); + assertEvents("inside:t11", + "C2T1Handler:t11", + "C2T2Handler:t21", + "inside:t11:done", + "C2T1Handler:t12"); } private void assertEvents(String... expected) { String joinExpected = StringUtil.join(expected, "\n"); - String joinActual = StringUtil.join(myLog.toArray(new String[0]), "\n"); + String joinActual = StringUtil.join(myLog, "\n"); assertEquals("events mismatch", joinExpected, joinActual); } - - } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java index 09ae9dde27a2..29de04c41f31 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java @@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.vcsUtil.VcsUtil; @@ -37,6 +38,8 @@ import java.util.*; * @author yole */ public abstract class VcsVFSListener implements Disposable { + private VcsDirtyScopeManager myDirtyScopeManager; + protected static class MovedFileInfo { public final String myOldPath; public String myNewPath; @@ -59,6 +62,7 @@ public abstract class VcsVFSListener implements Disposable { protected final List myDeletedFiles = new ArrayList(); protected final List myDeletedWithoutConfirmFiles = new ArrayList(); protected final List myMovedFiles = new ArrayList(); + protected final List myDirtyFiles = new ArrayList(); protected enum VcsDeleteType {SILENT, CONFIRM, IGNORE} @@ -66,6 +70,7 @@ public abstract class VcsVFSListener implements Disposable { myProject = project; myVcs = vcs; myChangeListManager = ChangeListManager.getInstance(project); + myDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject); final MyVirtualFileAdapter myVFSListener = new MyVirtualFileAdapter(); final MyCommandAdapter myCommandListener = new MyCommandAdapter(); @@ -200,7 +205,14 @@ public abstract class VcsVFSListener implements Disposable { protected void processMovedFile(VirtualFile file, String newParentPath, String newName) { - if (FileStatusManager.getInstance(myProject).getStatus(file) != FileStatus.UNKNOWN) { + final FileStatus status = FileStatusManager.getInstance(myProject).getStatus(file); + if (status == FileStatus.IGNORED) { + if (file.getParent() != null) { + myDirtyFiles.add(file.getParent()); + myDirtyFiles.add(file); // will be at new path + } + } + if (status != FileStatus.UNKNOWN && status != FileStatus.IGNORED) { final String newPath = newParentPath + "/" + newName; boolean foundExistingInfo = false; for (MovedFileInfo info : myMovedFiles) { @@ -359,7 +371,8 @@ public abstract class VcsVFSListener implements Disposable { if (myProject != event.getProject()) return; myCommandLevel--; if (myCommandLevel == 0) { - if (!myAddedFiles.isEmpty() || !myDeletedFiles.isEmpty() || !myDeletedWithoutConfirmFiles.isEmpty() || !myMovedFiles.isEmpty()) { + if (!myAddedFiles.isEmpty() || !myDeletedFiles.isEmpty() || !myDeletedWithoutConfirmFiles.isEmpty() || !myMovedFiles.isEmpty() || + ! myDirtyFiles.isEmpty()) { // avoid reentering commandFinished handler - saving the documents may cause a "before file deletion" event firing, // which will cause closing the text editor, which will itself run a command that will be caught by this listener myCommandLevel++; @@ -379,6 +392,20 @@ public abstract class VcsVFSListener implements Disposable { if (!myMovedFiles.isEmpty()) { executeMoveRename(); } + if (! myDirtyFiles.isEmpty()) { + final List files = new ArrayList(); + final List dirs = new ArrayList(); + for (VirtualFile dirtyFile : myDirtyFiles) { + if (dirtyFile != null) { + if (dirtyFile.isDirectory()) { + dirs.add(dirtyFile); + } else { + files.add(dirtyFile); + } + } + } + myDirtyScopeManager.filesDirty(files, dirs); + } } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index fe1727b77099..f584e79b4ab1 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1844,4 +1844,6 @@ package.dot.html.delete.command=package.html deletion package.dot.html.may.be.package.info.convert.quickfix=Convert to package-info.java package.dot.html.convert.command=package.html to package-info.java conversion choose.super.class.to.ignore=Choose class -ignore.anonymous.inner.classes=Ignore anonymous inner classes \ No newline at end of file +ignore.anonymous.inner.classes=Ignore anonymous inner classes +try.with.identical.catches.display.name=Identical 'catch' branches in 'try' statement +try.with.identical.catches.problem.descriptor=Identical 'catch' branches in 'try' statement #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java index 0607fd78b62c..5deb22cc2a72 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java @@ -24,7 +24,9 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.ui.DocumentAdapter; import com.siyeh.ig.ui.FormattedTextFieldMacFix; @@ -283,4 +285,9 @@ public abstract class BaseInspection extends BaseJavaLocalInspectionTool { inspectionGadgetsPlugin = null; } } + + @Nullable + public TextRange getProblemTextRange(PsiElement element) { + return null; + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java index c365f9e72c54..e93b09e95c3a 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java @@ -16,6 +16,7 @@ package com.siyeh.ig; import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -167,7 +168,13 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor{ fix.setOnTheFly(onTheFly); } final String description = inspection.buildErrorString(infos); - holder.registerProblem(location, description, fixes); + TextRange range = inspection.getProblemTextRange(location); + if (range != null) { + holder.registerProblem(location, range, description, fixes); + } + else { + holder.registerProblem(location, description, fixes); + } } @NotNull diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index f16ffba98be5..dea51ebec133 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -833,6 +833,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, m_inspectionClasses.add(ThrowFromFinallyBlockInspection.class); m_inspectionClasses.add(TooBroadCatchInspection.class); m_inspectionClasses.add(TooBroadThrowsInspection.class); + m_inspectionClasses.add(TryWithIdenticalCatchesInspection.class); m_inspectionClasses.add(UncheckedExceptionClassInspection.class); m_inspectionClasses.add(UnusedCatchParameterInspection.class); } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java new file mode 100644 index 000000000000..bfe4f41616b5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesInspection.java @@ -0,0 +1,138 @@ +/* + * 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.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.extractMethod.InputVariables; +import com.intellij.refactoring.util.duplicates.DuplicatesFinder; +import com.intellij.refactoring.util.duplicates.Match; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +/** + * @author yole + */ +public class TryWithIdenticalCatchesInspection extends BaseInspection { + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("try.with.identical.catches.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new TryWithIdenticalCatchesVisitor(); + } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("try.with.identical.catches.display.name"); + } + + @Override + public TextRange getProblemTextRange(PsiElement element) { + if (element instanceof PsiCatchSection) { + PsiJavaToken rParenth = ((PsiCatchSection)element).getRParenth(); + if (rParenth != null) { + return new TextRange(0, rParenth.getTextOffset() + 1 - element.getTextOffset()); + } + } + return null; + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new CollapseCatchSectionsFix((Integer) infos[0]); + } + + private static class TryWithIdenticalCatchesVisitor extends BaseInspectionVisitor { + @Override + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + if (!PsiUtil.isLanguageLevel7OrHigher(statement)) { + return; + } + PsiCatchSection[] catchSections = statement.getCatchSections(); + boolean[] duplicates = new boolean[catchSections.length]; + for (int i = 0; i < catchSections.length; i++) { + if (duplicates[i]) continue; + InputVariables inputVariables = new InputVariables(Collections.singletonList(catchSections[i].getParameter()), + statement.getProject(), + new LocalSearchScope(catchSections[i].getCatchBlock()), + false); + DuplicatesFinder finder = new DuplicatesFinder(new PsiElement[] { catchSections [i].getCatchBlock() }, + inputVariables, null, Collections.emptyList()); + for (int j = 0; j < catchSections.length; j++) { + if (i == j || duplicates[j]) continue; + Match match = finder.isDuplicate(catchSections[j].getCatchBlock(), true); + if (match != null) { + registerError(catchSections[j], i); + duplicates[i] = true; + duplicates[j] = true; + } + } + } + } + } + + private static class CollapseCatchSectionsFix extends InspectionGadgetsFix { + private final int myCollapseIntoIndex; + + public CollapseCatchSectionsFix(int collapseIntoIndex) { + myCollapseIntoIndex = collapseIntoIndex; + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + PsiCatchSection section = (PsiCatchSection) descriptor.getPsiElement(); + PsiTryStatement stmt = (PsiTryStatement) section.getParent(); + PsiCatchSection[] catchSections = stmt.getCatchSections(); + if (myCollapseIntoIndex >= catchSections.length) { + return; // something has gone stale + } + PsiCatchSection collapseInto = catchSections[myCollapseIntoIndex]; + PsiParameter parameter1 = collapseInto.getParameter(); + PsiParameter parameter2 = section.getParameter(); + if (parameter1 == null || parameter2 == null) { + return; + } + String text = "try { } catch(" + parameter1.getTypeElement().getText() + " | " + parameter2.getTypeElement().getText() + " e) { }"; + PsiTryStatement newTryCatch = (PsiTryStatement)JavaPsiFacade.getElementFactory(project).createStatementFromText(text, stmt); + parameter1.getTypeElement().replace(newTryCatch.getCatchSections() [0].getParameter().getTypeElement()); + section.delete(); + } + + @NotNull + @Override + public String getName() { + return"Collapse catch blocks into multi-catch"; + } + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html new file mode 100644 index 000000000000..887abc484396 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TryWithIdenticalCatches.html @@ -0,0 +1,7 @@ + + +This inspection reports identical 'catch' sections in 'try' blocks under JDK 7. A quickfix is provided to collapse the sections into +a multi-catch section. +Powered by InspectionGadgets + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.after.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.after.java new file mode 100644 index 000000000000..79dcbcb6e65b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.after.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.errorhandling.try_identical_catches; + +class TryIdenticalCatches { + public void notIdentical() { + try { + + } + catch(NumberFormatException e) { + log(e); + } + catch(RuntimeException e) { + throw e; + } + } + + public void identical(boolean value) { + try { + if (value) { + throw new ClassNotFoundException(); + } + else { + throw new NumberFormatException(); + } + } + catch(ClassNotFoundException | NumberFormatException cnfe) { + log(cnfe); + } + } + + private void log(Exception e) { + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.java new file mode 100644 index 000000000000..1e6712046875 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.java @@ -0,0 +1,35 @@ +package com.siyeh.igtest.errorhandling.try_identical_catches; + +class TryIdenticalCatches { + public void notIdentical() { + try { + + } + catch(NumberFormatException e) { + log(e); + } + catch(RuntimeException e) { + throw e; + } + } + + public void identical(boolean value) { + try { + if (value) { + throw new ClassNotFoundException(); + } + else { + throw new NumberFormatException(); + } + } + catch(ClassNotFoundException cnfe) { + log(cnfe); + } + catch(NumberFormatException nfe) { + log(nfe); + } + } + + private void log(Exception e) { + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesTest.java new file mode 100644 index 000000000000..24d77d236ebf --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/TryWithIdenticalCatchesTest.java @@ -0,0 +1,40 @@ +/* + * 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.siyeh.ig.errorhandling; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.application.PluginPathManager; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; + +/** + * @author yole + */ +public class TryWithIdenticalCatchesTest extends LightCodeInsightFixtureTestCase { + public void test() { + myFixture.enableInspections(TryWithIdenticalCatchesInspection.class); + myFixture.configureByFile("com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.java"); + myFixture.checkHighlighting(true, false, false); + IntentionAction intention = myFixture.findSingleIntention("Collapse catch blocks into multi-catch"); + assertNotNull(intention); + myFixture.launchAction(intention); + myFixture.checkResultByFile("com/siyeh/igtest/errorhandling/try_identical_catches/TryIdenticalCatches.after.java"); + } + + @Override + protected String getBasePath() { + return PluginPathManager.getPluginHomePathRelative("InspectionGadgets") + "/test"; + } +} diff --git a/plugins/ant/src/META-INF/plugin.xml b/plugins/ant/src/META-INF/plugin.xml index d1b3915d0432..fcbbeab06305 100644 --- a/plugins/ant/src/META-INF/plugin.xml +++ b/plugins/ant/src/META-INF/plugin.xml @@ -16,6 +16,7 @@ + diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactBuildExtension.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactBuildExtension.java new file mode 100644 index 000000000000..89e301020cda --- /dev/null +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactBuildExtension.java @@ -0,0 +1,87 @@ +/* + * 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.lang.ant.config.impl.artifacts; + +import com.intellij.compiler.ant.*; +import com.intellij.compiler.ant.taskdefs.AntCall; +import com.intellij.compiler.ant.taskdefs.Import; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.packaging.artifacts.Artifact; +import com.intellij.packaging.artifacts.ArtifactManager; +import com.intellij.packaging.artifacts.ArtifactPropertiesProvider; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * @author nik + */ +public class AntArtifactBuildExtension extends ChunkBuildExtension { + @Override + public void generateProjectTargets(Project project, GenerationOptions genOptions, CompositeGenerator generator) { + final Artifact[] artifacts = ArtifactManager.getInstance(project).getSortedArtifacts(); + Set filesToImport = new LinkedHashSet(); + for (Artifact artifact : artifacts) { + for (Boolean value : Arrays.asList(true, false)) { + final AntArtifactProperties properties = getProperties(artifact, value); + if (properties != null) { + filesToImport.add(properties.getFileUrl()); + } + } + } + for (String url : filesToImport) { + final String path = VfsUtil.urlToPath(url); + final String relativePath = GenerationUtils.toRelativePath(path, BuildProperties.getProjectBaseDir(project), BuildProperties.getProjectBaseDirProperty(), genOptions); + generator.add(new Import(relativePath)); + } + } + + @Override + public void generateTasksForArtifact(Project project, Artifact artifact, boolean preprocessing, CompositeGenerator generator) { + final AntArtifactProperties properties = getProperties(artifact, preprocessing); + if (properties != null) { + generator.add(new AntCall(properties.getTargetName())); + } + } + + @Nullable + private static AntArtifactProperties getProperties(Artifact artifact, boolean preprocessing) { + final ArtifactPropertiesProvider provider; + if (preprocessing) { + provider = AntArtifactPreProcessingPropertiesProvider.getInstance(); + } + else { + provider = AntArtifactPostprocessingPropertiesProvider.getInstance(); + } + final AntArtifactProperties properties = (AntArtifactProperties)artifact.getProperties(provider); + return properties != null && properties.isEnabled() ? properties : null; + } + + @NotNull + @Override + public String[] getTargets(ModuleChunk chunk) { + return ArrayUtil.EMPTY_STRING_ARRAY; + } + + @Override + public void process(Project project, ModuleChunk chunk, GenerationOptions genOptions, CompositeGenerator generator) { + } +} diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPostprocessingPropertiesProvider.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPostprocessingPropertiesProvider.java index 4ff35bef72f4..cc62f0990467 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPostprocessingPropertiesProvider.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPostprocessingPropertiesProvider.java @@ -24,6 +24,10 @@ import org.jetbrains.annotations.NotNull; * @author nik */ public class AntArtifactPostprocessingPropertiesProvider extends ArtifactPropertiesProvider { + public static AntArtifactPostprocessingPropertiesProvider getInstance() { + return EP_NAME.findExtension(AntArtifactPostprocessingPropertiesProvider.class); + } + protected AntArtifactPostprocessingPropertiesProvider() { super("ant-postprocessing"); } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPreProcessingPropertiesProvider.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPreProcessingPropertiesProvider.java index cf0a73956c7b..be29f129dd86 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPreProcessingPropertiesProvider.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/artifacts/AntArtifactPreProcessingPropertiesProvider.java @@ -24,6 +24,10 @@ import org.jetbrains.annotations.NotNull; * @author nik */ public class AntArtifactPreProcessingPropertiesProvider extends ArtifactPropertiesProvider { + public static AntArtifactPreProcessingPropertiesProvider getInstance() { + return EP_NAME.findExtension(AntArtifactPreProcessingPropertiesProvider.class); + } + public AntArtifactPreProcessingPropertiesProvider() { super("ant-preprocessing"); } diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index 45b6bddfb3c1..54e17021f122 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -312,7 +312,14 @@ public class GitUtil { * @return timestamp as {@link Date} object */ public static Date parseTimestamp(String value) { - return new Date(Long.parseLong(value.trim()) * 1000); + final long parsed; + try { + parsed = Long.parseLong(value.trim()); + return new Date(parsed * 1000); + } catch (NumberFormatException e) { + LOG.error("Error parsing timestamp from " + value, e); + return new Date(); + } } /** @@ -743,7 +750,7 @@ public class GitUtil { GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG); h.setSilent(true); h.setNoSSH(true); - h.addParameters("--pretty=format:%x00%x01" + GitChangeUtils.COMMITTED_CHANGELIST_FORMAT, "--name-status"); + h.addParameters("--pretty=format:%x04%x01" + GitChangeUtils.COMMITTED_CHANGELIST_FORMAT, "--name-status"); parametersSpecifier.consume(h); String output = h.run(); @@ -753,7 +760,7 @@ public class GitUtil { boolean firstStep = true; while (s.hasMoreData()) { final String line = s.line(); - final boolean lineIsAStart = line.startsWith("\u0000\u0001"); + final boolean lineIsAStart = line.startsWith("\u0004\u0001"); if ((!firstStep) && lineIsAStart) { final StringScanner innerScanner = new StringScanner(sb.toString()); sb.setLength(0); diff --git a/plugins/git4idea/src/git4idea/actions/GitShowAllSubmittedFilesAction.java b/plugins/git4idea/src/git4idea/actions/GitShowAllSubmittedFilesAction.java index dfbd405b8bb5..9eb2533feda9 100644 --- a/plugins/git4idea/src/git4idea/actions/GitShowAllSubmittedFilesAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitShowAllSubmittedFilesAction.java @@ -32,7 +32,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ui.UIUtil; import git4idea.GitFileRevision; import git4idea.GitUtil; -import git4idea.GitVcs; import git4idea.changes.GitChangeUtils; import git4idea.i18n.GitBundle; import git4idea.ui.GitUIUtil; @@ -98,8 +97,7 @@ public class GitShowAllSubmittedFilesAction extends AnAction implements DumbAwar * @param file file affected by the revision */ public static void showSubmittedFiles(final Project project, final String revision, final VirtualFile file) { - GitVcs.getInstance(project).runInBackground(new Task.Backgroundable(project, GitBundle.message("changes.retrieving", revision)) { - + new Task.Backgroundable(project, GitBundle.message("changes.retrieving", revision)) { public void run(@NotNull ProgressIndicator indicator) { indicator.setIndeterminate(true); try { @@ -122,7 +120,7 @@ public class GitShowAllSubmittedFilesAction extends AnAction implements DumbAwar }); } } - }); + }.queue(); } diff --git a/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java b/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java index 16e6467e84f3..0ae8d180ee41 100644 --- a/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java +++ b/plugins/git4idea/src/git4idea/changes/GitChangeUtils.java @@ -306,7 +306,7 @@ public class GitChangeUtils { h.setNoSSH(true); h.setSilent(true); h.addParameters(parameters); - h.addParameters("--max-count=1", "--pretty=%H", "--encoding=UTF-8", "\"" + anyReference + "\"", "--"); + h.addParameters("--max-count=1", "--pretty=%H", "--encoding=UTF-8", anyReference, "--"); try { final String output = h.run().trim(); if (StringUtil.isEmptyOrSpaces(output)) return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java index 9177e6552db6..2e091407d312 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java @@ -63,6 +63,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDef import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; +import org.jetbrains.plugins.groovy.lang.psi.util.GrClassImplUtil; import java.io.File; import java.io.IOException; @@ -355,7 +356,7 @@ public class GroovyToJavaGenerator { final PsiMethod method = ((MethodSignatureBackedByPsiMethod)signature).getMethod(); final PsiClass baseClass = method.getContainingClass(); if (isAbstractInJava(method) && baseClass != null && typeDefinition.isInheritor(baseClass, true)) { - methods.add(mirrorMethod(typeDefinition, method, baseClass, JAVA_MODIFIERS)); + methods.add(mirrorMethod(typeDefinition, method, baseClass, PsiSubstitutor.EMPTY, JAVA_MODIFIERS)); } } } @@ -368,20 +369,22 @@ public class GroovyToJavaGenerator { methods.add(factory.createMethodFromText("public void setProperty(String propertyName, Object newValue) {}", null)); } - for (PsiClass resolve : collectDelegateTypes(typeDefinition)) { - for (PsiMethod method : resolve.getAllMethods()) { - if (method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.STATIC)) { - methods.add(mirrorMethod(typeDefinition, method, typeDefinition, PsiModifier.PUBLIC, PsiModifier.PROTECTED, PsiModifier.PRIVATE)); - } + if (typeDefinition instanceof GrTypeDefinition) { + for (PsiMethod delegatedMethod : GrClassImplUtil.getDelegatedMethods((GrTypeDefinition)typeDefinition)) { + methods.add(delegatedMethod); } } return methods; } - private static LightMethodBuilder mirrorMethod(PsiClass typeDefinition, PsiMethod method, PsiClass baseClass, String... modifierFilter) { + private static LightMethodBuilder mirrorMethod(PsiClass typeDefinition, + PsiMethod method, + PsiClass baseClass, + PsiSubstitutor substitutor, + String... modifierFilter) { final LightMethodBuilder builder = new LightMethodBuilder(method.getManager(), method.getName()); - final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, typeDefinition, PsiSubstitutor.EMPTY); + substitutor = substitutor.putAll(TypeConversionUtil.getSuperClassSubstitutor(baseClass, typeDefinition, PsiSubstitutor.EMPTY)); for (PsiParameter parameter : method.getParameterList().getParameters()) { builder.addParameter(StringUtil.notNullize(parameter.getName()), substitutor.substitute(parameter.getType())); } @@ -394,20 +397,6 @@ public class GroovyToJavaGenerator { return builder; } - private static List collectDelegateTypes(PsiClass typeDefinition) { - final ArrayList result = new ArrayList(); - for (PsiField field : typeDefinition.getFields()) { - final PsiModifierList modifierList = field.getModifierList(); - if (modifierList != null && modifierList.findAnnotation("groovy.lang.Delegate") != null) { - final PsiType type = field.getType(); - if (type instanceof PsiClassType) { - ContainerUtil.addIfNotNull(result, ((PsiClassType)type).resolve()); - } - } - } - return result; - } - private static boolean isAbstractInJava(PsiMethod method) { if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { return true; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java index d5aab3694a53..5c27421ab3db 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovycStubGenerator.java @@ -44,6 +44,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerBase; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration; +import org.jetbrains.plugins.groovy.refactoring.GroovyNamesUtil; import java.io.File; import java.io.IOException; @@ -77,7 +78,7 @@ public class GroovycStubGenerator extends GroovyCompilerBase { } if (!excluded.isExcluded(virtualFile)) { - if (fileType == GroovyFileType.GROOVY_FILE_TYPE && !"package-info".equals(virtualFile.getNameWithoutExtension())) { + if (fileType == GroovyFileType.GROOVY_FILE_TYPE && GroovyNamesUtil.isIdentifier(virtualFile.getNameWithoutExtension())) { total.add(virtualFile); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java index 4acba2698cfd..d8085109a7bd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java @@ -1,17 +1,17 @@ package org.jetbrains.plugins.groovy.debugger; import com.intellij.execution.Executor; -import com.intellij.execution.configurations.JavaParameters; -import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.configurations.*; import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.runners.JavaProgramPatcher; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.PluginPathManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JdkUtil; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.LanguageLevelModuleExtension; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; @@ -78,10 +78,20 @@ public class GroovyHotSwapper extends JavaProgramPatcher { return; } - if (LanguageLevelProjectExtension.getInstance(project).getLanguageLevel().compareTo(LanguageLevel.JDK_1_5) < 0) { + if (!LanguageLevelProjectExtension.getInstance(project).getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_5)) { return; } + if (configuration instanceof ModuleBasedConfiguration) { + final Module module = ((ModuleBasedConfiguration)configuration).getConfigurationModule().getModule(); + if (module != null) { + final LanguageLevel level = LanguageLevelModuleExtension.getInstance(module).getLanguageLevel(); + if (level != null && !level.isAtLeast(LanguageLevel.JDK_1_5)) { + return; + } + } + } + Sdk jdk = javaParameters.getJdk(); if (jdk != null) { String vendor = JdkUtil.getJdkMainAttribute(jdk, Attributes.Name.IMPLEMENTATION_VENDOR); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java index 8f771b38ddf1..74595e8790db 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrClassImplUtil.java @@ -513,7 +513,8 @@ public class GrClassImplUtil { final PsiType type = field.getDeclaredType(); if (!(type instanceof PsiClassType)) continue; - final PsiClass psiClass = ((PsiClassType)type).resolve(); + final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics(); + final PsiClass psiClass = resolveResult.getElement(); if (psiClass == null) continue; final boolean deprecated = shouldDelegateDeprecated(delegate); @@ -527,7 +528,7 @@ public class GrClassImplUtil { for (PsiMethod method : methods) { if (method.isConstructor()) continue; if (!deprecated && getAnnotation(method, "java.lang.Deprecated") != null) continue; - result.add(generateDelegateMethod(method, clazz)); + result.add(generateDelegateMethod(method, clazz, resolveResult.getSubstitutor())); } } return new Result>(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); @@ -538,15 +539,15 @@ public class GrClassImplUtil { return cachedValue.getValue(); } - private static PsiMethod generateDelegateMethod(PsiMethod method, PsiClass clazz) { + private static PsiMethod generateDelegateMethod(PsiMethod method, PsiClass clazz, PsiSubstitutor substitutor) { final LightMethodBuilder builder = new LightMethodBuilder(clazz.getManager(), GroovyFileType.GROOVY_LANGUAGE, method.getName()); builder.setContainingClass(clazz); - builder.setReturnType(method.getReturnType()); + builder.setReturnType(substitutor.substitute(method.getReturnType())); builder.setNavigationElement(method); builder.addModifier(PsiModifier.PUBLIC); final PsiParameter[] originalParameters = method.getParameterList().getParameters(); for (PsiParameter originalParameter : originalParameters) { - builder.addParameter(originalParameter); + builder.addParameter(originalParameter.getName(), substitutor.substitute(originalParameter.getType())); } builder.setBaseIcon(GroovyIcons.METHOD); return builder; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.java index 8b1a8ee8aa29..ccdaaae4ed02 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/LightGroovyTestCase.java @@ -17,10 +17,6 @@ package org.jetbrains.plugins.groovy; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleType; -import com.intellij.openapi.module.StdModuleTypes; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.OrderRootType; @@ -28,6 +24,7 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -37,17 +34,7 @@ import org.jetbrains.plugins.groovy.util.TestUtils; * @author peter */ public abstract class LightGroovyTestCase extends LightCodeInsightFixtureTestCase { - public static final LightProjectDescriptor GROOVY_DESCRIPTOR = new LightProjectDescriptor() { - @Override - public ModuleType getModuleType() { - return StdModuleTypes.JAVA; - } - - @Override - public Sdk getSdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - + public static final LightProjectDescriptor GROOVY_DESCRIPTOR = new DefaultLightProjectDescriptor() { @Override public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY").getModifiableModel(); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java index d87d6de0de25..e070a7404cab 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GeneratorTest.java @@ -58,11 +58,10 @@ public class GeneratorTest extends LightGroovyTestCase { public void testThrowsCheckedException() throws Throwable { doTest(); } public void testSubclassProperty() throws Throwable { doTest(); } - public void testRawReturnTypeInImplementation() throws Throwable { - myFixture.addClass("package java.util.concurrent;" + - "public interface Callable {" + - " V call() throws java.lang.Exception;" + - "}"); + public void testRawReturnTypeInImplementation() throws Throwable { doTest(); } + + public void testDelegationGenerics() throws Throwable { + myFixture.addClass("package groovy.lang; public @interface Delegate { boolean interfaces() default true; }"); doTest(); } @@ -75,8 +74,7 @@ public class GeneratorTest extends LightGroovyTestCase { } public void testInaccessiblePropertyType() throws Throwable { - myFixture.addClass("package foo;" + - "class Hidden {}"); + myFixture.addClass("package foo; class Hidden {}"); doTest(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy index 3f83dff82597..35500fafe438 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy @@ -17,23 +17,20 @@ package org.jetbrains.plugins.groovy.gant; import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleType -import com.intellij.openapi.module.StdModuleTypes -import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.projectRoots.impl.JavaSdkImpl import com.intellij.openapi.roots.ContentEntry import com.intellij.openapi.roots.ModifiableRootModel import com.intellij.openapi.roots.OrderRootType import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.vfs.JarFileSystem import com.intellij.testFramework.LightProjectDescriptor +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUntypedAccessInspection import org.jetbrains.plugins.groovy.util.TestUtils -import org.jetbrains.annotations.NotNull -/** + /** * @author ilyas */ public class GantReferenceCompletionTest extends LightCodeInsightFixtureTestCase { @@ -178,15 +175,7 @@ target (default : '') { } -class GantProjectDescriptor implements LightProjectDescriptor { - public ModuleType getModuleType() { - return StdModuleTypes.JAVA; - } - - public Sdk getSdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - +class GantProjectDescriptor extends DefaultLightProjectDescriptor { public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY").getModifiableModel(); diff --git a/plugins/groovy/testdata/groovy/stubGenerator/delegationGenerics.test b/plugins/groovy/testdata/groovy/stubGenerator/delegationGenerics.test new file mode 100644 index 000000000000..e00eff8e74ef --- /dev/null +++ b/plugins/groovy/testdata/groovy/stubGenerator/delegationGenerics.test @@ -0,0 +1,44 @@ +interface Foo { + V get(K k); +} + +class ConfigNode { + @Delegate final Foo delegate +} +----- +public interface Foo { + public V get(K k) ; +} +--- +public class ConfigNode extends groovy.lang.GroovyObjectSupport implements Foo, groovy.lang.GroovyObject { + public final Foo getDelegate() { + return null; + } + + public java.lang.Object get(java.lang.String k) { + return null; + } + + public groovy.lang.MetaClass getMetaClass() { + return null; + } + + public void setMetaClass(groovy.lang.MetaClass mc) { + return ; + } + + public java.lang.Object invokeMethod(java.lang.String name, java.lang.Object args) { + return null; + } + + public java.lang.Object getProperty(java.lang.String propertyName) { + return null; + } + + public void setProperty(java.lang.String propertyName, java.lang.Object newValue) { + return ; + } + + private final Foo delegate = null; +} +--- \ No newline at end of file diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java index be5352929912..5dd6b7f4e595 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java @@ -23,7 +23,6 @@ import com.intellij.openapi.progress.BackgroundTaskQueue; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.JDOMUtil; @@ -46,7 +45,6 @@ import org.jetbrains.idea.maven.utils.*; import java.io.File; import java.io.IOException; -import java.rmi.RemoteException; import java.util.*; public class MavenIndicesManager { @@ -73,8 +71,7 @@ public class MavenIndicesManager { private final Object myUpdatingIndicesLock = new Object(); private final List myWaitingIndices = new ArrayList(); private volatile MavenIndex myUpdatingIndex; - private final BackgroundTaskQueue myUpdatingQueue = new BackgroundTaskQueue(ProjectManager.getInstance().getDefaultProject(), - IndicesBundle.message("maven.indices.updating")); + private final BackgroundTaskQueue myUpdatingQueue = new BackgroundTaskQueue(null, IndicesBundle.message("maven.indices.updating")); private volatile List myUserArchetypes = new ArrayList(); @@ -102,7 +99,7 @@ public class MavenIndicesManager { myIndexer = MavenFacadeManager.getInstance().createIndexer(); myDownloadListener = new MavenFacadeDownloadListener() { - public void artifactDownloaded(File file, String relativePath) throws RemoteException { + public void artifactDownloaded(File file, String relativePath) { addArtifact(file, relativePath); } }; @@ -205,7 +202,7 @@ public class MavenIndicesManager { } } - private String getRepositoryUrl(File artifactFile, String name) { + private static String getRepositoryUrl(File artifactFile, String name) { List parts = getArtifactParts(name); File result = artifactFile; @@ -215,7 +212,7 @@ public class MavenIndicesManager { return result.getPath(); } - private List getArtifactParts(String name) { + private static List getArtifactParts(String name) { return StringUtil.split(name, "/"); } @@ -284,11 +281,10 @@ public class MavenIndicesManager { } } - private MavenGeneralSettings getMavenSettings(@NotNull final Project project, @NotNull MavenProgressIndicator indicator) + private static MavenGeneralSettings getMavenSettings(@NotNull final Project project, @NotNull MavenProgressIndicator indicator) throws MavenProcessCanceledException { - MavenGeneralSettings settings; - settings = ApplicationManager.getApplication().runReadAction(new Computable() { + MavenGeneralSettings settings = ApplicationManager.getApplication().runReadAction(new Computable() { @Override public MavenGeneralSettings compute() { if (project.isDisposed()) return null; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachHandler.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachHandler.java index a0e12bcf9500..b11a8c027973 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachHandler.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/RepositoryAttachHandler.java @@ -157,7 +157,7 @@ public class RepositoryAttachHandler implements LibraryTableAttachHandler { FileUtil.copy(repoFile, toFile); } } - String url = VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(toFile.getPath())); + final String url = VfsUtil.getUrlForLibraryRoot(toFile); manager.refreshAndFindFileByUrl(url); if (MavenExtraArtifactType.DOCS.getDefaultClassifier().equals(each.getClassifier())) { libraryEditor.addRoot(url, JavadocOrderRootType.getInstance()); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenTestCase.java index 77aca6041cc9..1b4200f1991c 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenTestCase.java @@ -384,7 +384,7 @@ public abstract class MavenTestCase extends UsefulTestCase { return createProfilesFile(createProjectSubDir(relativePath), xml, false); } - private VirtualFile createProfilesFile(VirtualFile dir, String xml, boolean oldStyle) throws IOException { + private static VirtualFile createProfilesFile(VirtualFile dir, String xml, boolean oldStyle) throws IOException { return createProfilesFile(dir, createValidProfiles(xml, oldStyle)); } @@ -396,7 +396,7 @@ public abstract class MavenTestCase extends UsefulTestCase { return createProfilesFile(createProjectSubDir(relativePath), content); } - private VirtualFile createProfilesFile(final VirtualFile dir, String content) throws IOException { + private static VirtualFile createProfilesFile(final VirtualFile dir, String content) throws IOException { VirtualFile f = dir.findChild("profiles.xml"); if (f == null) { f = new WriteAction() { @@ -411,6 +411,7 @@ public abstract class MavenTestCase extends UsefulTestCase { return f; } + @Language("XML") private static String createValidProfiles(String xml, boolean oldStyle) { if (oldStyle) { return "" + @@ -478,15 +479,15 @@ public abstract class MavenTestCase extends UsefulTestCase { assertEquals(expected, actual); } - protected void assertOrderedElementsAreEqual(Collection actual, Collection expected) { + protected static void assertOrderedElementsAreEqual(Collection actual, Collection expected) { assertOrderedElementsAreEqual(actual, expected.toArray()); } - protected void assertUnorderedElementsAreEqual(Collection actual, Collection expected) { + protected static void assertUnorderedElementsAreEqual(Collection actual, Collection expected) { assertUnorderedElementsAreEqual(actual, expected.toArray()); } - protected void assertUnorderedElementsAreEqual(U[] actual, T... expected) { + protected static void assertUnorderedElementsAreEqual(U[] actual, T... expected) { assertUnorderedElementsAreEqual(Arrays.asList(actual), expected); } @@ -514,7 +515,7 @@ public abstract class MavenTestCase extends UsefulTestCase { for (int i = 0; i < expected.length; i++) { T expectedElement = expected[i]; U actualElement = actualList.get(i); - assertTrue(s, expectedElement.equals(actualElement)); + assertEquals(s, expectedElement, actualElement); } } @@ -526,7 +527,7 @@ public abstract class MavenTestCase extends UsefulTestCase { protected static void assertDoNotContain(List actual, T... expected) { List actualCopy = new ArrayList(actual); actualCopy.removeAll(Arrays.asList(expected)); - assertTrue(actual.toString(), actualCopy.size() == actual.size()); + assertEquals(actual.toString(), actualCopy.size(), actual.size()); } protected boolean ignore() { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java index 8655c42934bb..8c35ad17b4b0 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java @@ -19,7 +19,7 @@ import com.intellij.compiler.CompilerConfiguration; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.maven.MavenImportingTestCase; @@ -858,7 +858,7 @@ public class ResourceFilteringTest extends MavenImportingTestCase { public void testDoNotFilterButCopyBigFiles() throws Exception { assertFalse(CompilerConfiguration.getInstance(myProject).isResourceFile("file.xyz")); - assertEquals(FileTypeManager.getInstance().getFileTypeByFileName("file.xyz"), StdFileTypes.UNKNOWN); + assertEquals(FileTypeManager.getInstance().getFileTypeByFileName("file.xyz"), FileTypes.UNKNOWN); createProjectSubFile("resources/file.xyz").setBinaryContent(new byte[1024 * 1024 * 20]); diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index 3d84c3e01c53..5e4a963686c2 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/plugins/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -221,6 +221,13 @@ readonly refactor refactored refactoring +reifiable +reification +reifications +reified +reifies +reify +reifying reindex renderer resetlogs diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.form b/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.form index 25bb74aca16c..c15452cabdb4 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.form +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.form @@ -21,7 +21,7 @@ - + diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.java index 81f5e99c0fb4..ff9ee32403ea 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/config/BaseRepositoryEditor.java @@ -34,6 +34,7 @@ import java.awt.event.ActionListener; */ public class BaseRepositoryEditor extends TaskRepositoryEditor { + protected JLabel myUrlLabel; protected JTextField myURLText; protected JTextField myUserNameText; protected JLabel myUsernameLabel; diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepositoryEditor.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepositoryEditor.java index 0782a5b65f71..ea02946fd69d 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepositoryEditor.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepositoryEditor.java @@ -20,6 +20,9 @@ public class GitHubRepositoryEditor extends BaseRepositoryEditor changeListener) { super(project, repository, changeListener); + myUrlLabel.setVisible(false); + myURLText.setVisible(false); + // project author, by default same as username myRepoAuthor = new JTextField(); myRepoAuthor.setText(repository.getRepoAuthor()); diff --git a/plugins/ui-designer/testSrc/com/intellij/uiDesigner/binding/RenameUIRelatedTest.java b/plugins/ui-designer/testSrc/com/intellij/uiDesigner/binding/RenameUIRelatedTest.java index b1f6f3e83d9a..ffe873a1cbc6 100644 --- a/plugins/ui-designer/testSrc/com/intellij/uiDesigner/binding/RenameUIRelatedTest.java +++ b/plugins/ui-designer/testSrc/com/intellij/uiDesigner/binding/RenameUIRelatedTest.java @@ -41,11 +41,6 @@ public class RenameUIRelatedTest extends MultiFileTestCase { return PluginPathManager.getPluginHomePath("ui-designer") + "/testData"; } - @Override - protected Sdk getTestProjectJdk() { - return JavaSdkImpl.getMockJdk17("java 1.5"); - } - @Override protected void setupProject(VirtualFile rootDir) { LanguageLevelProjectExtension.getInstance(myJavaFacade.getProject()).setLanguageLevel(LanguageLevel.JDK_1_5); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 868c3ae07341..9a8aa3592a9e 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -260,6 +260,7 @@ order="last, before javaSmart"/> +