diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 156282cd75dc..5637497102cb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -49,7 +49,11 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.util.*; +import com.intellij.refactoring.typeMigration.TypeMigrationLabeler; +import com.intellij.refactoring.typeMigration.TypeMigrationProcessor; +import com.intellij.refactoring.typeMigration.TypeMigrationRules; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -401,7 +405,13 @@ public class HighlightClassUtil { if (aClass.isInterface()) { boolean isImplements = list.equals(aClass.getImplementsList()); if (isImplements) { - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, list, JavaErrorMessages.message("implements.after.interface")); + final HighlightInfo highlightInfo = + HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, list, JavaErrorMessages.message("implements.after.interface")); + final PsiClassType[] referencedTypes = list.getReferencedTypes(); + if (referencedTypes.length > 0) { + QuickFixAction.registerQuickFixAction(highlightInfo, new ChangeExtendsToImplementsFix(aClass, referencedTypes[0])); + } + return highlightInfo; } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 1e5416cdc798..47fa9a8a2f1c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -23,6 +23,7 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.util.TextRange; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; import com.intellij.psi.search.LocalSearchScope; @@ -698,7 +699,11 @@ public class HighlightControlFlowUtil { return null; } } - String description = JavaErrorMessages.message("variable.must.be.final", context.getText()); + if (PsiUtil.getLanguageLevel(variable).isAtLeast(LanguageLevel.JDK_1_8) && + isEffectivelyFinal(variable, innerClass, context)) { + return null; + } + final String description = JavaErrorMessages.message("variable.must.be.final", context.getText()); final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, context, description); QuickFixAction.registerQuickFixAction(highlightInfo, new VariableAccessFromInnerClassFix(variable, innerClass)); @@ -706,33 +711,11 @@ public class HighlightControlFlowUtil { } else { final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(context, PsiLambdaExpression.class); if (lambdaExpression != null && !PsiTreeUtil.isAncestor(lambdaExpression, variable, true)) { - boolean effectivelyFinal; - if (variable instanceof PsiParameter) { - final PsiElement parent = variable.getParent(); - if (parent instanceof PsiParameterList && parent.getParent() == lambdaExpression) { - return null; - } - effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(((PsiParameter)variable).getDeclarationScope())); - } else { - final ControlFlow controlFlow; - try { - controlFlow = getControlFlow(PsiUtil.getVariableCodeBlock(variable, context)); - } - catch (AnalysisCanceledException e) { - return null; - } - - if (ControlFlowUtil.isVariableDefinitelyAssigned(variable, controlFlow)) { - final Collection initializedTwice = ControlFlowUtil.getInitializedTwice(controlFlow); - effectivelyFinal = !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null)); - if (effectivelyFinal) { - effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(lambdaExpression)); - } - } else { - effectivelyFinal = false; - } + final PsiElement parent = variable.getParent(); + if (parent instanceof PsiParameterList && parent.getParent() == lambdaExpression) { + return null; } - if (!effectivelyFinal ) { + if (!isEffectivelyFinal(variable, lambdaExpression, context)) { return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, context, "Variable used in lambda expression should be effectively final"); } } @@ -740,6 +723,32 @@ public class HighlightControlFlowUtil { return null; } + private static boolean isEffectivelyFinal(PsiVariable variable, PsiElement scope, PsiJavaCodeReferenceElement context) { + boolean effectivelyFinal; + if (variable instanceof PsiParameter) { + effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(((PsiParameter)variable).getDeclarationScope())); + } else { + final ControlFlow controlFlow; + try { + controlFlow = getControlFlow(PsiUtil.getVariableCodeBlock(variable, context)); + } + catch (AnalysisCanceledException e) { + return true; + } + + if (ControlFlowUtil.isVariableDefinitelyAssigned(variable, controlFlow)) { + final Collection initializedTwice = ControlFlowUtil.getInitializedTwice(controlFlow); + effectivelyFinal = !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null)); + if (effectivelyFinal) { + effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(scope)); + } + } else { + effectivelyFinal = false; + } + } + return effectivelyFinal; + } + private static boolean notAccessedForWriting(PsiVariable variable, final LocalSearchScope searchScope) { for (PsiReference reference : ReferencesSearch.search(variable, searchScope)) { final PsiElement element = reference.getElement(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorMatchingSuperFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorMatchingSuperFix.java index 32e6750b5e22..57ed8f194357 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorMatchingSuperFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorMatchingSuperFix.java @@ -17,9 +17,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.QuickFixBundle; -import com.intellij.codeInsight.generation.ConstructorBodyGenerator; -import com.intellij.codeInsight.generation.GenerateMembersUtil; -import com.intellij.codeInsight.generation.PsiMethodMember; +import com.intellij.codeInsight.generation.*; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.ide.util.MemberChooser; import com.intellij.openapi.application.ApplicationManager; @@ -147,7 +145,9 @@ public class CreateConstructorMatchingSuperFix extends BaseIntentionAction { } derived = (PsiMethod)formatter.reformat(derived); derived = (PsiMethod)JavaCodeStyleManager.getInstance(project).shortenClassReferences(derived); - derived = (PsiMethod)GenerateMembersUtil.insert(targetClass, derived, null, true); + PsiGenerationInfo info = OverrideImplementUtil.createGenerationInfo(derived); + info.insert(targetClass, null, true); + derived = info.getPsiMember(); } if (derived != null) { editor.getCaretModel().moveToOffset(derived.getTextRange().getStartOffset()); diff --git a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java index 3be83cc48d6d..b8e3203e55ec 100644 --- a/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspection.java @@ -78,20 +78,31 @@ public class NullableStuffInspection extends BaseLocalInspectionTool { if (!PsiUtil.isLanguageLevel5OrHigher(expression) || !REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD) return; final PsiMethod psiMethod = expression.resolveMethod(); if (psiMethod != null && (psiMethod.getManager().isInProject(psiMethod) || CodeStyleSettingsManager.getInstance().getCurrentSettings().USE_EXTERNAL_ANNOTATIONS)) { + final NullableNotNullManager nullableNotNullManager = NullableNotNullManager.getInstance(holder.getProject()); + final PsiClass annotationsClass = + JavaPsiFacade.getInstance(holder.getProject()).findClass(nullableNotNullManager.getDefaultNullable(), psiMethod.getResolveScope()); + if (annotationsClass == null) return; final PsiParameterList parameterList = psiMethod.getParameterList(); final PsiParameter[] parameters = parameterList.getParameters(); final PsiExpression[] expressions = expression.getArgumentList().getExpressions(); for (int i = 0, expressionsLength = expressions.length; i < Math.min(expressionsLength, parameters.length); i++) { PsiExpression psiExpression = expressions[i]; - if (psiExpression.getType() == PsiType.NULL) { + boolean nullablePassedAsParameter = false; + if (psiExpression instanceof PsiMethodCallExpression) { + final PsiMethod method = expression.resolveMethod(); + nullablePassedAsParameter = nullableNotNullManager.isNullable(method, false); + } else if (psiExpression instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)psiExpression).resolve(); + if (resolve instanceof PsiModifierListOwner) { + nullablePassedAsParameter = nullableNotNullManager.isNullable((PsiModifierListOwner)resolve, false); + } + } + final PsiType exprType = psiExpression.getType(); + if (exprType == PsiType.NULL || nullablePassedAsParameter) { final PsiParameter parameter = parameters[i]; if (!NullableNotNullManager.isNullable(parameter) && !NullableNotNullManager.isNotNull(parameter)) { - final PsiClass annotationsClass = - JavaPsiFacade.getInstance(holder.getProject()).findClass(NullableNotNullManager.getInstance(holder.getProject()).getDefaultNullable(), - psiMethod.getResolveScope()); - if (annotationsClass != null) { - holder.registerProblem(psiExpression, "Null is passed to parameter which is not yet @Nullable", new MyAddNullableAnnotationFix(parameter)); - } + holder.registerProblem(psiExpression, "Nullable value is passed to parameter which is not yet @Nullable", + new MyAddNullableAnnotationFix(parameter)); } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java index 346d64831d15..2e0783e3d987 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java @@ -356,7 +356,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } public boolean hasSuperMethods() { - return !getSuperMethods().isEmpty() || isLibraryOverride(new HashSet()); + return !getSuperMethods().isEmpty() || isExternalOverride(); } public boolean isReferenced() { diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java index 89aa34787572..23941f46c43b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java @@ -30,6 +30,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.HashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -56,16 +57,19 @@ public class UnusedReturnValue extends GlobalJavaInspectionTool{ final RefMethod refMethod = (RefMethod)refEntity; if (refMethod.isConstructor()) return null; - if (refMethod.hasSuperMethods()) return null; + if (!refMethod.getSuperMethods().isEmpty()) return null; if (refMethod.getInReferences().size() == 0) return null; if (!refMethod.isReturnValueUsed()) { final PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); if (IGNORE_BUILDER_PATTERN && PropertyUtil.isSimplePropertySetter(psiMethod)) return null; + + final boolean isNative = psiMethod.hasModifierProperty(PsiModifier.NATIVE); + if (refMethod.isExternalOverride() && !isNative) return null; return new ProblemDescriptor[]{manager.createProblemDescriptor(psiMethod.getNavigationElement(), InspectionsBundle .message("inspection.unused.return.value.problem.descriptor"), - getFix(processor), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + !isNative ? getFix(processor) : null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)}; } } diff --git a/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java b/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java index 3d022a9f9fdf..17d937611b17 100644 --- a/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java +++ b/java/java-impl/src/com/intellij/psi/NonClasspathClassFinder.java @@ -130,6 +130,7 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder { } + @NotNull @Override public Set getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { final List classRoots = getClassRoots(); @@ -177,7 +178,7 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder { @Override public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, - Processor consumer) { + @NotNull Processor consumer) { final List classRoots = getClassRoots(); if (classRoots.isEmpty()) { return true; diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java index ec6ce75d242d..bf03e8ea3bb9 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java @@ -106,6 +106,7 @@ public class JavaRearranger implements Rearranger, for (ArrangementModifier modifier : visibility) { and(FIELD, modifier); } + and(FIELD); and(CONSTRUCTOR); and(METHOD, STATIC); and(METHOD); diff --git a/java/java-psi-api/src/com/intellij/psi/JavaPsiFacade.java b/java/java-psi-api/src/com/intellij/psi/JavaPsiFacade.java index b4313bebf566..3819fe5290b5 100644 --- a/java/java-psi-api/src/com/intellij/psi/JavaPsiFacade.java +++ b/java/java-psi-api/src/com/intellij/psi/JavaPsiFacade.java @@ -135,7 +135,7 @@ public abstract class JavaPsiFacade { * @param packageName the package name to check. * @return true if it is part of the package prefix, false otherwise. */ - public abstract boolean isPartOfPackagePrefix(String packageName); + public abstract boolean isPartOfPackagePrefix(@NotNull String packageName); /** * Checks if the specified PSI element belongs to the specified package. @@ -155,5 +155,6 @@ public abstract class JavaPsiFacade { */ public abstract boolean arePackagesTheSame(@NotNull PsiElement element1, @NotNull PsiElement element2); + @NotNull public abstract Project getProject(); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java b/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java index 8488baaf0081..6bedfff48a42 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiElementFinder.java @@ -97,11 +97,13 @@ public abstract class PsiElementFinder { return PsiClass.EMPTY_ARRAY; } + @NotNull public Set getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { return getClassNames(getClasses(psiPackage, scope)); } - protected static Set getClassNames(PsiClass[] classes) { + @NotNull + protected static Set getClassNames(@NotNull PsiClass[] classes) { if (classes.length == 0) { return Collections.emptySet(); } @@ -113,7 +115,7 @@ public abstract class PsiElementFinder { return names; } - public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, Processor consumer) { + public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, @NotNull Processor consumer) { return true; } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java b/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java index 62914df25d0b..94c08a1a2f6c 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypesDistinctProver.java @@ -79,9 +79,9 @@ public class TypesDistinctProver { return proveArrayTypeDistinct(((PsiWildcardType)type1).getManager().getProject(), (PsiArrayType)type2, type1); } } - if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType)type1).getWildcard(), type2, level +1); + if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType)type1).getWildcard(), type2, level); - if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1, level +1); + if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1, level); final PsiClassType.ClassResolveResult classResolveResult1 = PsiUtil.resolveGenericsClassInType(type1); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeEx.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeEx.java index 9553d44191d2..64d52091062b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeEx.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeEx.java @@ -22,6 +22,7 @@ package com.intellij.psi.impl; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFileFilter; import com.intellij.psi.JavaPsiFacade; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; public abstract class JavaPsiFacadeEx extends JavaPsiFacade { @@ -30,5 +31,5 @@ public abstract class JavaPsiFacadeEx extends JavaPsiFacade { } @TestOnly - public abstract void setAssertOnFileLoadingFilter(final VirtualFileFilter filter); + public abstract void setAssertOnFileLoadingFilter(@NotNull VirtualFileFilter filter); } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java index 782b0978fc43..16cecad25dec 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java @@ -34,7 +34,7 @@ import com.intellij.psi.impl.source.resolve.FileContextUtil; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Processor; import com.intellij.util.SmartList; @@ -43,6 +43,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.messages.MessageBus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import java.util.*; import java.util.concurrent.ConcurrentMap; @@ -51,7 +52,7 @@ import java.util.concurrent.ConcurrentMap; * @author max */ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { - private ArrayList myElementFinders; + private PsiElementFinder[] myElementFinders; //benign data race private final PsiNameHelper myNameHelper; private final PsiConstantEvaluationHelper myConstantEvaluationHelper; private final ConcurrentMap myPackageCache = new ConcurrentHashMap(); @@ -102,9 +103,9 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { ProgressIndicatorProvider.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly if (DumbService.getInstance(getProject()).isDumb()) { - final List classes = findClassesInDumbMode(qualifiedName, scope); - if (!classes.isEmpty()) { - return classes.get(0); + PsiClass[] classes = findClassesInDumbMode(qualifiedName, scope); + if (classes.length != 0) { + return classes[0]; } return null; } @@ -118,42 +119,46 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @NotNull - private List findClassesInDumbMode(String qualifiedName, GlobalSearchScope scope) { + private PsiClass[] findClassesInDumbMode(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { final String packageName = StringUtil.getPackageName(qualifiedName); final PsiPackage pkg = findPackage(packageName); final String className = StringUtil.getShortName(qualifiedName); if (pkg == null && packageName.length() < qualifiedName.length()) { - final List containingClasses = findClassesInDumbMode(packageName, scope); - if (containingClasses.size() == 1) { - return filterByName(className, containingClasses.get(0).getInnerClasses()); + PsiClass[] containingClasses = findClassesInDumbMode(packageName, scope); + if (containingClasses.length == 1) { + return filterByName(className, containingClasses[0].getInnerClasses()); } - return Collections.emptyList(); + return PsiClass.EMPTY_ARRAY; } if (pkg == null || !pkg.containsClassNamed(className)) { - return Collections.emptyList(); + return PsiClass.EMPTY_ARRAY; } return filterByName(className, pkg.getClasses(scope)); } - private static List filterByName(String className, PsiClass[] classes) { - final List foundClasses = new SmartList(); + @NotNull + private static PsiClass[] filterByName(@NotNull String className, @NotNull PsiClass[] classes) { + if (classes.length == 0) return PsiClass.EMPTY_ARRAY; + if (classes.length == 1) { + return className.equals(classes[0].getName()) ? classes : PsiClass.EMPTY_ARRAY; + } + List foundClasses = new SmartList(); for (PsiClass psiClass : classes) { if (className.equals(psiClass.getName())) { foundClasses.add(psiClass); } } - return foundClasses; + return foundClasses.isEmpty() ? PsiClass.EMPTY_ARRAY : foundClasses.toArray(new PsiClass[foundClasses.size()]); } @Override @NotNull public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { if (DumbService.getInstance(getProject()).isDumb()) { - final List classes = findClassesInDumbMode(qualifiedName, scope); - return classes.toArray(new PsiClass[classes.size()]); + return findClassesInDumbMode(qualifiedName, scope); } List classes = new SmartList(); @@ -165,8 +170,9 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return classes.toArray(new PsiClass[classes.size()]); } - private ArrayList finders() { - ArrayList answer = myElementFinders; + @NotNull + private PsiElementFinder[] finders() { + PsiElementFinder[] answer = myElementFinders; if (answer == null) { answer = calcFinders(); myElementFinders = answer; @@ -175,11 +181,12 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return answer; } - private ArrayList calcFinders() { - ArrayList elementFinders = new ArrayList(); + @NotNull + private PsiElementFinder[] calcFinders() { + List elementFinders = new ArrayList(); elementFinders.add(new PsiElementFinderImpl()); ContainerUtil.addAll(elementFinders, myProject.getExtensions(PsiElementFinder.EP_NAME)); - return elementFinders; + return elementFinders.toArray(new PsiElementFinder[elementFinders.size()]); } @Override @@ -205,16 +212,18 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return null; } - private List filteredFinders() { + @NotNull + private PsiElementFinder[] filteredFinders() { DumbService dumbService = DumbService.getInstance(getProject()); - List finders = finders(); + PsiElementFinder[] finders = finders(); if (dumbService.isDumb()) { - finders = dumbService.filterByDumbAwareness(finders); + List list = dumbService.filterByDumbAwareness(Arrays.asList(finders)); + finders = list.toArray(new PsiElementFinder[list.size()]); } return finders; } - @Override + @Override @NotNull public PsiJavaParserFacade getParserFacade() { return getElementFactory(); // TODO: lighter implementation which doesn't mark all the elements as generated. @@ -232,7 +241,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return myNameHelper; } - public Set getClassNames(PsiPackage psiPackage, GlobalSearchScope scope) { + @NotNull + public Set getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { Set result = new HashSet(); for (PsiElementFinder finder : filteredFinders()) { result.addAll(finder.getClassNames(psiPackage, scope)); @@ -240,7 +250,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return result; } - public PsiClass[] getClasses(PsiPackage psiPackage, GlobalSearchScope scope) { + @NotNull + public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { List result = null; for (PsiElementFinder finder : filteredFinders()) { PsiClass[] classes = finder.getClasses(psiPackage, scope); @@ -252,7 +263,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return result == null ? PsiClass.EMPTY_ARRAY : result.toArray(new PsiClass[result.size()]); } - public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, Processor consumer) { + public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope, @NotNull Processor consumer) { for (PsiElementFinder finder : filteredFinders()) { if (!finder.processPackageDirectories(psiPackage, scope, consumer)) { return false; @@ -261,7 +272,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return true; } - public PsiPackage[] getSubPackages(PsiPackage psiPackage, GlobalSearchScope scope) { + @NotNull + public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { LinkedHashSet result = new LinkedHashSet(); for (PsiElementFinder finder : filteredFinders()) { PsiPackage[] packages = finder.getSubPackages(psiPackage, scope); @@ -334,8 +346,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { ContainerUtil.quickSort(list, new Comparator() { @Override public int compare(PsiClass o1, PsiClass o2) { - VirtualFile file2 = PsiUtil.getVirtualFile(o2); - VirtualFile file1 = PsiUtil.getVirtualFile(o1); + VirtualFile file2 = PsiUtilCore.getVirtualFile(o2); + VirtualFile file1 = PsiUtilCore.getVirtualFile(o1); return scope.compare(file2, file1); } }); @@ -343,6 +355,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return list.toArray(new PsiClass[list.size()]); } + @NotNull @Override public Set getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { Set names = null; @@ -362,7 +375,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @Override - public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull final GlobalSearchScope scope, final Processor consumer) { + public boolean processPackageDirectories(@NotNull PsiPackage psiPackage, @NotNull final GlobalSearchScope scope, @NotNull final Processor consumer) { final PsiManager psiManager = PsiManager.getInstance(getProject()); PackageIndex.getInstance(getProject()).getDirsByPackageName(psiPackage.getQualifiedName(), false).forEach(new ReadActionProcessor() { @Override @@ -378,7 +391,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { @Override - public boolean isPartOfPackagePrefix(String packageName) { + public boolean isPartOfPackagePrefix(@NotNull String packageName) { final Collection packagePrefixes = myFileManager.getNonTrivialPackagePrefixes(); for (final String subpackageName : packagePrefixes) { if (isSubpackageOf(subpackageName, packageName)) return true; @@ -386,7 +399,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return false; } - private static boolean isSubpackageOf(final String subpackageName, String packageName) { + private static boolean isSubpackageOf(@NotNull String subpackageName, @NotNull String packageName) { return subpackageName.equals(packageName) || subpackageName.startsWith(packageName) && subpackageName.charAt(packageName.length()) == '.'; } @@ -423,6 +436,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @Override + @NotNull public Project getProject() { return myProject; } @@ -433,8 +447,9 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return PsiElementFactory.SERVICE.getInstance(myProject); } + @TestOnly @Override - public void setAssertOnFileLoadingFilter(final VirtualFileFilter filter) { + public void setAssertOnFileLoadingFilter(@NotNull final VirtualFileFilter filter) { ((PsiManagerImpl)PsiManager.getInstance(myProject)).setAssertOnFileLoadingFilter(filter); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCatchSectionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCatchSectionImpl.java index 6dd26b59e597..a9b8af316920 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCatchSectionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiCatchSectionImpl.java @@ -145,9 +145,9 @@ public class PsiCatchSectionImpl extends CompositePsiElement implements PsiCatch if (catchBlock != null) { catchBlock.accept(new JavaRecursiveElementWalkingVisitor() { @Override - public void visitAssignmentExpression(final PsiAssignmentExpression expression) { - final PsiExpression left = expression.getLExpression(); - if (left instanceof PsiReferenceExpression && parameter.equals(((PsiReferenceExpression)left).resolve())) { + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (expression.resolve() == parameter && PsiUtil.isAccessedForWriting(expression)) { result[0] = false; stopWalking(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolveProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolveProcessor.java new file mode 100644 index 000000000000..463e2a12b04a --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolveProcessor.java @@ -0,0 +1,96 @@ +/* + * 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.psi.scope.processor; + +import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.ResolveState; +import com.intellij.psi.scope.ElementClassHint; +import com.intellij.psi.scope.NameHint; +import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Avdeev + */ +public class MethodResolveProcessor implements PsiScopeProcessor, ElementClassHint, NameHint { + + private final String myNameHint; + private final List myMethods = new ArrayList(); + + public MethodResolveProcessor() { + myNameHint = null; + } + + public MethodResolveProcessor(final String name) { + myNameHint = name; + } + + public PsiMethod[] getMethods() { + return myMethods.toArray(new PsiMethod[myMethods.size()]); + } + + public boolean execute(@NotNull PsiElement element, ResolveState state) { + if (element instanceof PsiMethod) { + ContainerUtil.addIfNotNull(myMethods, (PsiMethod)element); + } + return true; + } + + public T getHint(@NotNull Key hintKey) { + if (hintKey == ElementClassHint.KEY) { + return (T)this; + } + if (hintKey == NameHint.KEY && myNameHint != null) { + return (T)this; + } + return null; + } + + public void handleEvent(Event event, Object associated) { + } + + public boolean shouldProcess(DeclarationKind kind) { + return kind == DeclarationKind.METHOD; + } + + public static PsiMethod[] findMethod(PsiClass psiClass, String methodName) { + MethodResolveProcessor processor = new MethodResolveProcessor(methodName); + psiClass.processDeclarations(processor, ResolveState.initial(), null, psiClass); + return processor.getMethods(); + } + + public static PsiMethod[] getAllMethods(PsiClass psiClass) { + MethodResolveProcessor processor = new MethodResolveProcessor(); + psiClass.processDeclarations(processor, ResolveState.initial(), null, psiClass); + return processor.getMethods(); + } + + + @Nullable + @Override + public String getName(ResolveState state) { + return myNameHint; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/WildcardTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/WildcardTypes.java index f5483d41ed6f..b230591054a9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/WildcardTypes.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/WildcardTypes.java @@ -231,4 +231,16 @@ class IDEA91481 { class BeanBuilder<T> {} class Bean {} class DirectBean extends Bean {} +} + +class IDEA89640 { + interface X {} + class Y<T extends X> {} + + public static void main(String[] args) { + Y a = null; + Y b = null; + boolean flag = a != b; + System.out.println(flag); + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeExtendsToImplements/afterInterface1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeExtendsToImplements/afterInterface1.java new file mode 100644 index 000000000000..861a85a57176 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeExtendsToImplements/afterInterface1.java @@ -0,0 +1,4 @@ +// "Change 'implements Runnable' to 'extends Runnable'" "true" +interface a extends Runnable { +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeExtendsToImplements/beforeInterface1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeExtendsToImplements/beforeInterface1.java new file mode 100644 index 000000000000..1bfaf485f9f3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeExtendsToImplements/beforeInterface1.java @@ -0,0 +1,4 @@ +// "Change 'implements Runnable' to 'extends Runnable'" "true" +interface a implements Runnable { +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mustBeFinal18/before1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mustBeFinal18/before1.java new file mode 100644 index 000000000000..db4e780861c8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/mustBeFinal18/before1.java @@ -0,0 +1,14 @@ +// "Make 'i' final" "false" +import java.io.*; + +class a { + void f() { + int i = 0; + new Runnable() { + public void run() { + int ii = i; + } + }; + } +} + diff --git a/java/java-tests/testData/inspection/unusedReturnValue/native/expected.xml b/java/java-tests/testData/inspection/unusedReturnValue/native/expected.xml new file mode 100644 index 000000000000..1e9ac4bc0e7c --- /dev/null +++ b/java/java-tests/testData/inspection/unusedReturnValue/native/expected.xml @@ -0,0 +1,8 @@ + + + + Test.java + 2 + Return value of the method is never used + + diff --git a/java/java-tests/testData/inspection/unusedReturnValue/native/src/Test.java b/java/java-tests/testData/inspection/unusedReturnValue/native/src/Test.java new file mode 100644 index 000000000000..3cae2c18903e --- /dev/null +++ b/java/java-tests/testData/inspection/unusedReturnValue/native/src/Test.java @@ -0,0 +1,7 @@ +class Test { + private static native boolean isUnused(); + + public static void main(String[] args) { + Test.isUnused(); + } +} diff --git a/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImplTest.java b/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImplTest.java index 87b91a6e16e9..3f6475c9d266 100644 --- a/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImplTest.java +++ b/java/java-tests/testSrc/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleEditingModelImplTest.java @@ -145,23 +145,18 @@ public class ArrangementRuleEditingModelImplTest extends AbstractArrangementRule modelToChange.removeAndCondition(atom(PUBLIC)); - assertSame(1, modelToChange.getRow()); - assertEquals(atom(FIELD), modelToChange.getCondition()); - assertSame(3, siblingModel.getRow()); assertEquals(and(atom(FIELD), atom(STATIC)), siblingModel.getCondition()); - ArrangementTreeNode atomFieldNode = myRoot.getFirstChild(); - assertNotNull(atomFieldNode); - assertEquals(atom(FIELD), atomFieldNode.getBackingCondition()); + ArrangementTreeNode fieldNode = myRoot.getFirstChild(); + assertNotNull(fieldNode); + assertEquals(atom(FIELD), fieldNode.getBackingCondition()); - ArrangementTreeNode layeredFieldNode = atomFieldNode.getNextSibling(); - assertNotNull(atomFieldNode); - assertEquals(atom(FIELD), atomFieldNode.getBackingCondition()); - - ArrangementTreeNode staticNode = layeredFieldNode.getFirstChild(); + ArrangementTreeNode staticNode = fieldNode.getFirstChild(); assertNotNull(staticNode); assertEquals(atom(STATIC), staticNode.getBackingCondition()); + + assertNull(staticNode.getNextNode()); } @Test @@ -182,20 +177,15 @@ public class ArrangementRuleEditingModelImplTest extends AbstractArrangementRule assertSame(siblingModel, myRowMappings.get(2)); assertEquals(and(atom(FIELD), atom(PUBLIC)), siblingModel.getCondition()); - assertSame(modelToChange, myRowMappings.get(3)); - assertEquals(atom(FIELD), modelToChange.getCondition()); + ArrangementTreeNode fieldNode = myRoot.getFirstChild(); + assertNotNull(fieldNode); + assertEquals(atom(FIELD), fieldNode.getBackingCondition()); - ArrangementTreeNode compositeFieldNode = myRoot.getFirstChild(); - assertNotNull(compositeFieldNode); - assertEquals(atom(FIELD), compositeFieldNode.getBackingCondition()); - - ArrangementTreeNode publicNode = compositeFieldNode.getFirstChild(); + ArrangementTreeNode publicNode = fieldNode.getFirstChild(); assertNotNull(publicNode); assertEquals(atom(PUBLIC), publicNode.getBackingCondition()); - ArrangementTreeNode atomFieldNode = compositeFieldNode.getNextSibling(); - assertNotNull(atomFieldNode); - assertEquals(atom(FIELD), atomFieldNode.getBackingCondition()); + assertNull(publicNode.getNextNode()); } private void checkModelTreeNodesConsistency(@NotNull ArrangementRuleEditingModelImpl model) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClass18Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClass18Test.java new file mode 100644 index 000000000000..d7c4e76371b1 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClass18Test.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.quickFix; + +import com.intellij.openapi.application.ApplicationManager; + +/** + * User: anna + */ +public class VariableAccessFromInnerClass18Test extends LightQuickFixTestCase { + public void test() throws Exception { + doAllTests(); + } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/mustBeFinal18"; + } + + @Override + protected void beforeActionStarted(String testName, String contents) { + for (int i=0;i<10;i++) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + myEditor.getDocument().insertString(myEditor.getCaretModel().getOffset(), "//"); + } + }); + + doHighlighting(); + delete(); + delete(); + doHighlighting(); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClassTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClassTest.java index 95fc1d6603b6..98b8a7432baf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClassTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/VariableAccessFromInnerClassTest.java @@ -1,33 +1,18 @@ package com.intellij.codeInsight.daemon.quickFix; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.pom.java.LanguageLevel; -public class VariableAccessFromInnerClassTest extends LightQuickFixTestCase { - public void test() throws Exception { - doAllTests(); - } - - @Override - protected void beforeActionStarted(String testName, String contents) { - for (int i=0;i<10;i++) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - myEditor.getDocument().insertString(myEditor.getCaretModel().getOffset(), "//"); - } - }); - - doHighlighting(); - delete(); - delete(); - doHighlighting(); - } - } +public class VariableAccessFromInnerClassTest extends VariableAccessFromInnerClass18Test { @Override protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/mustBeFinal"; } + + @Override + protected LanguageLevel getLanguageLevel() { + return LanguageLevel.JDK_1_7; + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/InspectionProfileTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/InspectionProfileTest.java index a8e4c63bf961..ff4ba0d97d27 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/InspectionProfileTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/InspectionProfileTest.java @@ -268,7 +268,7 @@ public class InspectionProfileTest extends LightIdeaTestCase { for (ScopeToolState tool : tools) { InspectionProfileEntry entry = tool.getTool(); assertTrue(entry instanceof InspectionToolWrapper); - if (entry.isInitialized() && ((InspectionToolWrapper)entry).hasXmlMapping()) { + if (entry.isInitialized()) { i++; } } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java index 0fcd2ef1a07e..6753f529f2d2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/UnusedReturnValueTest.java @@ -31,6 +31,10 @@ public class UnusedReturnValueTest extends InspectionTestCase { doTest(); } + public void testNative() throws Exception { + doTest(); + } + public void testHierarchy() throws Exception { doTest(); } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java index 9d02d2052db4..a0c23b19fbac 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java @@ -486,6 +486,10 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica } public void setCharset(final Charset charset) { + setCharset(charset, null); + } + + public void setCharset(final Charset charset, @Nullable Runnable whenChanged) { final Charset old = getUserData(CHARSET_KEY); putUserData(CHARSET_KEY, charset); if (Comparing.equal(charset, old)) return; @@ -497,6 +501,7 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica setBOM(bom); if (old != null) { //do not send on detect + if (whenChanged != null) whenChanged.run(); VirtualFileManager.getInstance().notifyPropertyChanged(this, PROP_ENCODING, old, charset); } } diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java index 4b12ef88955b..870ae592107f 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java @@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.ref.Reference; import java.util.Enumeration; import java.util.HashSet; import java.util.Map; @@ -46,7 +47,7 @@ public class JarHandlerBase { private static final long DEFAULT_TIMESTAMP = -1L; private final TimedReference myJarFile = new TimedReference(null); - private SoftReference> myRelPathsToEntries = new SoftReference>(null); + private Reference> myRelPathsToEntries = new SoftReference>(null); private final Object lock = new Object(); protected final String myBasePath; @@ -59,7 +60,7 @@ public class JarHandlerBase { public EntryInfo(final String shortName, final EntryInfo parent, final boolean directory) { this.shortName = shortName; this.parent = parent; - this.isDirectory = directory; + isDirectory = directory; } } @@ -88,7 +89,7 @@ public class JarHandlerBase { while (entries.hasMoreElements()) { JarFile.JarEntry entry = entries.nextElement(); final String name = entry.getName(); - final boolean isDirectory = name.endsWith("/"); + final boolean isDirectory = StringUtil.endsWithChar(name, '/'); getOrCreate(isDirectory ? name.substring(0, name.length() - 1) : name, isDirectory, map); } @@ -105,17 +106,19 @@ public class JarHandlerBase { @Nullable public JarFile getJar() { - synchronized (lock) { - JarFile jar = myJarFile.get(); - if (jar == null) { - jar = createJarFile(); - if (jar != null) { - myJarFile.set(jar); + JarFile jar = myJarFile.get(); + if (jar == null) { + synchronized (lock) { + jar = myJarFile.get(); + if (jar == null) { + jar = createJarFile(); + if (jar != null) { + myJarFile.set(jar); + } } } - - return jar; } + return jar; } @Nullable diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java index c7cb00668529..216de4634e17 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java @@ -44,6 +44,7 @@ import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.containers.ConcurrentSoftValueHashMap; import com.intellij.util.containers.ConcurrentWeakValueHashMap; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; @@ -416,7 +417,7 @@ public class FileManagerImpl implements FileManager { List files = new ArrayList(); for (FileViewProvider provider : myVFileToViewProviderMap.values()) { if (provider instanceof SingleRootFileViewProvider) { - files.add(((SingleRootFileViewProvider)provider).getCachedPsi(provider.getBaseLanguage())); + ContainerUtil.addIfNotNull(files, ((SingleRootFileViewProvider)provider).getCachedPsi(provider.getBaseLanguage())); } } return files; diff --git a/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java b/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java index af02ab7c34f2..c242e6f8e3e9 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/CommandLineState.java @@ -60,6 +60,7 @@ public abstract class CommandLineState implements RunnableState { return myEnvironment.getExecutionTarget(); } + @NotNull public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { final ProcessHandler processHandler = startProcess(); final ConsoleView console = createConsole(executor); diff --git a/platform/lang-api/src/com/intellij/execution/ui/ObservableConsoleView.java b/platform/lang-api/src/com/intellij/execution/ui/ObservableConsoleView.java index 40ca61d92a54..87fcf415eb63 100644 --- a/platform/lang-api/src/com/intellij/execution/ui/ObservableConsoleView.java +++ b/platform/lang-api/src/com/intellij/execution/ui/ObservableConsoleView.java @@ -17,12 +17,13 @@ package com.intellij.execution.ui; import com.intellij.openapi.Disposable; +import org.jetbrains.annotations.NotNull; import java.util.Collection; public interface ObservableConsoleView { - void addChangeListener(ChangeListener listener, Disposable parent); + void addChangeListener(@NotNull ChangeListener listener, @NotNull Disposable parent); interface ChangeListener { void contentAdded(Collection types); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java index 28f26a7b9a46..1f278dbe7623 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAndNodeComponent.java @@ -110,6 +110,11 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo myScreenBounds = bounds; } + @Override + public boolean onCanvasWidthChange(int width) { + return false; + } + @Override public void setSelected(boolean selected) { for (ArrangementNodeComponent component : myComponents) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java index 52e471940d0f..1d61feb130d2 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementAtomNodeComponent.java @@ -169,6 +169,11 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent { myScreenBounds = screenBounds; } + @Override + public boolean onCanvasWidthChange(int width) { + return false; + } + @Override public ArrangementNodeComponent getNodeComponentAt(@NotNull RelativePoint point) { return (myScreenBounds != null && myScreenBounds.contains(point.getScreenPoint())) ? this : null; diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementGroupingNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementGroupingNodeComponent.java index 3d57752a1d0c..27a39f1e3257 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementGroupingNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementGroupingNodeComponent.java @@ -34,10 +34,14 @@ import java.awt.event.MouseEvent; * @since 9/12/12 5:39 PM */ public class ArrangementGroupingNodeComponent extends JPanel implements ArrangementNodeComponent { - + + private static final int TOP_INSET = 3; + @NotNull private final ArrangementColorsService myColorsService = ServiceManager.getService(ArrangementColorsService.class); @NotNull private final ArrangementAtomMatchCondition myCondition; + @Nullable private Rectangle myScreenBounds; + @NotNull private Dimension myPreferredSize; private boolean mySelected; public ArrangementGroupingNodeComponent(@NotNull ArrangementNodeDisplayManager manager, @@ -46,9 +50,9 @@ public class ArrangementGroupingNodeComponent extends JPanel implements Arrangem myCondition = condition; String text = StringUtil.capitalize(StringUtil.pluralize(manager.getDisplayValue(myCondition.getValue()))); setLayout(new GridBagLayout()); - add(new JLabel(String.format("%s", text)), new GridBag().anchor(GridBagConstraints.CENTER).weightx(1).insets(0, 12, 0, 0)); - Dimension size = getPreferredSize(); - setPreferredSize(new Dimension(manager.getMaxGroupTextWidth() * 5, size.height * 2)); + GridBag constraints = new GridBag().anchor(GridBagConstraints.WEST).weightx(1).insets(TOP_INSET * 2, 20, 0, 0); + add(new JLabel(String.format("%s", text)), constraints); + myPreferredSize = super.getPreferredSize(); } @NotNull @@ -80,6 +84,21 @@ public class ArrangementGroupingNodeComponent extends JPanel implements Arrangem myScreenBounds = bounds; } + @Override + public boolean onCanvasWidthChange(int width) { + if (width > 0 && myPreferredSize.width != width) { + myPreferredSize = new Dimension(width - UIUtil.getTreeLeftChildIndent(), myPreferredSize.height); + return true; + } + return false; + } + + @NotNull + @Override + public Dimension getPreferredSize() { + return myPreferredSize; + } + @Override public void setSelected(boolean selected) { mySelected = selected; @@ -101,7 +120,7 @@ public class ArrangementGroupingNodeComponent extends JPanel implements Arrangem Rectangle bounds = getBounds(); g.setColor(UIManager.getColor("Tree.hash")); int cornerX = UIUtil.getTreeLeftChildIndent(); - int y = 3; + int y = TOP_INSET; g.drawLine(cornerX, y, bounds.width, y); g.drawLine(cornerX, y, cornerX, y + bounds.height); if (mySelected) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java index 994ac5a5b54c..fd4a9536084d 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementNodeComponent.java @@ -49,6 +49,17 @@ public interface ArrangementNodeComponent { void setScreenBounds(@Nullable Rectangle bounds); + /** + * Notifies current component that canvas (container where current component is painted) width has been changed. + *

+ * The intended usage is to allow component to draw something up to/at the right screen size. + * + * @param width new canvas width + * @return true if current component's representation has been changed; + * false otherwise + */ + boolean onCanvasWidthChange(int width); + /** * Instructs current component that it should {@link #getUiComponent() draw} itself according to the given 'selected' state. * diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java index e440966a1ddc..fee3ff8ac975 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementRuleTree.java @@ -74,6 +74,7 @@ public class ArrangementRuleTree { @NotNull private final ArrangementNodeComponentFactory myFactory; @NotNull private final List> myGroupingRules; + private int myCanvasWidth; private boolean myExplicitSelectionChange; private boolean mySkipSelectionChange; @@ -199,6 +200,35 @@ public class ArrangementRuleTree { } } + public void updateCanvasWidth(final int width) { + myCanvasWidth = width; + myRenderers.forEachKey(new TIntProcedure() { + @Override + public boolean execute(int row) { + doUpdateCanvasWidth(row); + return true; + } + }); + } + + private void doUpdateCanvasWidth(int row) { + if (myCanvasWidth <= 0) { + return; + } + ArrangementNodeComponent component = myRenderers.get(row); + if (component == null) { + return; + } + if (!component.onCanvasWidthChange(myCanvasWidth)) { + return; + } + + TreePath path = myTree.getPathForRow(row); + if (path != null) { + myTreeModel.nodeChanged((TreeNode)path.getLastPathComponent()); + } + } + private void selectPreviousRule() { ArrangementTreeNode currentSelectionBottom = getCurrentSelectionBottom(); @@ -342,7 +372,7 @@ public class ArrangementRuleTree { @NotNull public List getActiveModels() { TreePath[] paths = mySelectionModel.getSelectionPaths(); - if (paths == null || paths.length != 1) { + if (paths == null) { return Collections.emptyList(); } @@ -432,6 +462,7 @@ public class ArrangementRuleTree { ArrangementNodeComponent result = myRenderers.get(row); if (result == null || !result.getMatchCondition().equals(condition)) { myRenderers.put(row, result = myFactory.getComponent(condition, model)); + doUpdateCanvasWidth(row); } return result; } @@ -619,7 +650,9 @@ public class ArrangementRuleTree { } if (row < 0) { - return myFactory.getComponent(node, null).getUiComponent(); + ArrangementNodeComponent component = myFactory.getComponent(node, null); + doUpdateCanvasWidth(row); + return component.getUiComponent(); } ArrangementNodeComponent component = getNodeComponentAt(row, node, myModels.get(row)); component.setSelected(selected); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java index 4f8beb3cffe1..a9592c75f597 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java @@ -118,8 +118,29 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { setupKeyboardActions(actionManager, treeComponent); setupScrollingHelper(treeComponent, scrollPane, editorPane); + setupCanvasWidthUpdater(scrollPane); } + private void setupCanvasWidthUpdater(@NotNull JBScrollPane scrollPane) { + final JViewport viewport = scrollPane.getViewport(); + viewport.addChangeListener(new ChangeListener() { + + private int myWidth; + + @Override + public void stateChanged(ChangeEvent e) { + Rectangle visibleRect = viewport.getVisibleRect(); + if (visibleRect == null || visibleRect.width <= 0) { + return; + } + if (myWidth != visibleRect.width) { + myWidth = visibleRect.width; + myRuleTree.updateCanvasWidth(myWidth); + } + } + }); + } + /** * The general idea is to configure UI in a way that it automatically changes tree viewport 'y' coordinate in order to make * target rule visible on rule editor opening. diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index e07a62dfcbd3..0800964fc35c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -100,7 +100,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private final FileStatusMap myFileStatusMap; private DaemonCodeAnalyzerSettings myLastSettings; - private IntentionHintComponent myLastIntentionHint; //guarded by this + private volatile IntentionHintComponent myLastIntentionHint; private volatile boolean myDisposed; // the only possible transition: false -> true private volatile boolean myInitialized; // the only possible transition: false -> true @@ -109,7 +109,6 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx @NonNls private static final String URL_ATT = "url"; private DaemonListeners myDaemonListeners; private final PassExecutorService myPassExecutorService; - private int myModificationCount = 0; private volatile boolean allowToInterrupt = true; private StatusBarUpdater myStatusBarUpdater; @@ -456,7 +455,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @NotNull - public List getPassesToShowProgressFor(Document document) { + List getPassesToShowProgressFor(Document document) { List allPasses = myPassExecutorService.getAllSubmittedPasses(); List result = new ArrayList(allPasses.size()); for (TextEditorHighlightingPass pass : allPasses) { @@ -467,7 +466,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return result; } - public boolean isAllAnalysisFinished(@NotNull PsiFile file) { + boolean isAllAnalysisFinished(@NotNull PsiFile file) { if (myDisposed) return false; Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file); return document != null && @@ -488,11 +487,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myFileStatusMap; } - public synchronized int getModificationCount() { - return myModificationCount; - } - - public synchronized boolean isRunning() { + synchronized boolean isRunning() { return myUpdateProgress != null && !myUpdateProgress.isCanceled(); } @@ -509,7 +504,6 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private synchronized void cancelUpdateProgress(final boolean start, @NonNls String reason) { PassExecutorService.log(myUpdateProgress, null, reason, start); - myModificationCount++; if (myUpdateProgress != null) { myUpdateProgress.cancel(); @@ -541,12 +535,12 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx }); } - public static boolean processHighlightsOverlappingOutside(@NotNull Document document, - @NotNull Project project, - @Nullable("null means all") final HighlightSeverity minSeverity, - final int startOffset, - final int endOffset, - @NotNull final Processor processor) { + static boolean processHighlightsOverlappingOutside(@NotNull Document document, + @NotNull Project project, + @Nullable("null means all") final HighlightSeverity minSeverity, + final int startOffset, + final int endOffset, + @NotNull final Processor processor) { LOG.assertTrue(ApplicationManager.getApplication().isReadAccessAllowed()); final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project); @@ -634,13 +628,17 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return markup.getUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY); } - public static void setLineMarkers(@NotNull Document document, List lineMarkers, Project project) { + static void setLineMarkers(@NotNull Document document, List lineMarkers, Project project) { ApplicationManager.getApplication().assertIsDispatchThread(); MarkupModel markup = DocumentMarkupModel.forDocument(document, project, true); markup.putUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY, lineMarkers); } - public synchronized void setLastIntentionHint(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor, @NotNull ShowIntentionsPass.IntentionsInfo intentions, boolean hasToRecreate) { + void setLastIntentionHint(@NotNull Project project, + @NotNull PsiFile file, + @NotNull Editor editor, + @NotNull ShowIntentionsPass.IntentionsInfo intentions, + boolean hasToRecreate) { ApplicationManager.getApplication().assertIsDispatchThread(); hideLastIntentionHint(); IntentionHintComponent hintComponent = IntentionHintComponent.showIntentionHint(project, file, editor, intentions, false); @@ -650,15 +648,17 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myLastIntentionHint = hintComponent; } - public synchronized void hideLastIntentionHint() { - if (myLastIntentionHint != null && myLastIntentionHint.isVisible()) { - myLastIntentionHint.hide(); + void hideLastIntentionHint() { + ApplicationManager.getApplication().assertIsDispatchThread(); + IntentionHintComponent hint = myLastIntentionHint; + if (hint != null && hint.isVisible()) { + hint.hide(); myLastIntentionHint = null; } } @Nullable - public synchronized IntentionHintComponent getLastIntentionHint() { + IntentionHintComponent getLastIntentionHint() { return myLastIntentionHint; } @@ -715,7 +715,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx Runnable runnable = new Runnable() { @Override public void run() { - PassExecutorService.log(myUpdateProgress, null, "Update Runnable. myUpdateByTimerEnabled:",myUpdateByTimerEnabled," something disposed:",PowerSaveMode.isEnabled() || myDisposed || !myProject.isInitialized()," activeEditors:",myProject.isDisposed() ? null : myDaemonListeners.getSelectedEditors()); + PassExecutorService.log(getUpdateProgress(), null, "Update Runnable. myUpdateByTimerEnabled:",myUpdateByTimerEnabled," something disposed:",PowerSaveMode.isEnabled() || myDisposed || !myProject.isInitialized()," activeEditors:",myProject.isDisposed() ? null : myDaemonListeners.getSelectedEditors()); if (!myUpdateByTimerEnabled) return; if (myDisposed) return; ApplicationManager.getApplication().assertIsDispatchThread(); @@ -786,6 +786,10 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + synchronized DaemonProgressIndicator getUpdateProgress() { + return myUpdateProgress; + } + @NotNull @TestOnly public static List getFileLevelHighlights(@NotNull Project project, @NotNull PsiFile file ) { @@ -796,9 +800,4 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx public void allowToInterrupt(boolean can) { allowToInterrupt = can; } - - @TestOnly - public synchronized DaemonProgressIndicator getUpdateProgress() { - return myUpdateProgress; - } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index 5480d1a4b3f1..edbc4a2e5557 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -181,7 +181,12 @@ class DaemonListeners implements Disposable { @Override public void editorReleased(@NotNull EditorFactoryEvent event) { // mem leak after closing last editor otherwise - myDaemonCodeAnalyzer.hideLastIntentionHint(); + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + myDaemonCodeAnalyzer.hideLastIntentionHint(); + } + }); } }; EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, this); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java index e79cf9ac57c8..5b9a6beb7f56 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolRegistrar.java @@ -131,47 +131,45 @@ public class InspectionToolRegistrar { } } - /* - private void printExtension(Class aClass, InspectionTool tool) { - StringBuilder builder = new StringBuilder(tool instanceof GlobalInspectionToolWrapper ? ""); - System.out.println(builder); - } - */ + //private static void printExtension(Class aClass, InspectionTool tool) { + // StringBuilder builder = new StringBuilder(tool instanceof GlobalInspectionToolWrapper ? ""); + // System.out.println(builder); + //} private Factory registerInspectionTool(final Class aClass, boolean store) { if (LocalInspectionTool.class.isAssignableFrom(aClass)) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java index d8e22b466e46..38f413544a85 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java @@ -27,7 +27,6 @@ import com.intellij.openapi.util.WriteExternalException; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.net.URL; @@ -194,11 +193,6 @@ public abstract class InspectionToolWrapper - + @@ -56,7 +56,7 @@ - + diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 4b368a4fa702..94d22879706f 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -1512,7 +1512,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } @Override - public void addChangeListener(final ChangeListener listener, final Disposable parent) { + public void addChangeListener(@NotNull final ChangeListener listener, @NotNull final Disposable parent) { myListeners.add(listener); Disposer.register(parent, new Disposable() { @Override diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java index 5485a8aecd99..758af6d73e55 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java @@ -105,7 +105,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple final ModifiableModel model = SingleInspectionProfilePanel.createNewProfile(-1, getSelectedObject(), myWholePanel, "", existingProfileNames); if (model != null) { addProfile((InspectionProfileImpl)model); - myDeletedProfiles.remove(model.getName()); + myDeletedProfiles.remove(getProfilePrefix(model) + model.getName()); myDeleteButton.setEnabled(true); } } @@ -115,7 +115,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple public void actionPerformed(ActionEvent e) { final InspectionProfileImpl selectedProfile = (InspectionProfileImpl)myProfiles.getSelectedItem(); ((DefaultComboBoxModel)myProfiles.getModel()).removeElement(selectedProfile); - myDeletedProfiles.add(selectedProfile.getName()); + myDeletedProfiles.add(getProfilePrefix(selectedProfile) + selectedProfile.getName()); myDeleteButton.setEnabled(isDeleteEnabled(selectedProfile)); } }); @@ -177,7 +177,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple if (Messages.showOkCancelDialog(myWholePanel, "Profile with name \'" + profile.getName() + "\' already exists. Do you want to overwrite it?", "Warning", Messages.getInformationIcon()) != DialogWrapper.OK_EXIT_CODE) return; } addProfile((InspectionProfileImpl)profile.getModifiableModel()); - myDeletedProfiles.remove(profile.getName()); + myDeletedProfiles.remove(getProfilePrefix(profile) + profile.getName()); myDeleteButton.setEnabled(true); } catch (InvalidDataException e1) { @@ -228,7 +228,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple final InspectionProfileImpl modifiableModel = (InspectionProfileImpl)model.getModifiableModel(); modifiableModel.setModified(true); addProfile(modifiableModel); - myDeletedProfiles.remove(model.getName()); + myDeletedProfiles.remove(getProfilePrefix(model) + model.getName()); myDeleteButton.setEnabled(true); } } @@ -244,7 +244,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple final String modelName = model.getName(); final SingleInspectionProfilePanel panel = new SingleInspectionProfilePanel(myProjectProfileManager, modelName, model); myPanel.add(modelName, panel); - if (!myPanels.containsKey(modelName)) { + if (!myPanels.containsKey(getProfilePrefix(model) + modelName)) { ((DefaultComboBoxModel)myProfiles.getModel()).addElement(model); } putProfile(model, panel); @@ -323,7 +323,8 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple final Map panels = new LinkedHashMap(); for (final String name : myPanels.keySet()) { if (myDeletedProfiles.remove(name)) { - deleteProfile(name); + final String profileName = getProfilePanel(name).getSelectedProfile().getName(); + deleteProfile(profileName); } else { final SingleInspectionProfilePanel panel = getProfilePanel(name); diff --git a/platform/lang-impl/src/com/intellij/tools/Tool.java b/platform/lang-impl/src/com/intellij/tools/Tool.java index 3c9db88ee02e..2848c547a936 100644 --- a/platform/lang-impl/src/com/intellij/tools/Tool.java +++ b/platform/lang-impl/src/com/intellij/tools/Tool.java @@ -52,6 +52,8 @@ public class Tool implements SchemeElement { private boolean myEnabled; private boolean myUseConsole; + private boolean myShowConsoleOnStdOut; + private boolean myShowConsoleOnStdErr; private boolean mySynchronizeAfterExecution; private String myWorkingDirectory; @@ -103,6 +105,14 @@ public class Tool implements SchemeElement { return myUseConsole; } + public boolean isShowConsoleOnStdOut() { + return myShowConsoleOnStdOut; + } + + public boolean isShowConsoleOnStdErr() { + return myShowConsoleOnStdErr; + } + public boolean synchronizeAfterExecution() { return mySynchronizeAfterExecution; } @@ -139,6 +149,14 @@ public class Tool implements SchemeElement { myUseConsole = useConsole; } + void setShowConsoleOnStdOut(boolean showConsole) { + myShowConsoleOnStdOut = showConsole; + } + + void setShowConsoleOnStdErr(boolean showConsole) { + myShowConsoleOnStdErr = showConsole; + } + public void setFilesSynchronizedAfterRun(boolean synchronizeAfterRun) { mySynchronizeAfterExecution = synchronizeAfterRun; } @@ -192,6 +210,8 @@ public class Tool implements SchemeElement { myShownInSearchResultsPopup = source.myShownInSearchResultsPopup; myEnabled = source.myEnabled; myUseConsole = source.myUseConsole; + myShowConsoleOnStdOut = source.myShowConsoleOnStdOut; + myShowConsoleOnStdErr = source.myShowConsoleOnStdErr; mySynchronizeAfterExecution = source.mySynchronizeAfterExecution; myWorkingDirectory = source.myWorkingDirectory; myProgram = source.myProgram; @@ -215,6 +235,8 @@ public class Tool implements SchemeElement { myShownInSearchResultsPopup == source.myShownInSearchResultsPopup && myEnabled == source.myEnabled && myUseConsole == source.myUseConsole && + myShowConsoleOnStdOut == source.myShowConsoleOnStdOut && + myShowConsoleOnStdErr == source.myShowConsoleOnStdErr && mySynchronizeAfterExecution == source.mySynchronizeAfterExecution && Comparing.equal(myWorkingDirectory, source.myWorkingDirectory) && Comparing.equal(myProgram, source.myProgram) && diff --git a/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java b/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java index 35905c7b2688..98b4302c3b07 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolEditorDialog.java @@ -16,6 +16,7 @@ package com.intellij.tools; +import com.intellij.execution.ExecutionBundle; import com.intellij.ide.DataManager; import com.intellij.ide.macro.MacroManager; import com.intellij.ide.macro.MacrosDialog; @@ -36,8 +37,11 @@ import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.IdeBorderFactory; import com.intellij.util.Consumer; +import net.miginfocom.swing.MigLayout; import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.text.BadLocationException; import java.awt.*; @@ -55,6 +59,8 @@ public class ToolEditorDialog extends DialogWrapper { private final JCheckBox myShowInProjectTreeCheckbox = new JCheckBox(ToolsBundle.message("tools.menu.project.checkbox")); private final JCheckBox myShowInSearchResultsPopupCheckbox = new JCheckBox(ToolsBundle.message("tools.menu.search.checkbox")); private final JCheckBox myUseConsoleCheckbox = new JCheckBox(ToolsBundle.message("tools.open.console.checkbox")); + private final JCheckBox myShowConsoleOnStdOutCheckbox = new JCheckBox(ExecutionBundle.message("logs.show.console.on.stdout")); + private final JCheckBox myShowConsoleOnStdErrCheckbox = new JCheckBox(ExecutionBundle.message("logs.show.console.on.stderr")); private final JCheckBox mySynchronizedAfterRunCheckbox = new JCheckBox(ToolsBundle.message("tools.synchronize.files.checkbox")); private boolean myEnabled; @@ -179,6 +185,8 @@ public class ToolEditorDialog extends DialogWrapper { setTitle(ToolsBundle.message("tools.edit.title")); init(); addListeners(); + myShowConsoleOnStdOutCheckbox.setVisible(false); + myShowConsoleOnStdErrCheckbox.setVisible(false); } private JPanel createCommandPane() { @@ -375,6 +383,14 @@ public class ToolEditorDialog extends DialogWrapper { handleOKButton(); } }); + + myUseConsoleCheckbox.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + myShowConsoleOnStdOutCheckbox.setVisible(myUseConsoleCheckbox.isSelected()); + myShowConsoleOnStdErrCheckbox.setVisible(myUseConsoleCheckbox.isSelected()); + } + }); } private void handleOKButton() { @@ -392,6 +408,8 @@ public class ToolEditorDialog extends DialogWrapper { tool.setShownInProjectViews(myShowInProjectTreeCheckbox.isSelected()); tool.setShownInSearchResultsPopup(myShowInSearchResultsPopupCheckbox.isSelected()); tool.setUseConsole(myUseConsoleCheckbox.isSelected()); + tool.setShowConsoleOnStdOut(myShowConsoleOnStdOutCheckbox.isSelected()); + tool.setShowConsoleOnStdErr(myShowConsoleOnStdErrCheckbox.isSelected()); tool.setFilesSynchronizedAfterRun(mySynchronizedAfterRunCheckbox.isSelected()); tool.setEnabled(myEnabled); @@ -428,6 +446,8 @@ public class ToolEditorDialog extends DialogWrapper { myShowInProjectTreeCheckbox.setSelected(tool.isShownInProjectViews()); myShowInSearchResultsPopupCheckbox.setSelected(tool.isShownInSearchResultsPopup()); myUseConsoleCheckbox.setSelected(tool.isUseConsole()); + myShowConsoleOnStdOutCheckbox.setSelected(tool.isShowConsoleOnStdOut()); + myShowConsoleOnStdErrCheckbox.setSelected(tool.isShowConsoleOnStdErr()); mySynchronizedAfterRunCheckbox.setSelected(tool.synchronizeAfterExecution()); myEnabled = tool.isEnabled(); myTfCommandWorkingDirectory.setText(toCurrentSystemFormat(tool.getWorkingDirectory())); @@ -453,11 +473,13 @@ public class ToolEditorDialog extends DialogWrapper { } private JPanel getOptionsPanel() { - JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0)); + JPanel panel = new JPanel(new MigLayout("fill, gap 10")); panel.setBorder(IdeBorderFactory.createTitledBorder(ToolsBundle.message("tools.options.group"), true)); panel.add(mySynchronizedAfterRunCheckbox); panel.add(myUseConsoleCheckbox); - panel.add(myOutputFiltersButton); + panel.add(myOutputFiltersButton, "ax right, wrap"); + panel.add(myShowConsoleOnStdOutCheckbox); + panel.add(myShowConsoleOnStdErrCheckbox, "spanx 2"); return panel; } diff --git a/platform/lang-impl/src/com/intellij/tools/ToolRunProfile.java b/platform/lang-impl/src/com/intellij/tools/ToolRunProfile.java index a257e0683989..08637f5fdc9f 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolRunProfile.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolRunProfile.java @@ -16,21 +16,20 @@ package com.intellij.tools; import com.intellij.execution.ExecutionException; +import com.intellij.execution.ExecutionManager; import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; import com.intellij.execution.filters.RegexpFilter; import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilderFactory; -import com.intellij.execution.process.ColoredProcessHandler; -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.process.ProcessTerminatedListener; +import com.intellij.execution.process.*; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -89,11 +88,21 @@ public class ToolRunProfile implements ModuleRunProfile{ return processHandler; } + @NotNull public ExecutionResult execute(@NotNull final Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { final ExecutionResult result = super.execute(executor, runner); final ProcessHandler processHandler = result.getProcessHandler(); if (processHandler != null) { processHandler.addProcessListener(new ToolProcessAdapter(project, myTool.synchronizeAfterExecution(), getName())); + processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void onTextAvailable(ProcessEvent event, Key outputType) { + if ((outputType == ProcessOutputTypes.STDOUT && myTool.isShowConsoleOnStdOut()) + || (outputType == ProcessOutputTypes.STDERR && myTool.isShowConsoleOnStdErr())) { + ExecutionManager.getInstance(project).getContentManager().toFrontRunContent(executor, processHandler); + } + } + }); } return result; } diff --git a/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java b/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java index 9a921d63c8a5..83aa9f30d07c 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java @@ -42,6 +42,8 @@ class ToolsProcessor extends BaseSchemeProcessor { @NonNls private static final String SHOW_IN_SEARCH_POPUP = "showInSearchPopup"; @NonNls private static final String DISABLED = "disabled"; @NonNls private static final String USE_CONSOLE = "useConsole"; + @NonNls private static final String SHOW_CONSOLE_ON_STDOUT = "showConsoleOnStdOut"; + @NonNls private static final String SHOW_CONSOLE_ON_STDERR = "showConsoleOnStdErr"; @NonNls private static final String SYNCHRONIZE_AFTER_EXECUTION = "synchronizeAfterRun"; @NonNls private static final String EXEC = "exec"; @NonNls private static final String WORKING_DIRECTORY = "WORKING_DIRECTORY"; @@ -76,6 +78,8 @@ class ToolsProcessor extends BaseSchemeProcessor { tool.setShownInSearchResultsPopup(Boolean.valueOf(element.getAttributeValue(SHOW_IN_SEARCH_POPUP)).booleanValue()); tool.setEnabled(!Boolean.valueOf(element.getAttributeValue(DISABLED)).booleanValue()); tool.setUseConsole(Boolean.valueOf(element.getAttributeValue(USE_CONSOLE)).booleanValue()); + tool.setShowConsoleOnStdOut(Boolean.valueOf(element.getAttributeValue(SHOW_CONSOLE_ON_STDOUT)).booleanValue()); + tool.setShowConsoleOnStdErr(Boolean.valueOf(element.getAttributeValue(SHOW_CONSOLE_ON_STDERR)).booleanValue()); tool.setFilesSynchronizedAfterRun(Boolean.valueOf(element.getAttributeValue(SYNCHRONIZE_AFTER_EXECUTION)).booleanValue()); Element exec = element.getChild(EXEC); @@ -150,6 +154,8 @@ class ToolsProcessor extends BaseSchemeProcessor { element.setAttribute(SHOW_IN_SEARCH_POPUP, Boolean.toString(tool.isShownInSearchResultsPopup())); element.setAttribute(DISABLED, Boolean.toString(!tool.isEnabled())); element.setAttribute(USE_CONSOLE, Boolean.toString(tool.isUseConsole())); + element.setAttribute(SHOW_CONSOLE_ON_STDOUT, Boolean.toString(tool.isShowConsoleOnStdOut())); + element.setAttribute(SHOW_CONSOLE_ON_STDERR, Boolean.toString(tool.isShowConsoleOnStdErr())); element.setAttribute(SYNCHRONIZE_AFTER_EXECUTION, Boolean.toString(tool.synchronizeAfterExecution())); Element taskElement = new Element(EXEC); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index 6e0c230da31d..ff8b4b37f30a 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -3834,11 +3834,11 @@ public class AbstractTreeUi { } } - Set toSelect = new THashSet(); clearSelection(); - ContainerUtil.addAll(toSelect, elements); + Set toSelect = new THashSet(); + ContainerUtil.addAllNotNull(toSelect, elements); if (addToSelection) { - toSelect.addAll(currentElements); + ContainerUtil.addAllNotNull(toSelect, currentElements); } if (checkIfInStructure) { diff --git a/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java b/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java index 0fc4f7d49f52..77ef876b8501 100644 --- a/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java +++ b/platform/platform-api/src/com/intellij/openapi/util/DimensionService.java @@ -20,6 +20,7 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; import com.intellij.ui.ScreenUtil; import gnu.trove.TObjectIntHashMap; @@ -263,8 +264,19 @@ public class DimensionService implements PersistentStateComponent, Appl private static String realKey(String key, @Nullable Project project) { if (project == null) return key; - final JFrame frame = WindowManager.getInstance().getFrame(project); - if (frame == null) return key; //during frame initialization + JFrame frame = WindowManager.getInstance().getFrame(project); + if (frame == null) { + final IdeFrame[] frames = WindowManager.getInstance().getAllFrames(); + for (IdeFrame ideFrame : frames) { + if (ideFrame instanceof JFrame) { + frame = (JFrame)ideFrame; + break; + } + } + if (frame == null) { + return key; //during frame initialization + } + } final Point topLeft = frame.getLocation(); Point center = new Point(topLeft.x + frame.getWidth() / 2, topLeft.y + frame.getHeight() / 2); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula.properties index 09b69c0c08ae..1c9fe32465ba 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula.properties @@ -65,7 +65,7 @@ StatusBar.bottomColor=2c2c2c Button.foreground=eeeeee Button.background=535353 Button.border=com.intellij.ide.ui.laf.borders.DarculaButtonPainter -ButtonUI=com.intellij.ide.ui.laf.borders.DarculaButtonUI +#ButtonUI=com.intellij.ide.ui.laf.borders.DarculaButtonUI MenuItem.acceleratorForeground=eeeeee PopupMenu.background=535353 diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula_windows.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula_windows.properties index 93cb21e38ec8..75eb2305015a 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula_windows.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula_windows.properties @@ -1,12 +1,6 @@ -Button.background=606060 -Button.foreground=cccccc - -ComboBox.background=606060 -ComboBox.foreground=cccccc +ButtonUI=com.intellij.ide.ui.laf.borders.DarculaButtonUI Tree.line=909090 Tree.hash=909090 Tree.collapsedIcon=AllIcons.Darcula.TreeNodeCollapsed -Tree.expandedIcon=AllIcons.Darcula.TreeNodeExpanded - -Menu.selectionBackground=526CA4 +Tree.expandedIcon=AllIcons.Darcula.TreeNodeExpanded \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties index f2b6b490fbd1..ae8c13d27778 100644 --- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties +++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties @@ -286,6 +286,8 @@ run.configuration.error.no.jdk.specified=No JDK specified run.configuration.cannot.find.vm.executable=Cannot find VM executable logs.tab.title=Logs +logs.show.console.on.stdout=Show console when standard out changes +logs.show.console.on.stderr=Show console when standard error changes before.launch.panel.title=Before launch before.launch.panel.empty=There are no tasks to run before launch before.launch.panel.cyclic_dependency_warning=''{0}'' has already configured to be launched before {1}.\nSuch cyclic dependencies are not allowed. diff --git a/platform/platform-resources/src/idea/Keymap_Xcode.xml b/platform/platform-resources/src/idea/Keymap_Xcode.xml index 7353ec503e42..0ae26438b406 100644 --- a/platform/platform-resources/src/idea/Keymap_Xcode.xml +++ b/platform/platform-resources/src/idea/Keymap_Xcode.xml @@ -29,6 +29,10 @@ + + + + @@ -51,9 +55,9 @@ + - @@ -164,9 +168,9 @@ + - @@ -288,12 +292,12 @@ + - + - @@ -313,8 +317,8 @@ + - diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/BaseTestsOutputConsoleView.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/BaseTestsOutputConsoleView.java index e929f62670ed..753528386c8b 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/BaseTestsOutputConsoleView.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/BaseTestsOutputConsoleView.java @@ -133,7 +133,7 @@ public abstract class BaseTestsOutputConsoleView implements ConsoleView, Observa myConsole = null; } - public void addChangeListener(final ChangeListener listener, final Disposable parent) { + public void addChangeListener(@NotNull final ChangeListener listener, @NotNull final Disposable parent) { if (myConsole instanceof ObservableConsoleView) { ((ObservableConsoleView)myConsole).addChangeListener(listener, parent); } else { diff --git a/platform/util-rt/src/com/intellij/BundleBase.java b/platform/util-rt/src/com/intellij/BundleBase.java index 566be37adda1..beb1e83227ee 100644 --- a/platform/util-rt/src/com/intellij/BundleBase.java +++ b/platform/util-rt/src/com/intellij/BundleBase.java @@ -67,7 +67,10 @@ public abstract class BundleBase { return messageOrDefault(bundle, key, null, params); } - public static String replaceMnemonicAmpersand(final String value) { + @Nullable + public static String replaceMnemonicAmpersand(@Nullable final String value) { + if (value == null) + return null; if (value.indexOf('&') >= 0) { boolean useMacMnemonic = value.contains("&&"); StringBuilder realValue = new StringBuilder(); diff --git a/platform/util/src/com/intellij/util/CommonProcessors.java b/platform/util/src/com/intellij/util/CommonProcessors.java index 0d0a6033b235..794d72624614 100644 --- a/platform/util/src/com/intellij/util/CommonProcessors.java +++ b/platform/util/src/com/intellij/util/CommonProcessors.java @@ -18,6 +18,7 @@ package com.intellij.util; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -123,6 +124,7 @@ public class CommonProcessors { return myValue != null; } + @Nullable public T getFoundValue() { return myValue; } diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index f478a58f624b..949a89880e57 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -467,6 +467,25 @@ public class ContainerUtil extends ContainerUtilRt { } } + /** + * Adds all not-null elements from the {@code elements}, ignoring nulls + */ + public static void addAllNotNull(@NotNull Collection collection, @NotNull Iterable elements) { + addAll(collection, elements.iterator()); + } + + /** + * Adds all not-null elements from the {@code elements}, ignoring nulls + */ + public static void addAllNotNull(@NotNull Collection collection, @NotNull Iterator elements) { + while (elements.hasNext()) { + T o = elements.next(); + if (o != null) { + collection.add(o); + } + } + } + @NotNull public static List collect(@NotNull Iterator iterator) { if (!iterator.hasNext()) return Collections.emptyList(); @@ -859,6 +878,19 @@ public class ContainerUtil extends ContainerUtilRt { return collection; } + /** + * Adds all not-null elements from the {@code elements}, ignoring nulls + */ + public static > C addAllNotNull(@NotNull C collection, @NotNull A... elements) { + //noinspection ManualArrayToCollectionCopy + for (T element : elements) { + if (element != null) { + collection.add(element); + } + } + return collection; + } + public static U findInstance(@NotNull Iterable iterable, @NotNull Class aClass) { return findInstance(iterable.iterator(), aClass); } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java index 08fca2be4fee..574897f83417 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java @@ -23,6 +23,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebugSessionAdapter; import com.intellij.xdebugger.XDebuggerBundle; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.EvaluationMode; @@ -54,6 +55,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { private EvaluationMode myMode; private final XSourcePosition mySourcePosition; private final SwitchModeAction mySwitchModeAction; + private final XDebugSessionAdapter mySessionListener; public XDebuggerEvaluationDialog(@NotNull XDebugSession session, final @NotNull XDebuggerEditorsProvider editorsProvider, @@ -68,6 +70,19 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { setOKButtonText(XDebuggerBundle.message("xdebugger.button.evaluate")); setCancelButtonText(XDebuggerBundle.message("xdebugger.evaluate.dialog.close")); + mySessionListener = new XDebugSessionAdapter() { + @Override + public void sessionStopped() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + close(CANCEL_EXIT_CODE); + } + }); + } + }; + mySession.addSessionListener(mySessionListener); + myTreePanel = new XDebuggerTreePanel(session, editorsProvider, myDisposable, sourcePosition, XDebuggerActions.EVALUATE_DIALOG_TREE_POPUP_GROUP); myResultPanel = new JPanel(new BorderLayout()); myResultPanel.add(new JLabel(XDebuggerBundle.message("xdebugger.evaluate.label.result")), BorderLayout.NORTH); @@ -101,6 +116,12 @@ public class XDebuggerEvaluationDialog extends DialogWrapper { init(); } + @Override + protected void dispose() { + mySession.removeSessionListener(mySessionListener); + super.dispose(); + } + protected void doOKAction() { evaluate(); } diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java index 866cb73e38fc..f55526e46eb3 100644 --- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java +++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.UsefulTestCase; import com.intellij.util.ui.UIUtil; @@ -71,11 +72,22 @@ public class XDebuggerTestUtil { XDebuggerUtil.getInstance().toggleLineBreakpoint(project, file, line); } - public static

void insertBreakpoint(final Project project, final P properties, final Class, P>> typeClass) { + public static

XBreakpoint

insertBreakpoint(final Project project, + final P properties, + final Class, P>> typeClass) { + return new WriteAction>() { + protected void run(final Result> result) { + result.setResult(XDebuggerManager.getInstance(project).getBreakpointManager() + .addBreakpoint((XBreakpointType, P>)XDebuggerUtil.getInstance().findBreakpointType(typeClass), + properties)); + } + }.execute().getResultObject(); + } + + public static void removeBreakpoint(final Project project, final XBreakpoint breakpoint) { new WriteAction() { protected void run(final Result result) { - XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); - breakpointManager.addBreakpoint((XBreakpointType,P>)XDebuggerUtil.getInstance().findBreakpointType(typeClass), properties); + XDebuggerManager.getInstance(project).getBreakpointManager().removeBreakpoint(breakpoint); } }.execute(); } @@ -267,6 +279,20 @@ public class XDebuggerTestUtil { UsefulTestCase.assertOrderedEquals(actualNames, expectedNames); } + public static void assertVariablesContain(List vars, String... names) throws InterruptedException { + List expectedNames = new ArrayList(Arrays.asList(names)); + + List actualNames = new ArrayList(); + for (XValue each : vars) { + actualNames.add(computePresentation(each).myName); + } + + expectedNames.removeAll(actualNames); + UsefulTestCase.assertTrue("Missing variables:" + StringUtil.join(expectedNames, ", ") + + "\nAll Variables: " + StringUtil.join(actualNames, ", "), + expectedNames.isEmpty()); + } + public static void assertSourcePosition(final XValue value, VirtualFile file, int offset) { final XTestNavigatable n = new XTestNavigatable(); ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -327,7 +353,7 @@ public class XDebuggerTestUtil { public static void removeAllBreakpoints(@NotNull final Project project) { final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); XBreakpoint[] breakpoints = breakpointManager.getAllBreakpoints(); - for (XBreakpoint b: breakpoints) { + for (XBreakpoint b : breakpoints) { breakpointManager.removeBreakpoint(b); } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java index 97706e7c02c6..040ac91af4cd 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ package com.siyeh.ig.cloneable; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.searches.SuperMethodsSearch; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; @@ -25,64 +27,64 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.CloneUtils; +import com.siyeh.ig.psiutils.MethodUtils; import org.jetbrains.annotations.NotNull; public class CloneDeclaresCloneNotSupportedInspection extends BaseInspection { + @Override @NotNull public String getID() { return "CloneDoesntDeclareCloneNotSupportedException"; } + @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "clone.doesnt.declare.clonenotsupportedexception.display.name"); + return InspectionGadgetsBundle.message("clone.doesnt.declare.clonenotsupportedexception.display.name"); } + @Override @NotNull public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "clone.doesnt.declare.clonenotsupportedexception.problem.descriptor"); + return InspectionGadgetsBundle.message("clone.doesnt.declare.clonenotsupportedexception.problem.descriptor"); } + @Override public boolean isEnabledByDefault() { return true; } + @Override public InspectionGadgetsFix buildFix(Object... infos) { return new CloneDeclaresCloneNotSupportedInspectionFix(); } - private static class CloneDeclaresCloneNotSupportedInspectionFix - extends InspectionGadgetsFix { + private static class CloneDeclaresCloneNotSupportedInspectionFix extends InspectionGadgetsFix { + @Override @NotNull public String getName() { - return InspectionGadgetsBundle.message( - "clone.doesnt.declare.clonenotsupportedexception.declare.quickfix"); + return InspectionGadgetsBundle.message("clone.doesnt.declare.clonenotsupportedexception.declare.quickfix"); } - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + @Override + public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiElement methodNameIdentifier = descriptor.getPsiElement(); - final PsiMethod method = - (PsiMethod)methodNameIdentifier.getParent(); - PsiUtil.addException(method, - "java.lang.CloneNotSupportedException"); + final PsiMethod method = (PsiMethod)methodNameIdentifier.getParent(); + PsiUtil.addException(method, "java.lang.CloneNotSupportedException"); } } + @Override public BaseInspectionVisitor buildVisitor() { return new CloneDeclaresCloneNotSupportedExceptionVisitor(); } - private static class CloneDeclaresCloneNotSupportedExceptionVisitor - extends BaseInspectionVisitor { + private static class CloneDeclaresCloneNotSupportedExceptionVisitor extends BaseInspectionVisitor { @Override public void visitMethod(@NotNull PsiMethod method) { - //note: no call to super; if (!CloneUtils.isClone(method)) { return; } @@ -96,30 +98,18 @@ public class CloneDeclaresCloneNotSupportedInspection extends BaseInspection { if (containingClass.hasModifierProperty(PsiModifier.FINAL)) { return; } - if (hasThrowsCloneNotSupportedException(method)) { + if (MethodUtils.hasInThrows(method, "java.lang.CloneNotSupportedException")) { return; } - final PsiMethod[] superMethods = method.findSuperMethods(); - if (superMethods.length < 1) { + final MethodSignatureBackedByPsiMethod signature = SuperMethodsSearch.search(method, null, true, false).findFirst(); + if (signature == null) { return; } - if (!hasThrowsCloneNotSupportedException(superMethods[0])) { + final PsiMethod superMethod = signature.getMethod(); + if (!MethodUtils.hasInThrows(superMethod, "java.lang.CloneNotSupportedException")) { return; } registerMethodError(method); } - - public static boolean hasThrowsCloneNotSupportedException( - @NotNull PsiMethod method) { - final PsiReferenceList throwsList = method.getThrowsList(); - final PsiClassType[] thrownTypes = throwsList.getReferencedTypes(); - for (final PsiClassType thrownType : thrownTypes) { - if (thrownType.equalsToText( - "java.lang.CloneNotSupportedException")) { - return true; - } - } - return false; - } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodUtils.java index 32ba59ab2796..248305f45281 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodUtils.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodUtils.java @@ -259,6 +259,9 @@ public class MethodUtils { } public static boolean hasInThrows(@NotNull PsiMethod method, @NotNull String... exceptions) { + if (exceptions.length == 0) { + throw new IllegalArgumentException("no exceptions specified"); + } final PsiReferenceList throwsList = method.getThrowsList(); final PsiJavaCodeReferenceElement[] references = throwsList.getReferenceElements(); for (PsiJavaCodeReferenceElement reference : references) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneDeclaresCloneNonSupportedExceptionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneDeclaresCloneNonSupportedExceptionInspection.java deleted file mode 100644 index 1635b005565e..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneDeclaresCloneNonSupportedExceptionInspection.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.siyeh.igtest.cloneable; - -public class CloneDeclaresCloneNonSupportedExceptionInspection implements Cloneable -{ - - public void foo() - { - - } - - public Object clone() - { - try - { - return super.clone(); - } - catch(CloneNotSupportedException e) - { - return null; - } - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_declares_clone_not_supported/CloneDeclaresCloneNonSupportedException.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_declares_clone_not_supported/CloneDeclaresCloneNonSupportedException.java new file mode 100644 index 000000000000..461fd61ca5d7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_declares_clone_not_supported/CloneDeclaresCloneNonSupportedException.java @@ -0,0 +1,36 @@ +package com.siyeh.igtest.cloneable.clone_declares_clone_not_supported; + +public class CloneDeclaresCloneNonSupportedException implements Cloneable +{ + + public void foo() + { + + } + + public Object clone() + { + try + { + return super.clone(); + } + catch(CloneNotSupportedException e) + { + return null; + } + } +} +class Normal implements Cloneable { + + @Override + protected Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} +class Child extends CloneDeclaresCloneNonSupportedException { + + @Override + public Object clone() { + return super.clone(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_declares_clone_not_supported/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_declares_clone_not_supported/expected.xml new file mode 100644 index 000000000000..017ae12ebb44 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_declares_clone_not_supported/expected.xml @@ -0,0 +1,9 @@ + + + + CloneDeclaresCloneNonSupportedException.java + 11 + 'clone()' does not declare 'CloneNotSupportedException' + <code>clone()</code> does not declare 'CloneNotSupportedException' + + \ No newline at end of file diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml index c72f0a8f607b..da7094e0ffa2 100644 --- a/plugins/android/src/META-INF/plugin.xml +++ b/plugins/android/src/META-INF/plugin.xml @@ -185,7 +185,81 @@ enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.android.inspections.AndroidNonConstantResIdsInSwitchInspection"/> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionToolProvider.java b/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionToolProvider.java index dca31689700c..5e1e4ac537a1 100644 --- a/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionToolProvider.java +++ b/plugins/android/src/org/jetbrains/android/inspections/lint/AndroidLintInspectionToolProvider.java @@ -4,7 +4,6 @@ import com.android.tools.lint.checks.*; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LintConstants; import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInspection.InspectionToolProvider; import com.intellij.psi.PsiElement; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.annotations.NotNull; @@ -12,95 +11,13 @@ import org.jetbrains.annotations.NotNull; /** * @author Eugene.Kudelevsky */ -public class AndroidLintInspectionToolProvider implements InspectionToolProvider { +public class AndroidLintInspectionToolProvider { /* Missing: DeprecationDetector, NamespaceDetector.TYPO, NamespaceDetector.UNUSED Also detectors based on CLASS_FILE scope are missing */ - @Override - public Class[] getInspectionClasses() { - return new Class[]{ - AndroidLintContentDescriptionInspection.class, - AndroidLintAdapterViewChildrenInspection.class, - AndroidLintScrollViewCountInspection.class, - AndroidLintMissingPrefixInspection.class, - AndroidLintDuplicateIdsInspection.class, - AndroidLintGridLayoutInspection.class, - AndroidLintHardcodedTextInspection.class, - AndroidLintInefficientWeightInspection.class, - AndroidLintNestedWeightsInspection.class, - AndroidLintDisableBaselineAlignmentInspection.class, - AndroidLintManifestOrderInspection.class, - AndroidLintMergeRootFrameInspection.class, - AndroidLintNestedScrollingInspection.class, - AndroidLintObsoleteLayoutParamInspection.class, - AndroidLintProguardInspection.class, - AndroidLintPxUsageInspection.class, - AndroidLintScrollViewSizeInspection.class, - AndroidLintExportedServiceInspection.class, - AndroidLintGrantAllUrisInspection.class, - AndroidLintStateListReachableInspection.class, - AndroidLintTextFieldsInspection.class, - AndroidLintTooManyViewsInspection.class, - AndroidLintTooDeepLayoutInspection.class, - AndroidLintTypographyDashesInspection.class, - AndroidLintTypographyQuotesInspection.class, - AndroidLintTypographyFractionsInspection.class, - AndroidLintTypographyEllipsisInspection.class, - AndroidLintTypographyOtherInspection.class, - AndroidLintUseCompoundDrawablesInspection.class, - AndroidLintUselessParentInspection.class, - AndroidLintUselessLeafInspection.class, - AndroidLintButtonOrderInspection.class, - AndroidLintBackButtonInspection.class, - AndroidLintButtonCaseInspection.class, - AndroidLintResourceAsColorInspection.class, - AndroidLintExtraTextInspection.class, - AndroidLintHardcodedDebugModeInspection.class, - AndroidLintDrawAllocationInspection.class, - AndroidLintSparseArrayInspection.class, - AndroidLintUseValueOfInspection.class, - AndroidLintLibraryCustomViewInspection.class, - AndroidLintPrivateResourceInspection.class, - AndroidLintSdCardPathInspection.class, - AndroidLintStyleCycleInspection.class, - AndroidLintTextViewEditsInspection.class, - AndroidLintEnforceUTF8Inspection.class, - AndroidLintUnknownIdInLayoutInspection.class, - AndroidLintSuspiciousImportInspection.class, - AndroidLintMultipleUsesSdkInspection.class, - AndroidLintUsesMinSdkAttributesInspection.class, - AndroidLintProguardSplitConfigInspection.class, - AndroidLintWorldWriteableFilesInspection.class, - - // batch-mode-only - AndroidLintInconsistentArraysInspection.class, - AndroidLintDuplicateIncludedIdsInspection.class, - AndroidLintIconExpectedSizeInspection.class, - AndroidLintIconDipSizeInspection.class, - AndroidLintIconLocationInspection.class, - AndroidLintIconDensitiesInspection.class, - AndroidLintIconMissingDensityFolderInspection.class, - AndroidLintGifUsageInspection.class, - AndroidLintIconDuplicatesInspection.class, - AndroidLintIconDuplicatesConfigInspection.class, - AndroidLintIconNoDpiInspection.class, - AndroidLintOverdrawInspection.class, - AndroidLintMissingTranslationInspection.class, - AndroidLintExtraTranslationInspection.class, - AndroidLintUnusedResourcesInspection.class, - AndroidLintUnusedIdsInspection.class, - AndroidLintAlwaysShowActionInspection.class, - AndroidLintStringFormatCountInspection.class, - AndroidLintStringFormatMatchesInspection.class, - AndroidLintStringFormatInvalidInspection.class, - AndroidLintWrongViewCastInspection.class, - AndroidLintUnknownIdInspection.class - }; - } - /** * Batch-mode-only inspections */ diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 075f1a5f4032..3a737880f10a 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -127,6 +127,7 @@ + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java index 6b9f4a2d19cc..457c98406cf0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppClosureParameterTypeProvider.java @@ -114,7 +114,7 @@ public class GppClosureParameterTypeProvider extends AbstractClosureParameterEnh } @Nullable - private static PsiType getSingleMethodParameterType(@Nullable PsiType type, int index, GrClosableBlock closure) { + public static PsiType getSingleMethodParameterType(@Nullable PsiType type, int index, GrClosableBlock closure) { final PsiType[] signature = findSingleAbstractMethodSignature(type); if (signature != null && GrClosureSignatureUtil.isSignatureApplicable(GrClosureSignatureUtil.createSignature(closure), signature, closure)) { return signature.length > index ? signature[index] : PsiType.NULL; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java index a3f84e14109c..d36faf97e26a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gpp/GppTypeConverter.java @@ -76,7 +76,7 @@ public class GppTypeConverter extends GrTypeConverter { return true; } } - else if (rType instanceof GrClosureType) { + else if (rType instanceof GrClosureType && hasTypedContext(context)) { final PsiType[] methodParameters = GppClosureParameterTypeProvider.findSingleAbstractMethodSignature(lType); if (isClosureOverride(methodParameters, (GrClosureType)rType, context)) return true; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java new file mode 100644 index 000000000000..6ebe35af596f --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/typeEnhancers/ClosureAsAnonymousParameterEnhancer.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.typeEnhancers; + +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.gpp.GppClosureParameterTypeProvider; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCastExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; +import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Max Medvedev + */ +public class ClosureAsAnonymousParameterEnhancer extends AbstractClosureParameterEnhancer { + @Nullable + @Override + protected PsiType getClosureParameterType(GrClosableBlock closure, int index) { + + Set expectedTypes; + + if (closure.getParent() instanceof GrSafeCastExpression) { + GrSafeCastExpression safeCastExpression = (GrSafeCastExpression)closure.getParent(); + GrTypeElement typeElement = safeCastExpression.getCastTypeElement(); + if (typeElement != null) { + PsiType castType = typeElement.getType(); + expectedTypes = new HashSet(GroovyExpectedTypesProvider.getDefaultExpectedTypes(safeCastExpression)); + PsiManager manager = closure.getManager(); + GlobalSearchScope scope = closure.getResolveScope(); + for (PsiType expected : expectedTypes) { + if (!TypesUtil.isAssignable(expected, castType, manager, scope)) { + expectedTypes.remove(expected); + } + } + + if (expectedTypes.isEmpty()) expectedTypes.add(castType); + } + else { + expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); + } + } + else { + expectedTypes = GroovyExpectedTypesProvider.getDefaultExpectedTypes(closure); + } + + for (PsiType constraint : expectedTypes) { + final PsiType suggestion = GppClosureParameterTypeProvider.getSingleMethodParameterType(constraint, index, closure); + if (suggestion != null) { + return suggestion; + } + } + + return null; + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy index 6dfb40b48c7d..f973bd3303ac 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy @@ -1452,6 +1452,25 @@ List foo() {[]} def (int x, String y) = foo() List foo() {[]} +''', GroovyAssignabilityCheckInspection) + } + + void testCastClosureToInterface() { + testHighlighting('''\ +interface Function { + F fun(D d) +} + +def foo(Function function) { + // print function.fun('abc') +} + + +foo({println it.byteValue()} as Function) +foo({println it.substring(1)} as Function) +foo({println it.substring(1)} as Function) +foo({println it}) + ''', GroovyAssignabilityCheckInspection) } diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java index d0342822db07..f38114009914 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolderImpl.java @@ -38,6 +38,16 @@ import java.util.List; public class DomElementAnnotationHolderImpl extends SmartList implements DomElementAnnotationHolder { private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.highlighting.DomElementAnnotationHolderImpl"); private final SmartList myAnnotations = new SmartList(); + private final boolean myOnTheFly; + + public DomElementAnnotationHolderImpl(boolean onTheFly) { + myOnTheFly = onTheFly; + } + + @Override + public boolean isOnTheFly() { + return myOnTheFly; + } @NotNull public DomElementProblemDescriptor createProblem(@NotNull DomElement domElement, @Nullable String message, LocalQuickFix... fixes) { @@ -104,7 +114,9 @@ public class DomElementAnnotationHolderImpl extends SmartList result = new SmartList(); final Converter converter = WrappingConverter.getDeepestConverter(element.getConverter(), element); if (converter instanceof ResolvingConverter) { diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java index 963afc1d2bec..9da5e8cd6dab 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManagerImpl.java @@ -235,13 +235,14 @@ public class DomElementAnnotationsManagerImpl extends DomElementAnnotationsManag @NotNull public List checkFileElement(@NotNull final DomFileElement domFileElement, - @NotNull final DomElementsInspection inspection) { + @NotNull final DomElementsInspection inspection, + boolean onTheFly) { final DomElementsProblemsHolder problemHolder = getProblemHolder(domFileElement); if (isHolderUpToDate(domFileElement) && problemHolder.isInspectionCompleted(inspection)) { return problemHolder.getAllProblems(inspection); } - final DomElementAnnotationHolder holder = new DomElementAnnotationHolderImpl(); + final DomElementAnnotationHolder holder = new DomElementAnnotationHolderImpl(onTheFly); inspection.checkFileElement(domFileElement, holder); return appendProblems(domFileElement, holder, inspection.getClass()); } diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java index c8b6eefe45eb..5e8614d4a0d0 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomHighlightingHelperImpl.java @@ -116,18 +116,10 @@ public class DomHighlightingHelperImpl extends DomHighlightingHelper { if (valueElement != null && !isSoftReference(element)) { final SmartList list = new SmartList(); final PsiReference[] psiReferences = myProvider.getReferencesByElement(valueElement, new ProcessingContext()); - GenericDomValueReference domReference = null; - for (final PsiReference reference : psiReferences) { - if (reference instanceof GenericDomValueReference) { - domReference = (GenericDomValueReference)reference; - break; - } - } + GenericDomValueReference domReference = ContainerUtil.findInstance(psiReferences, GenericDomValueReference.class); final Converter converter = WrappingConverter.getDeepestConverter(element.getConverter(), element); - final boolean domReferenceResolveOK = domReference != null && !hasBadResolve(domReference) - || domReference != null && converter instanceof ResolvingConverter && ((ResolvingConverter)converter).getAdditionalVariants(domReference.getConvertContext()).contains(element.getStringValue()); boolean hasBadResolve = false; - if (!domReferenceResolveOK) { + if (!(domReference != null && isDomResolveOK(element, domReference, converter))) { for (final PsiReference reference : psiReferences) { if (reference != domReference && hasBadResolve(reference)) { hasBadResolve = true; @@ -158,6 +150,11 @@ public class DomHighlightingHelperImpl extends DomHighlightingHelper { return Collections.emptyList(); } + private static boolean isDomResolveOK(GenericDomValue element, GenericDomValueReference domReference, Converter converter) { + return !hasBadResolve(domReference) + || converter instanceof ResolvingConverter && ((ResolvingConverter)converter).getAdditionalVariants(domReference.getConvertContext()).contains(element.getStringValue()); + } + @NotNull public List checkNameIdentity(DomElement element, final DomElementAnnotationHolder holder) { final String elementName = ElementPresentationManager.getElementName(element); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DefaultDomAnnotator.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DefaultDomAnnotator.java index cf14a4be076a..40dea532d3fe 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DefaultDomAnnotator.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DefaultDomAnnotator.java @@ -48,7 +48,7 @@ public class DefaultDomAnnotator implements Annotator { DomElementAnnotationsManagerImpl annotationsManager = getAnnotationsManager(fileElement); if (DomElementAnnotationsManagerImpl.isHolderUpToDate(fileElement) && annotationsManager.getProblemHolder(fileElement).isInspectionCompleted(inspection)) return; - final DomElementAnnotationHolderImpl annotationHolder = new DomElementAnnotationHolderImpl(); + final DomElementAnnotationHolderImpl annotationHolder = new DomElementAnnotationHolderImpl(true); inspection.checkFileElement(fileElement, annotationHolder); annotationsManager.appendProblems(fileElement, annotationHolder, inspection.getClass()); for (final DomElementProblemDescriptor descriptor : annotationHolder) { diff --git a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolder.java b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolder.java index 9b5db9f2aed3..a1bee881a5b1 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolder.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationHolder.java @@ -29,6 +29,8 @@ import org.jetbrains.annotations.Nullable; public interface DomElementAnnotationHolder extends Iterable{ + boolean isOnTheFly(); + @NotNull DomElementProblemDescriptor createProblem(@NotNull DomElement domElement, @Nullable String message, LocalQuickFix... fixes); diff --git a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManager.java b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManager.java index 77debde5f736..364aca490bc5 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManager.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementAnnotationsManager.java @@ -52,12 +52,16 @@ public abstract class DomElementAnnotationsManager { * Calls {@link com.intellij.util.xml.highlighting.DomElementsInspection#checkFileElement(com.intellij.util.xml.DomFileElement, DomElementAnnotationHolder)} * with appropriate parameters if needed, saves the collected problems to {@link com.intellij.util.xml.highlighting.DomElementsProblemsHolder}, which * can then be obtained from {@link #getProblemHolder(com.intellij.util.xml.DomElement)} method, and returns them. + * * @param element file element being checked * @param inspection inspection to run on the given file element + * @param onTheFly * @return collected DOM problem descriptors */ @NotNull - public abstract List checkFileElement(@NotNull DomFileElement element, @NotNull DomElementsInspection inspection); + public abstract List checkFileElement(@NotNull DomFileElement element, + @NotNull DomElementsInspection inspection, + boolean onTheFly); public abstract void dropAnnotationsCache(); diff --git a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java index 18a8a13a0eff..fe7670eb8755 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/highlighting/DomElementsInspection.java @@ -55,7 +55,7 @@ public abstract class DomElementsInspection extends XmlSup } /** - * This method is called internally in {@link com.intellij.util.xml.highlighting.DomElementAnnotationsManager#checkFileElement(com.intellij.util.xml.DomFileElement, DomElementsInspection)}, + * This method is called internally in {@link DomElementAnnotationsManager#checkFileElement(com.intellij.util.xml.DomFileElement, DomElementsInspection, boolean)} * it should add some problems to the annotation holder. The default implementation performs recursive tree traversal, and calls * {@link #checkDomElement(com.intellij.util.xml.DomElement, DomElementAnnotationHolder, DomHighlightingHelper)} for each element. * @param domFileElement file element to check @@ -143,7 +143,7 @@ public abstract class DomElementsInspection extends XmlSup @SuppressWarnings("UnusedParameters") final boolean isOnTheFly) { final DomElementAnnotationsManager annotationsManager = DomElementAnnotationsManager.getInstance(manager.getProject()); - final List list = annotationsManager.checkFileElement(domFileElement, this); + final List list = annotationsManager.checkFileElement(domFileElement, this, isOnTheFly); if (list.isEmpty()) return ProblemDescriptor.EMPTY_ARRAY; List problems = diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomHighlightingLiteTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomHighlightingLiteTest.java index 8470c15bb5e0..dc21e4d94167 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/DomHighlightingLiteTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/DomHighlightingLiteTest.java @@ -117,25 +117,29 @@ public class DomHighlightingLiteTest extends DomTestCase { } public void testProblemDescriptorIsCreated() throws Throwable { - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MyDomElementsInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class); final DomElementsProblemsHolderImpl holder = assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement)); assertEmpty(holder.getAllProblems()); assertEmpty(holder.getAllProblems(new MyDomElementsInspection())); } + private static DomElementAnnotationHolderImpl createHolder() { + return new DomElementAnnotationHolderImpl(true); + } + private static DomElementsProblemsHolderImpl assertNotEmptyHolder(final DomElementsProblemsHolder holder1) { return assertInstanceOf(holder1, DomElementsProblemsHolderImpl.class); } public void testInspectionMarkedAsPassedAfterAppend() throws Throwable { - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MyDomElementsInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class); final DomElementsProblemsHolderImpl holder = (DomElementsProblemsHolderImpl)myAnnotationsManager.getProblemHolder(myElement); assertTrue(holder.isInspectionCompleted(MyDomElementsInspection.class)); assertFalse(holder.isInspectionCompleted(DomElementsInspection.class)); } public void testHolderRecreationAfterChange() throws Throwable { - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MyDomElementsInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class); assertTrue(DomElementAnnotationsManagerImpl.isHolderUpToDate(myElement)); final DomElementsProblemsHolder holder = myAnnotationsManager.getProblemHolder(myElement); @@ -143,7 +147,7 @@ public class DomHighlightingLiteTest extends DomTestCase { assertFalse(DomElementAnnotationsManagerImpl.isHolderUpToDate(myElement)); assertSame(holder, myAnnotationsManager.getProblemHolder(myElement)); - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MyDomElementsInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MyDomElementsInspection.class); assertNotSame(holder, assertNotEmptyHolder(myAnnotationsManager.getProblemHolder(myElement))); } @@ -194,13 +198,13 @@ public class DomHighlightingLiteTest extends DomTestCase { myElement.setFileDescription(new MyNonHighlightingDomFileDescription()); assertEquals(DomHighlightStatus.NONE, myAnnotationsManager.getHighlightStatus(myElement)); - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MockDomInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MockDomInspection.class); assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement)); } public void testHighlightStatus_MockAnnotatingDomInspection() throws Throwable { myElement.setFileDescription(new DomFileDescription(DomElement.class, "a")); - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MockAnnotatingDomInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MockAnnotatingDomInspection.class); assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement)); } @@ -211,7 +215,7 @@ public class DomHighlightingLiteTest extends DomTestCase { @Override public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) { - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), this.getClass()); + myAnnotationsManager.appendProblems(myElement, createHolder(), this.getClass()); return new ProblemDescriptor[0]; } @@ -222,10 +226,10 @@ public class DomHighlightingLiteTest extends DomTestCase { HighlightDisplayKey.register(inspection.getShortName()); myInspectionProfile.setInspectionTools(inspection); - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MockAnnotatingDomInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MockAnnotatingDomInspection.class); assertEquals(DomHighlightStatus.ANNOTATORS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement)); - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), inspection.getClass()); + myAnnotationsManager.appendProblems(myElement, createHolder(), inspection.getClass()); assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement)); } @@ -236,7 +240,7 @@ public class DomHighlightingLiteTest extends DomTestCase { @Override public ProblemDescriptor[] checkFile(@NotNull final PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) { - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), this.getClass()); + myAnnotationsManager.appendProblems(myElement, createHolder(), this.getClass()); return new ProblemDescriptor[0]; } @@ -248,13 +252,13 @@ public class DomHighlightingLiteTest extends DomTestCase { myInspectionProfile.setInspectionTools(inspection); myInspectionProfile.setEnabled(inspection, false); - myAnnotationsManager.appendProblems(myElement, new DomElementAnnotationHolderImpl(), MockAnnotatingDomInspection.class); + myAnnotationsManager.appendProblems(myElement, createHolder(), MockAnnotatingDomInspection.class); assertEquals(DomHighlightStatus.INSPECTIONS_FINISHED, myAnnotationsManager.getHighlightStatus(myElement)); } public void testRequiredAttributeWithoutAttributeValue() throws Throwable { final MyElement element = createElement("", MyElement.class); - new MyBasicDomElementsInspection().checkDomElement(element.getId(), new DomElementAnnotationHolderImpl(), DomHighlightingHelperImpl.INSTANCE); + new MyBasicDomElementsInspection().checkDomElement(element.getId(), createHolder(), DomHighlightingHelperImpl.INSTANCE); } private class MyDomElementsInspection extends DomElementsInspection {