diff --git a/build/lib/gant/jps-sources.zip b/build/lib/gant/jps-sources.zip index b3ba72d2b6f4..8fe522551467 100644 Binary files a/build/lib/gant/jps-sources.zip and b/build/lib/gant/jps-sources.zip differ diff --git a/build/lib/gant/lib/jps.jar b/build/lib/gant/lib/jps.jar index 57bf7b6b164e..ba0edbb05375 100644 Binary files a/build/lib/gant/lib/jps.jar and b/build/lib/gant/lib/jps.jar differ diff --git a/build/scripts/common_tests.gant b/build/scripts/common_tests.gant index d29059d66986..dd7794da93d4 100644 --- a/build/scripts/common_tests.gant +++ b/build/scripts/common_tests.gant @@ -38,6 +38,8 @@ target('default': 'The default target') { }; } + commonJvmArgs().each { jvmarg(value: it) } + if (isDefined("jvm_args")) { jvm_args.each { jvmarg(value: it) } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 555fdc4f4ecc..fcf92f5c8a61 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -15,7 +15,6 @@ */ package com.intellij.codeInsight.completion; -import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix; import com.intellij.codeInsight.hint.ShowParameterInfoHandler; @@ -249,7 +248,6 @@ public class JavaCompletionContributor extends CompletionContributor { if (reference instanceof PsiJavaReference) { final ElementFilter filter = getReferenceFilter(position); if (filter != null) { - boolean showCapitalizedClasses = showCapitalizedClasses(result); final boolean isSwitchLabel = SWITCH_LABEL.accepts(position); final PsiFile originalFile = parameters.getOriginalFile(); for (LookupElement element : JavaCompletionUtil.processJavaReference(position, @@ -261,12 +259,6 @@ public class JavaCompletionContributor extends CompletionContributor { continue; } - if (!showCapitalizedClasses && - element.getObject() instanceof PsiClass && - StringUtil.isCapitalized(((PsiClass)element.getObject()).getName())) { - continue; - } - if (isSwitchLabel) { result.addElement(TailTypeDecorator.withTail(element, TailType.createSimpleTailType(':'))); } @@ -308,11 +300,6 @@ public class JavaCompletionContributor extends CompletionContributor { }); } - public static boolean showCapitalizedClasses(CompletionResultSet result) { - String prefix = result.getPrefixMatcher().getPrefix(); - return StringUtil.isEmpty(prefix) || StringUtil.isCapitalized(prefix) || CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE == CodeInsightSettings.NONE; - } - private static void addKeywords(CompletionParameters parameters, CompletionResultSet result) { PsiElement position = parameters.getPosition(); final Set lookupSet = new LinkedHashSet(); @@ -344,7 +331,7 @@ public class JavaCompletionContributor extends CompletionContributor { return false; } - return StringUtil.isCapitalized(result.getPrefixMatcher().getPrefix()); + return StringUtil.isNotEmpty(result.getPrefixMatcher().getPrefix()); } private static void completeAnnotationAttributeName(CompletionResultSet result, PsiElement insertedElement, diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index a1609e04d8be..3cc4288d9e20 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -849,7 +849,6 @@ public class HighlightMethodUtil { static HighlightInfo checkConstructorCallMustBeFirstStatement(PsiReferenceExpression expression) { - String text = expression.getText(); PsiElement methodCall = expression.getParent(); if (!HighlightUtil.isSuperOrThisMethodCall(methodCall)) return null; PsiElement codeBlock = methodCall.getParent().getParent(); @@ -863,7 +862,7 @@ public class HighlightMethodUtil { prevSibling = prevSibling.getPrevSibling(); } } - String message = JavaErrorMessages.message("constructor.call.must.be.first.statement", text + "()"); + String message = JavaErrorMessages.message("constructor.call.must.be.first.statement", expression.getText() + "()"); return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression.getParent(), message); } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java index e06812b6587a..ae3e603ccf70 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateClassFromNewFix.java @@ -48,11 +48,19 @@ public class CreateClassFromNewFix extends CreateFromUsageBaseFix { protected void invokeImpl(PsiClass targetClass) { assert ApplicationManager.getApplication().isWriteAccessAllowed(); - PsiNewExpression newExpression = getNewExpression(); + final PsiNewExpression newExpression = getNewExpression(); - PsiJavaCodeReferenceElement referenceElement = getReferenceElement(newExpression); - final PsiClass psiClass = CreateFromUsageUtils.createClass(referenceElement, CreateClassKind.CLASS, null); - setupClassFromNewExpression(psiClass, newExpression); + final PsiJavaCodeReferenceElement referenceElement = getReferenceElement(newExpression); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + final PsiClass psiClass = CreateFromUsageUtils.createClass(referenceElement, CreateClassKind.CLASS, null); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + setupClassFromNewExpression(psiClass, newExpression); + } + }); + } + }); } protected static void setupClassFromNewExpression(final PsiClass psiClass, final PsiNewExpression newExpression) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index fe27b82adea0..4bcc98095c95 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -41,6 +41,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -264,6 +265,7 @@ public class CreateFromUsageUtils { public static PsiClass createClass(final PsiJavaCodeReferenceElement referenceElement, final CreateClassKind classKind, final String superClassName) { + assert !ApplicationManager.getApplication().isWriteAccessAllowed(); final String name = referenceElement.getReferenceName(); final PsiElement qualifierElement; @@ -274,23 +276,7 @@ public class CreateFromUsageUtils { return ApplicationManager.getApplication().runWriteAction( new Computable() { public PsiClass compute() { - try { - PsiClass psiClass = (PsiClass) qualifierElement; - if (!CodeInsightUtilBase.preparePsiElementForWrite(psiClass)) return null; - - PsiManager manager = psiClass.getManager(); - PsiElementFactory elementFactory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - PsiClass result = classKind == INTERFACE ? elementFactory.createInterface(name) : - classKind == CLASS ? elementFactory.createClass(name) : - elementFactory.createEnum(name); - CreateFromUsageBaseFix.setupGenericParameters(result, referenceElement); - result = (PsiClass)manager.getCodeStyleManager().reformat(result); - return (PsiClass) psiClass.add(result); - } - catch (IncorrectOperationException e) { - LOG.error(e); - return null; - } + return createClassInQualifier((PsiClass)qualifierElement, classKind, name, referenceElement); } }); } @@ -302,20 +288,7 @@ public class CreateFromUsageUtils { final PsiManager manager = referenceElement.getManager(); final PsiFile sourceFile = referenceElement.getContainingFile(); final Module module = ModuleUtil.findModuleForPsiElement(sourceFile); - PsiPackage aPackage = null; - if (qualifierElement instanceof PsiPackage) { - aPackage = (PsiPackage)qualifierElement; - } - else { - final PsiDirectory directory = sourceFile.getContainingDirectory(); - if (directory != null) { - aPackage = JavaDirectoryService.getInstance().getPackage(directory); - } - - if (aPackage == null) { - aPackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage(""); - } - } + PsiPackage aPackage = findTargetPackage(qualifierElement, manager, sourceFile); if (aPackage == null) return null; final PsiDirectory targetDirectory; if (!ApplicationManager.getApplication().isUnitTestMode()) { @@ -335,6 +308,48 @@ public class CreateFromUsageUtils { return createClass(classKind, targetDirectory, name, manager, referenceElement, sourceFile, superClassName); } + @Nullable + public static PsiPackage findTargetPackage(PsiElement qualifierElement, PsiManager manager, PsiFile sourceFile) { + PsiPackage aPackage = null; + if (qualifierElement instanceof PsiPackage) { + aPackage = (PsiPackage)qualifierElement; + } + else { + final PsiDirectory directory = sourceFile.getContainingDirectory(); + if (directory != null) { + aPackage = JavaDirectoryService.getInstance().getPackage(directory); + } + + if (aPackage == null) { + aPackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage(""); + } + } + if (aPackage == null) return null; + return aPackage; + } + + public static PsiClass createClassInQualifier(PsiClass psiClass, + CreateClassKind classKind, + String name, + PsiJavaCodeReferenceElement referenceElement) { + try { + if (!CodeInsightUtilBase.preparePsiElementForWrite(psiClass)) return null; + + PsiManager manager = psiClass.getManager(); + PsiElementFactory elementFactory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); + PsiClass result = classKind == INTERFACE ? elementFactory.createInterface(name) : + classKind == CLASS ? elementFactory.createClass(name) : + elementFactory.createEnum(name); + CreateFromUsageBaseFix.setupGenericParameters(result, referenceElement); + result = (PsiClass)manager.getCodeStyleManager().reformat(result); + return (PsiClass) psiClass.add(result); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return null; + } + } + public static PsiClass createClass(final CreateClassKind classKind, final PsiDirectory directory, final String name, diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java index ed62d32ba2cd..81c76b2737c8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiSuperMethodImplUtil.java @@ -78,8 +78,8 @@ public class PsiSuperMethodImplUtil { @NotNull private static List findSuperMethodSignatures(PsiMethod method, - PsiClass parentClass, - boolean allowStaticMethod) { + PsiClass parentClass, + boolean allowStaticMethod) { return new ArrayList(SuperMethodsSearch.search(method, parentClass, true, allowStaticMethod).findAll()); } @@ -306,4 +306,58 @@ public class PsiSuperMethodImplUtil { private static Map getSignaturesMap(final PsiClass aClass) { return SIGNATURES_KEY.getValue(aClass); } + + + // uses hierarchy signature tree if available, traverses class structure by itself otherwise + public static boolean isSuperMethodSmart(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) { + //boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod); + + if (method == superMethod) return false; + PsiClass aClass = method.getContainingClass(); + PsiClass superClass = superMethod.getContainingClass(); + + if (aClass == null || superClass == null || superClass == aClass) return false; + + if (!canHaveSuperMethod(method, true, false)) return false; + + PsiMethod[] superMethods = null; + Map cachedMap = SIGNATURES_KEY.getCachedValueOrNull(aClass); + if (cachedMap != null) { + HierarchicalMethodSignature signature = cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY)); + if (signature != null) { + superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures()); + } + } + if (superMethods == null) { + PsiClassType[] directSupers = aClass.getSuperTypes(); + List found = null; + boolean canceled = false; + for (PsiClassType directSuper : directSupers) { + PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics(); + if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) { + // generics + canceled = true; + break; + } + PsiClass directSuperClass = resolveResult.getElement(); + if (directSuperClass == null) continue; + PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false); + if (candidates.length != 0) { + if (found == null) found = new ArrayList(); + for (PsiMethod candidate : candidates) { + if (PsiUtil.canBeOverriden(candidate)) found.add(candidate); + } + } + } + superMethods = canceled ? null : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]); + } + if (superMethods == null) { + superMethods = MethodSignatureUtil.convertMethodSignaturesToMethods(method.getHierarchicalMethodSignature().getSuperSignatures()); + } + + for (PsiMethod superCandidate : superMethods) { + if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod)) return true; + } + return false; + } } diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java index ae32fccd1998..0d59b5ed8367 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/SmartTypePointerManagerImpl.java @@ -49,7 +49,7 @@ public class SmartTypePointerManagerImpl extends SmartTypePointerManager { } @NotNull - public SmartTypePointer createSmartTypePointer(PsiType type) { + public SmartTypePointer createSmartTypePointer(@NotNull PsiType type) { return type.accept(new SmartTypeCreatingVisitor()); } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java index d3e6181586f5..9e0948a847ef 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java @@ -49,14 +49,23 @@ public class JavaResolveUtil { public static boolean isAccessible(@NotNull PsiMember member, @Nullable final PsiClass memberClass, @Nullable PsiModifierList modifierList, - @NotNull PsiElement place, + @NotNull PsiElement place, @Nullable PsiClass accessObjectClass, @Nullable final PsiElement fileResolveScope) { + return isAccessible(member, memberClass, modifierList, place, accessObjectClass, fileResolveScope, place.getContainingFile()); + } + + public static boolean isAccessible(@NotNull PsiMember member, + @Nullable final PsiClass memberClass, + @Nullable PsiModifierList modifierList, + @NotNull PsiElement place, + @Nullable PsiClass accessObjectClass, + @Nullable final PsiElement fileResolveScope, + final PsiFile placeFile) { if (modifierList == null) return true; - final PsiFile placeContainingFile = place.getContainingFile(); final PsiManager manager = member.getManager(); - if (placeContainingFile instanceof JavaCodeFragment) { - JavaCodeFragment fragment = (JavaCodeFragment)placeContainingFile; + if (placeFile instanceof JavaCodeFragment) { + JavaCodeFragment fragment = (JavaCodeFragment)placeFile; JavaCodeFragment.VisibilityChecker visibilityChecker = fragment.getVisibilityChecker(); if (visibilityChecker != null) { JavaCodeFragment.VisibilityChecker.Visibility visibility = visibilityChecker.isDeclarationVisible(member, place); @@ -64,17 +73,17 @@ public class JavaResolveUtil { if (visibility == JavaCodeFragment.VisibilityChecker.Visibility.NOT_VISIBLE) return false; } } - else if (placeContainingFile instanceof XmlFile && !JspPsiUtil.isInJspFile(placeContainingFile)) return true; + else if (placeFile instanceof XmlFile && !JspPsiUtil.isInJspFile(placeFile)) return true; // We don't care about access rights in javadoc if (isInJavaDoc(place)) return true; if (accessObjectClass != null) { if (!isAccessible(accessObjectClass, accessObjectClass.getContainingClass(), accessObjectClass.getModifierList(), place, null, - null)) return false; + null, placeFile)) return false; } int effectiveAccessLevel = PsiUtil.getAccessLevel(modifierList); - PsiFile file = FileContextUtil.getContextFile(place); //TODO: implementation method!!!! + PsiFile file = placeFile == null ? null : FileContextUtil.getContextFile(placeFile); //TODO: implementation method!!!! if (JspPsiUtil.isInJspFile(file) && JspPsiUtil.isInJspFile(member.getContainingFile())) return true; if (file instanceof XmlFile && !JspPsiUtil.isInJspFile(file)) return true; if (effectiveAccessLevel == PsiUtil.ACCESS_LEVEL_PUBLIC) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 551b95ac8ba4..c60d11f38076 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -15,7 +15,10 @@ */ package com.intellij.psi.impl.source.resolve; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; @@ -32,10 +35,8 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; - public class PsiResolveHelperImpl implements PsiResolveHelper { + private static final RecursionGuard ourGuard = RecursionManager.createGuard("typeArgInference"); private final PsiManager myManager; public PsiResolveHelperImpl(PsiManager manager) { @@ -146,7 +147,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (parameters.length > 0) { for (int j = 0; j < arguments.length; j++) { PsiExpression argument = arguments[j]; - if (argument instanceof PsiMethodCallExpression && myBlockedForInferenceMethodCalls.get().contains(argument)) continue; + if (argument instanceof PsiMethodCallExpression && ourGuard.currentStack().contains(argument)) continue; final PsiParameter parameter = parameters[Math.min(j, parameters.length - 1)]; if (j >= parameters.length && !parameter.isVarArgs()) break; @@ -701,12 +702,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return result; } - private static final ThreadLocal> myBlockedForInferenceMethodCalls = new ThreadLocal>() { - protected List initialValue() { - return new ArrayList(2); - } - }; - + @Nullable private static Pair inferTypeForCompletionFromCallContext(final PsiCallExpression innerMethodCall, final PsiExpressionList expressionList, final PsiCallExpression contextCall, @@ -722,7 +718,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (owner == null) return null; final PsiType innerReturnType = owner.getReturnType(); - for (JavaResolveResult result : results) { + for (final JavaResolveResult result : results) { final PsiElement element = result.getElement(); if (element instanceof PsiMethod) { final PsiMethod method = (PsiMethod)element; @@ -735,10 +731,14 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { parameter = parameters[parameters.length - 1]; } if (parameter != null) { - //prevent infinite recursion - myBlockedForInferenceMethodCalls.get().add(innerMethodCall); - PsiType type = result.getSubstitutor().substitute(parameter.getType()); - myBlockedForInferenceMethodCalls.get().remove(innerMethodCall); + final PsiParameter finalParameter = parameter; + PsiType type = ourGuard + .doPreventingRecursion(innerMethodCall, new Computable() { + @Override + public PsiType compute() { + return result.getSubstitutor().substitute(finalParameter.getType()); + } + }) ; final Pair constraint = getSubstitutionForTypeParameterConstraint(typeParameter, innerReturnType, type, false, PsiUtil.getLanguageLevel(innerMethodCall)); if (constraint != null) return constraint; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java index d85d4a99a724..b49ea654f6dd 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiReferenceExpressionImpl.java @@ -332,6 +332,7 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements public boolean isReferenceTo(PsiElement element) { IElementType i = getLastChildNode().getElementType(); + boolean resolvingToMethod = element instanceof PsiMethod; if (i == JavaTokenType.IDENTIFIER) { if (!(element instanceof PsiPackage)) { if (!(element instanceof PsiNamedElement)) return false; @@ -341,10 +342,15 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements } } else if (i == JavaTokenType.SUPER_KEYWORD || i == JavaTokenType.THIS_KEYWORD) { - if (!(element instanceof PsiMethod)) return false; + if (!resolvingToMethod) return false; if (!((PsiMethod)element).isConstructor()) return false; } + PsiElement parent = getParent(); + boolean parentIsMethodCall = parent instanceof PsiMethodCallExpression; + // optimization: methodCallExpression should resolve to a method + if (parentIsMethodCall != resolvingToMethod) return false; + return element.getManager().areElementsEquivalent(element, resolve()); } diff --git a/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java b/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java index 2b3191611767..cd88e48ba124 100644 --- a/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java +++ b/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.resolve; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; @@ -25,6 +26,7 @@ import com.intellij.psi.scope.conflictResolvers.DuplicateConflictResolver; import com.intellij.psi.scope.processor.MethodCandidatesProcessor; import com.intellij.psi.scope.processor.MethodResolverProcessor; import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; @@ -45,12 +47,14 @@ public class JavaMethodResolveHelper { public JavaMethodResolveHelper(final PsiElement argumentList, @Nullable final PsiType[] parameterTypes) { myParameterTypes = parameterTypes; + final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(argumentList); final PsiConflictResolver resolver = parameterTypes == null ? DuplicateConflictResolver.INSTANCE : new JavaMethodsConflictResolver(argumentList, parameterTypes); myProcessor = new MethodResolverProcessor(argumentList, new PsiConflictResolver[]{resolver}) { protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor, final boolean staticProblem, final boolean accessible) { - return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext, parameterTypes, PsiType.EMPTY_ARRAY); + return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext, parameterTypes, + PsiType.EMPTY_ARRAY, languageLevel); } @Override diff --git a/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index f324999ba9a7..db990d48f565 100644 --- a/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.scope.PsiConflictResolver; @@ -150,7 +151,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (!method.hasModifierProperty(PsiModifier.STATIC)) { for (int k=i-1; k>=0; k--) { PsiMethod existingMethod = (PsiMethod)conflicts.get(k).getElement(); - if (PsiSuperMethodUtil.isSuperMethod(existingMethod, method)) { + if (PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) { conflicts.remove(i); i--; continue nextConflict; @@ -189,12 +190,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ // filter out methods with incorrect inferred bounds (for unrelated methods only) boolean existingTypeParamAgree = areTypeParametersAgree(existing); boolean infoTypeParamAgree = areTypeParametersAgree(info); - if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodUtil.isSuperMethod(method, existingMethod)) { + if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) { conflicts.remove(i); i--; continue; } - else if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodUtil.isSuperMethod(existingMethod, method)) { + else if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) { signatures.put(signature, info); int index = conflicts.indexOf(existing); conflicts.remove(index); diff --git a/java/java-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java b/java/java-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java index 5dd0c032e455..e6ff85329f71 100644 --- a/java/java-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java +++ b/java/java-impl/src/com/intellij/psi/scope/processor/ConflictFilterProcessor.java @@ -16,10 +16,7 @@ package com.intellij.psi.scope.processor; import com.intellij.openapi.util.Key; -import com.intellij.psi.JavaResolveResult; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiSubstitutor; -import com.intellij.psi.ResolveState; +import com.intellij.psi.*; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.scope.JavaScopeProcessorEvent; @@ -41,6 +38,7 @@ public class ConflictFilterProcessor extends FilterScopeProcessor private JavaResolveResult[] myCachedResult = null; protected String myName; protected final PsiElement myPlace; + protected final PsiFile myPlaceFile; public ConflictFilterProcessor(String name, ElementFilter filter, PsiConflictResolver[] resolvers, List container, final PsiElement place){ @@ -48,6 +46,7 @@ public class ConflictFilterProcessor extends FilterScopeProcessor myResolvers = resolvers; myName = name; myPlace = place; + myPlaceFile = place.getContainingFile(); } public boolean execute(PsiElement element, ResolveState state){ diff --git a/java/java-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java b/java/java-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java index 4e4c7aa53af5..d633b2178146 100644 --- a/java/java-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java +++ b/java/java-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java @@ -50,7 +50,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{ public void addMethod(final PsiMethod method, final PsiSubstitutor substitutor, final boolean staticProblem) { boolean isAccessible = JavaResolveUtil.isAccessible(method, method.getContainingClass(), method.getModifierList(), - myPlace, myAccessClass, myCurrentFileContext); + myPlace, myAccessClass, myCurrentFileContext, myPlaceFile); myHasAccessibleStaticCorrectCandidate |= isAccessible && !staticProblem; if (isAccepted(method)) { @@ -62,7 +62,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{ final boolean staticProblem, final boolean accessible) { return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, getArgumentList(), myCurrentFileContext, - getArgumentList().getExpressionTypes(), getTypeArguments()); + getArgumentList().getExpressionTypes(), getTypeArguments(), getLanguageLevel()); } protected boolean isAccepted(final PsiMethod candidate) { diff --git a/java/java-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java b/java/java-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java index fc9b4d9ed687..73cd192fda70 100644 --- a/java/java-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java +++ b/java/java-impl/src/com/intellij/psi/scope/processor/MethodsProcessor.java @@ -16,6 +16,7 @@ package com.intellij.psi.scope.processor; import com.intellij.openapi.util.Key; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.infos.CandidateInfo; @@ -23,6 +24,7 @@ import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.scope.PsiConflictResolver; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.SmartList; /** @@ -41,6 +43,7 @@ public abstract class MethodsProcessor extends ConflictFilterProcessor implement protected PsiClass myAccessClass = null; private PsiExpressionList myArgumentList; private PsiType[] myTypeArguments; + private LanguageLevel myLanguageLevel; public MethodsProcessor(PsiConflictResolver[] resolvers, SmartList container, final PsiElement place) { super(null, ourFilter, resolvers, container, place); @@ -52,6 +55,11 @@ public abstract class MethodsProcessor extends ConflictFilterProcessor implement public void setArgumentList(PsiExpressionList argList) { myArgumentList = argList; + myLanguageLevel = PsiUtil.getLanguageLevel(myArgumentList); + } + + protected LanguageLevel getLanguageLevel() { + return myLanguageLevel; } public void obtainTypeArguments(PsiCallExpression callExpression) { diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java index 47da714e3d2a..0dff8adf5943 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java @@ -252,7 +252,7 @@ public class CopyClassesHandler implements CopyHandlerDelegate { return newElement; } - private static PsiFile copy(PsiFile file, PsiDirectory directory, String name, String relativePath) { + private static PsiFile copy(@NotNull PsiFile file, PsiDirectory directory, String name, String relativePath) { final String fileName = name != null ? (name + "." + file.getViewProvider().getVirtualFile().getExtension()) : file.getName(); if (relativePath != null && !relativePath.isEmpty()) { return buildRelativeDir(directory, relativePath).findOrCreateTargetDirectory().copyFileFrom(fileName, file); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java index 86e12da2147f..dfa6615c6b6e 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceConstantPopup.java @@ -24,6 +24,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.Computable; @@ -116,7 +117,7 @@ public class InplaceIntroduceConstantPopup { } myOccurenceManager = occurenceManager; - myExprMarker = expr != null ? myEditor.getDocument().createRangeMarker(expr.getTextRange()) : null; + myExprMarker = expr != null && expr.isPhysical() ? myEditor.getDocument().createRangeMarker(expr.getTextRange()) : null; myExprText = expr != null ? expr.getText() : null; myLocalName = localVariable != null ? localVariable.getName() : null; @@ -200,6 +201,7 @@ public class InplaceIntroduceConstantPopup { final PsiField field = createFieldToStartTemplateOn(names, defaultType); if (field != null) { myEditor.getCaretModel().moveToOffset(field.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); final LinkedHashSet nameSuggestions = new LinkedHashSet(); nameSuggestions.add(field.getName()); nameSuggestions.addAll(Arrays.asList(names)); @@ -218,6 +220,10 @@ public class InplaceIntroduceConstantPopup { PsiField field = elementFactory.createFieldFromText(psiType.getCanonicalText() + " " + (myConstantName != null ? myConstantName : names[0]) + " = " + myExprText + ";", myParentClass); PsiUtil.setModifierProperty(field, PsiModifier.FINAL, true); PsiUtil.setModifierProperty(field, PsiModifier.STATIC, true); + final String visibility = myVisibilityPanel.getVisibility(); + if (visibility != null) { + PsiUtil.setModifierProperty(field, visibility, true); + } field = BaseExpressionToFieldHandler.ConvertToFieldRunnable.appendField(myExpr, myParentClass, myParentClass, myAnchorElementIfAll, field); return field; } @@ -255,7 +261,7 @@ public class InplaceIntroduceConstantPopup { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, field, false, myTypeSelectorManager.getTypesForAll().length > 1, - myExpr != null ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null, InplaceIntroduceConstantPopup.this.getOccurrenceMarkers()); + myExpr != null && myExpr.isPhysical() ? myEditor.getDocument().createRangeMarker(myExpr.getTextRange()) : null, InplaceIntroduceConstantPopup.this.getOccurrenceMarkers()); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType()); @@ -269,7 +275,7 @@ public class InplaceIntroduceConstantPopup { @Override protected PsiExpression getExpr() { - return myExpr; + return myExpr != null && myExpr.isValid() && myExpr.isPhysical() ? myExpr : null; } @Override @@ -392,9 +398,12 @@ public class InplaceIntroduceConstantPopup { public void run() { final PsiFile containingFile = myParentClass.getContainingFile(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - myExpr = restoreExpression(containingFile, psiField, elementFactory, getExprMarker(), myExprText); - if (myExpr != null) { - myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); + final RangeMarker exprMarker = getExprMarker(); + if (exprMarker != null) { + myExpr = restoreExpression(containingFile, psiField, elementFactory, exprMarker, myExprText); + if (myExpr != null && myExpr.isPhysical()) { + myExprMarker = myEditor.getDocument().createRangeMarker(myExpr.getTextRange()); + } } final List occurrenceMarkers = getOccurrenceMarkers(); for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java index 848db6a5cee2..7e2f140c9820 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/InplaceIntroduceFieldPopup.java @@ -22,6 +22,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; @@ -95,7 +96,7 @@ public class InplaceIntroduceFieldPopup { myInitializerExpression = initializerExpression; myExprText = myInitializerExpression != null ? myInitializerExpression.getText() : null; myLocalName = localVariable != null ? localVariable.getName() : null; - myExprMarker = myInitializerExpression != null ? editor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null; + myExprMarker = myInitializerExpression != null && myInitializerExpression.isPhysical() ? editor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null; myTypeSelectorManager = typeSelectorManager; myAnchorElement = anchorElement; myAnchorElementIfAll = anchorElementIfAll; @@ -176,6 +177,7 @@ public class InplaceIntroduceFieldPopup { final PsiField field = createFieldToStartTemplateOn(suggestedNameInfo.names, defaultType); if (field != null) { myEditor.getCaretModel().moveToOffset(field.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); final LinkedHashSet nameSuggestions = new LinkedHashSet(); nameSuggestions.add(field.getName()); nameSuggestions.addAll(Arrays.asList(suggestedNameInfo.names)); @@ -195,6 +197,10 @@ public class InplaceIntroduceFieldPopup { PsiField field = elementFactory.createField(myFieldName != null ? myFieldName : names[0], defaultType); field = (PsiField)myParentClass.add(field); PsiUtil.setModifierProperty(field, PsiModifier.FINAL, myIntroduceFieldPanel.isDeclareFinal()); + final String visibility = myIntroduceFieldPanel.getFieldVisibility(); + if (visibility != null) { + PsiUtil.setModifierProperty(field, visibility, true); + } return field; } }); @@ -233,7 +239,7 @@ public class InplaceIntroduceFieldPopup { super(myProject, new TypeExpression(myProject, myTypeSelectorManager.getTypesForAll()), myEditor, psiVariable, false, myTypeSelectorManager.getTypesForAll().length > 1, - myInitializerExpression != null ? myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null, InplaceIntroduceFieldPopup.this.getOccurrenceMarkers()); + myInitializerExpression != null && myInitializerExpression.isPhysical() ? myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()) : null, InplaceIntroduceFieldPopup.this.getOccurrenceMarkers()); myDefaultParameterTypePointer = SmartTypePointerManager.getInstance(myProject).createSmartTypePointer(myTypeSelectorManager.getDefaultType()); myFieldRangeStart = myEditor.getDocument().createRangeMarker(psiVariable.getTextRange()); @@ -246,7 +252,7 @@ public class InplaceIntroduceFieldPopup { @Override protected PsiExpression getExpr() { - return myInitializerExpression; + return myInitializerExpression != null && myInitializerExpression.isValid() && myInitializerExpression.isPhysical() ? myInitializerExpression : null; } @Override @@ -354,9 +360,11 @@ public class InplaceIntroduceFieldPopup { public void run() { final PsiFile containingFile = myParentClass.getContainingFile(); final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject); - myInitializerExpression = restoreExpression(containingFile, psiField, elementFactory, getExprMarker(), myExprText); - if (myInitializerExpression != null) { - myExprMarker = myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()); + if (getExprMarker() != null) { + myInitializerExpression = restoreExpression(containingFile, psiField, elementFactory, getExprMarker(), myExprText); + if (myInitializerExpression != null) { + myExprMarker = myEditor.getDocument().createRangeMarker(myInitializerExpression.getTextRange()); + } } final List occurrenceMarkers = getOccurrenceMarkers(); for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java index 7e7606ad7612..a63f7a2a676f 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/InplaceIntroduceParameterPopup.java @@ -22,6 +22,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.psi.*; @@ -135,6 +136,7 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { if (parameter != null) { myParameterIndex = myMethod.getParameterList().getParameterIndex(parameter); myEditor.getCaretModel().moveToOffset(parameter.getTextOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); final LinkedHashSet nameSuggestions = new LinkedHashSet(); nameSuggestions.add(parameter.getName()); nameSuggestions.addAll(Arrays.asList(names)); @@ -247,20 +249,25 @@ class InplaceIntroduceParameterPopup extends IntroduceParameterSettingsUI { getReplaceFieldsWithGetters(), myMustBeFinal || myFinal, isGenerateDelegate(), myParameterTypePointer.getType(), parametersToRemove); - ApplicationManager.getApplication().invokeLater(new Runnable() { + final Runnable runnable = new Runnable() { public void run() { - final boolean [] conflictsFound = new boolean[] {true}; - processor.setPrepareSuccessfulSwingThreadCallback(new Runnable() { - @Override + ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { - conflictsFound[0] = processor.hasConflicts(); + final boolean [] conflictsFound = new boolean[] {true}; + processor.setPrepareSuccessfulSwingThreadCallback(new Runnable() { + @Override + public void run() { + conflictsFound[0] = processor.hasConflicts(); + } + }); + processor.run(); + normalizeParameterIdxAccordingToRemovedParams(parametersToRemove); + ParameterInplaceIntroducer.super.moveOffsetAfter(!conflictsFound[0]); } }); - processor.run(); - normalizeParameterIdxAccordingToRemovedParams(parametersToRemove); - ParameterInplaceIntroducer.super.moveOffsetAfter(!conflictsFound[0]); } - }); + }; + CommandProcessor.getInstance().executeCommand(myProject, runnable, IntroduceParameterHandler.REFACTORING_NAME, null); } else { super.moveOffsetAfter(success); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index e75a44e48d8b..001e566b46c3 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -90,7 +90,11 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme final PsiElement[] statementsInRange = findStatementsAtOffset(editor, file, offset); //try line selection - if (statementsInRange.length == 1 && (PsiUtil.hasErrorElementChild(statementsInRange[0]) || !PsiUtil.isStatement(statementsInRange[0]) || isPreferStatements())) { + if (statementsInRange.length == 1 && (PsiUtil.hasErrorElementChild(statementsInRange[0]) || + !PsiUtil.isStatement(statementsInRange[0]) || + statementsInRange[0].getTextRange().getStartOffset() >= offset || + statementsInRange[0].getTextRange().getEndOffset() <= offset || + isPreferStatements())) { selectionModel.selectLineAtCaret(); if (findExpressionInRange(project, file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) == null) { selectionModel.removeSelection(); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java index 363393e2c7e5..2a164b4ea3c6 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableInplaceIntroducer.java @@ -28,10 +28,7 @@ import com.intellij.ide.IdeTooltipManager; import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.*; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.RangeMarker; -import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.editor.*; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; @@ -55,6 +52,7 @@ import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.TitlePanel; import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.ui.PositionTracker; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -161,8 +159,9 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { @Override public boolean performInplaceRename(boolean processTextOccurrences, LinkedHashSet nameSuggestions) { + final boolean result = super.performInplaceRename(processTextOccurrences, nameSuggestions); showBalloon(); - return super.performInplaceRename(processTextOccurrences, nameSuggestions); + return result; } public RangeMarker getExprMarker() { @@ -178,12 +177,13 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { if (psiVariable == null) { return; } + LOG.assertTrue(psiVariable.isValid()); saveSettings(psiVariable); adjustLine(psiVariable, document); int startOffset = myExprMarker != null && myExprMarker.isValid() ? myExprMarker.getStartOffset() : psiVariable.getTextOffset(); final PsiFile file = psiVariable.getContainingFile(); final PsiReference referenceAt = file.findReferenceAt(startOffset); - if (referenceAt != null && referenceAt.resolve() instanceof PsiLocalVariable) { + if (referenceAt != null && referenceAt.resolve() instanceof PsiVariable) { startOffset = referenceAt.getElement().getTextRange().getEndOffset(); } else { @@ -193,6 +193,7 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { } } myEditor.getCaretModel().moveToOffset(startOffset); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); if (psiVariable.getInitializer() != null) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { @@ -353,7 +354,7 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { if (ApplicationManager.getApplication().isHeadlessEnvironment()) return; final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(component); balloonBuilder.setFadeoutTime(0) - .setFillColor(IdeTooltipManager.GRAPHITE_COLOR) + .setFillColor(IdeTooltipManager.GRAPHITE_COLOR.brighter().brighter()) .setAnimationCycle(0) .setHideOnClickOutside(false) .setHideOnKeyOutside(false) @@ -363,8 +364,11 @@ public class VariableInplaceIntroducer extends VariableInplaceRenamer { final RelativePoint target = JBPopupFactory.getInstance().guessBestPopupLocation(myEditor); final Point screenPoint = target.getScreenPoint(); myBalloon = balloonBuilder.createBalloon(); - myBalloon - .show(new RelativePoint(new Point(screenPoint.x, screenPoint.y - myEditor.getLineHeight())), Balloon.Position.above); + int y = screenPoint.y; + if (target.getPoint().getY() > myEditor.getLineHeight() + myBalloon.getPreferredSize().getHeight()) { + y -= myEditor.getLineHeight(); + } + myBalloon.show(new RelativePoint(new Point(screenPoint.x, y)), Balloon.Position.above); } public class FinalListener implements ActionListener { diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java index 9cd7922962fb..36f119eec048 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveDirectoryWithClassesProcessor.java @@ -33,7 +33,10 @@ import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.intellij.refactoring.move.FileReferenceContextUtil; import com.intellij.refactoring.move.MoveCallback; +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler; +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil; import com.intellij.refactoring.rename.RenameUtil; import com.intellij.refactoring.util.NonCodeUsageInfo; import com.intellij.refactoring.util.RefactoringUIUtil; @@ -67,7 +70,8 @@ public class MoveDirectoryWithClassesProcessor extends BaseRefactoringProcessor if (targetDirectory != null) { final List dirs = new ArrayList(Arrays.asList(directories)); for (Iterator iterator = dirs.iterator(); iterator.hasNext();) { - if (targetDirectory.equals(iterator.next().getParentDirectory())) { + final PsiDirectory directory = iterator.next(); + if (targetDirectory.equals(directory.getParentDirectory()) || targetDirectory.equals(directory)) { iterator.remove(); } } @@ -182,6 +186,7 @@ public class MoveDirectoryWithClassesProcessor extends BaseRefactoringProcessor Messages.showErrorDialog(myProject, e.getMessage(), CommonBundle.getErrorTitle()); return; } + final List movedFiles = new ArrayList(); final Map oldToNewElementsMapping = new HashMap(); for (PsiFile psiFile : myFilesToMove.keySet()) { ChangeContextUtil.encodeContextInfo(psiFile, true); @@ -195,7 +200,14 @@ public class MoveDirectoryWithClassesProcessor extends BaseRefactoringProcessor } } else { if (!moveDestination.equals(psiFile.getContainingDirectory())) { - psiFile.getManager().moveFile(psiFile, moveDestination); + MoveFileHandler.forElement(psiFile).prepareMovedFile(psiFile, moveDestination, oldToNewElementsMapping); + + PsiFile moving = moveDestination.findFile(psiFile.getName()); + if (moving == null) { + MoveFilesOrDirectoriesUtil.doMoveFile(psiFile, moveDestination); + } + moving = moveDestination.findFile(psiFile.getName()); + movedFiles.add(moving); listener.elementMoved(psiFile); } } @@ -203,6 +215,13 @@ public class MoveDirectoryWithClassesProcessor extends BaseRefactoringProcessor for (PsiElement newElement : oldToNewElementsMapping.values()) { ChangeContextUtil.decodeContextInfo(newElement, null, null); } + + // fix references in moved files to outer files + for (PsiFile movedFile : movedFiles) { + MoveFileHandler.forElement(movedFile).updateMovedFile(movedFile); + FileReferenceContextUtil.decodeFileReferences(movedFile); + } + myNonCodeUsages = MoveClassesOrPackagesProcessor.retargetUsages(usages, oldToNewElementsMapping); for (UsageInfo usage : usages) { if (usage instanceof RemoveOnDemandImportStatementsUsageInfo) { diff --git a/java/java-tests/testData/codeInsight/completion/normal/OnlyUppercaseClassesWhenNothingIsFound.java b/java/java-tests/testData/codeInsight/completion/normal/OnlyUppercaseClassesWhenNothingIsFound.java deleted file mode 100644 index 89550af05178..000000000000 --- a/java/java-tests/testData/codeInsight/completion/normal/OnlyUppercaseClassesWhenNothingIsFound.java +++ /dev/null @@ -1,7 +0,0 @@ -public class Foo { - - { - aa - } - -} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after6.java index c791df6fc625..2ee20246b298 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after6.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after6.java @@ -3,7 +3,7 @@ public class Test { public static void main() { Collection[] cc = new MyCollection[10]; } -} +} -public class MyCollection { +public class MyCollection { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after8.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after8.java index e1e4712ec0c1..e4761ed3c0ca 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after8.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/after8.java @@ -6,7 +6,7 @@ public class Test { public static void main() { JTable table = new JTable(new MyTableModel()); } -} +} -public class MyTableModel implements TableModel { +public class MyTableModel implements TableModel { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/afterGenerics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/afterGenerics.java index aea3f7e011f6..3cae4d83de95 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/afterGenerics.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createClassFromNew/afterGenerics.java @@ -3,7 +3,7 @@ class Test { void foo () { new Generic (); } -} +} -public class Generic { +public class Generic { } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java index bd093ca219a1..76192e23e425 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/HeavyNormalCompletionTest.java @@ -48,13 +48,6 @@ public class HeavyNormalCompletionTest extends CompletionTestCase{ checkResultByFile("/codeInsight/completion/normal/" + getTestName(false) + "_after.java"); } - public void testOnlyUppercaseClassesWhenNothingIsFound() throws Throwable { - createClass("package foo.bar; public class aaaxBxCxDxEx {}"); - - configureByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - checkResultByFile("/codeInsight/completion/normal/" + getTestName(false) + ".java"); - } - public void testAllClassesOnSecondBasicCompletion() throws Throwable { createClass("package foo.bar; public class AxBxCxDxEx {}"); diff --git a/java/openapi/src/com/intellij/psi/SmartTypePointerManager.java b/java/openapi/src/com/intellij/psi/SmartTypePointerManager.java index 7c46254a519d..2624506a0b57 100644 --- a/java/openapi/src/com/intellij/psi/SmartTypePointerManager.java +++ b/java/openapi/src/com/intellij/psi/SmartTypePointerManager.java @@ -29,5 +29,5 @@ public abstract class SmartTypePointerManager { } @NotNull - public abstract SmartTypePointer createSmartTypePointer(PsiType type); + public abstract SmartTypePointer createSmartTypePointer(@NotNull PsiType type); } \ No newline at end of file diff --git a/java/openapi/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/openapi/src/com/intellij/psi/infos/MethodCandidateInfo.java index 70e33bcc70a7..fdaeb1f7b9a0 100644 --- a/java/openapi/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/openapi/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.infos; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.Nullable; @@ -28,6 +29,7 @@ public class MethodCandidateInfo extends CandidateInfo{ private final PsiType[] myArgumentTypes; private final PsiType[] myTypeArguments; private PsiSubstitutor myCalcedSubstitutor = null; + private final LanguageLevel myLanguageLevel; public MethodCandidateInfo(PsiElement candidate, PsiSubstitutor substitutor, @@ -37,10 +39,24 @@ public class MethodCandidateInfo extends CandidateInfo{ PsiElement currFileContext, @Nullable PsiType[] argumentTypes, PsiType[] typeArguments) { + this(candidate, substitutor, accessProblem, staticsProblem, argumentList, currFileContext, argumentTypes, typeArguments, + PsiUtil.getLanguageLevel(argumentList)); + } + + public MethodCandidateInfo(PsiElement candidate, + PsiSubstitutor substitutor, + boolean accessProblem, + boolean staticsProblem, + PsiElement argumentList, + PsiElement currFileContext, + @Nullable PsiType[] argumentTypes, + PsiType[] typeArguments, + final LanguageLevel languageLevel) { super(candidate, substitutor, accessProblem, staticsProblem, currFileContext); myArgumentList = argumentList; myArgumentTypes = argumentTypes; myTypeArguments = typeArguments; + myLanguageLevel = languageLevel; } public boolean isApplicable(){ @@ -50,7 +66,7 @@ public class MethodCandidateInfo extends CandidateInfo{ private int getApplicabilityLevelInner() { if (myArgumentTypes == null) return ApplicabilityLevel.NOT_APPLICABLE; - int level = PsiUtil.getApplicabilityLevel(getElement(), getSubstitutor(), myArgumentTypes, PsiUtil.getLanguageLevel(myArgumentList)); + int level = PsiUtil.getApplicabilityLevel(getElement(), getSubstitutor(), myArgumentTypes, myLanguageLevel); if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable()) level = ApplicabilityLevel.NOT_APPLICABLE; return level; } diff --git a/java/openapi/src/com/intellij/psi/util/PsiSuperMethodUtil.java b/java/openapi/src/com/intellij/psi/util/PsiSuperMethodUtil.java index 9646bb12fdb9..0de28052cc6e 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiSuperMethodUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiSuperMethodUtil.java @@ -20,6 +20,7 @@ import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import java.util.List; import java.util.Set; public class PsiSuperMethodUtil { @@ -70,7 +71,9 @@ public class PsiSuperMethodUtil { public static boolean isSuperMethod(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) { HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature(); - for (HierarchicalMethodSignature supsig : signature.getSuperSignatures()) { + List superSignatures = signature.getSuperSignatures(); + for (int i = 0, superSignaturesSize = superSignatures.size(); i < superSignaturesSize; i++) { + HierarchicalMethodSignature supsig = superSignatures.get(i); PsiMethod supsigme = supsig.getMethod(); if (superMethod.equals(supsigme) || isSuperMethod(supsigme, superMethod)) return true; } diff --git a/java/openapi/src/com/intellij/psi/util/PsiUtil.java b/java/openapi/src/com/intellij/psi/util/PsiUtil.java index 1019f791774e..0ce698ec2495 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiUtil.java @@ -190,26 +190,29 @@ public final class PsiUtil extends PsiUtilBase { PsiElement blockSoFar = null; while (element != null) { // variable can be defined in for loop initializer - if (element instanceof PsiCodeBlock || element instanceof PsiForStatement || element instanceof PsiForeachStatement) { - blockSoFar = element; - } PsiElement parent = element.getParent(); - if (parent instanceof PsiMethod - && parent.getParent() instanceof PsiClass - && !isLocalOrAnonymousClass((PsiClass)parent.getParent())) - break; - if (parent instanceof PsiClassInitializer && !(parent.getParent() instanceof PsiAnonymousClass)) break; - if (parent instanceof PsiField && ((PsiField) parent).getInitializer() == element) { - blockSoFar = element; - } - if (parent instanceof PsiClassLevelDeclarationStatement) { - parent = parent.getParent(); - } - if (element instanceof PsiClass && !isLocalOrAnonymousClass((PsiClass)element)) { - break; - } - if (element instanceof PsiFile && PsiUtilBase.getTemplateLanguageFile(element) != null) { - return element; + if (!(parent instanceof PsiExpression)) { + if (element instanceof PsiCodeBlock || element instanceof PsiForStatement || element instanceof PsiForeachStatement) { + blockSoFar = element; + } + + if (parent instanceof PsiMethod + && parent.getParent() instanceof PsiClass + && !isLocalOrAnonymousClass((PsiClass)parent.getParent())) + break; + if (parent instanceof PsiClassInitializer && !(parent.getParent() instanceof PsiAnonymousClass)) break; + if (parent instanceof PsiField && ((PsiField) parent).getInitializer() == element) { + blockSoFar = element; + } + if (parent instanceof PsiClassLevelDeclarationStatement) { + parent = parent.getParent(); + } + if (element instanceof PsiClass && !isLocalOrAnonymousClass((PsiClass)element)) { + break; + } + if (element instanceof PsiFile && PsiUtilBase.getTemplateLanguageFile(element) != null) { + return element; + } } if (element == scope) break; element = parent; diff --git a/platform/lang-api/src/com/intellij/psi/stubs/StubBase.java b/platform/lang-api/src/com/intellij/psi/stubs/StubBase.java index ace05ca8492d..8a5255bd0c22 100644 --- a/platform/lang-api/src/com/intellij/psi/stubs/StubBase.java +++ b/platform/lang-api/src/com/intellij/psi/stubs/StubBase.java @@ -123,7 +123,9 @@ public abstract class StubBase extends UserDataHolderBase private int countChildren(final IElementType elementType) { int count = 0; - for (StubElement childStub : getChildrenStubs()) { + List childrenStubs = getChildrenStubs(); + for (int i = 0, childrenStubsSize = childrenStubs.size(); i < childrenStubsSize; i++) { + StubElement childStub = childrenStubs.get(i); if (childStub.getStubType() == elementType) count++; } @@ -132,7 +134,9 @@ public abstract class StubBase extends UserDataHolderBase private int countChildren(final TokenSet types) { int count = 0; - for (StubElement childStub : getChildrenStubs()) { + List childrenStubs = getChildrenStubs(); + for (int i = 0, childrenStubsSize = childrenStubs.size(); i < childrenStubsSize; i++) { + StubElement childStub = childrenStubs.get(i); if (types.contains(childStub.getStubType())) count++; } diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java b/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java index d6ccc12f249a..8c6c16991e0e 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiCacheKey.java @@ -21,9 +21,11 @@ package com.intellij.psi.util; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.UserDataHolderEx; import com.intellij.psi.PsiElement; import com.intellij.util.Function; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; public class PsiCacheKey extends Key> { private final Function myFunction; @@ -34,10 +36,34 @@ public class PsiCacheKey extends Key> { } public final T getValue(H h) { + while (true) { + Pair data = h.getUserData(this); + + final long count = h.getManager().getModificationTracker().getJavaStructureModificationCount(); + if (data == null) { + data = new Pair(count, myFunction.fun(h)); + data = ((UserDataHolderEx)h).putUserDataIfAbsent(this, data); + } + else if (data.getFirst() != count) { + Pair newData = new Pair(count, myFunction.fun(h)); + if (((UserDataHolderEx)h).replace(this, data, newData)) { + data = newData; + } + else { + continue; + } + } + + return data.getSecond(); + } + } + + @Nullable + public final T getCachedValueOrNull(H h) { Pair data = h.getUserData(this); final long count = h.getManager().getModificationTracker().getJavaStructureModificationCount(); if (data == null || data.getFirst() != count) { - h.putUserData(this, data = new Pair(count, myFunction.fun(h))); + return null; } return data.getSecond(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 14f177aee1b7..421341b5e3cf 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -103,7 +103,9 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument()); if (!ApplicationManager.getApplication().isUnitTestMode()) { - assert !ApplicationManager.getApplication().isWriteAccessAllowed() : "Completion should not be invoked inside write action"; + if (ApplicationManager.getApplication().isWriteAccessAllowed()) { + throw new AssertionError("Completion should not be invoked inside write action"); + } } if (editor.isViewer()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 81500a37fa65..5c51cacbda78 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -320,7 +320,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement ApplicationManager.getApplication().assertIsDispatchThread(); if (isOutdated()) return; - if (!myLookup.isShown()) { + if (!myLookup.isShown() && (!isAutopopupCompletion() || !myLookup.isCalculating())) { if (hideAutopopupIfMeaningless()) { return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java index 370c39f68bc3..0c32cfa102bd 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/TypedHandler.java @@ -32,6 +32,7 @@ import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.editor.actionSystem.TypedActionHandler; import com.intellij.openapi.extensions.Extensions; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; @@ -98,26 +99,43 @@ public class TypedHandler implements TypedActionHandler { } static CharFilter.Result getLookupAction(final char charTyped, final LookupImpl lookup) { + final CharFilter.Result filtersDecision = getFiltersDecision(charTyped, lookup); + final LookupElement currentItem = lookup.getCurrentItem(); if (currentItem != null && charTyped != ' ') { - String postfix = lookup.getAdditionalPrefix() + charTyped; - final PrefixMatcher matcher = currentItem.getPrefixMatcher(); - if (matcher.cloneWithPrefix(matcher.getPrefix() + postfix).prefixMatches(currentItem)) { - return CharFilter.Result.ADD_TO_PREFIX; - } - for (final LookupElement element : lookup.getItems()) { - if (element.isPrefixMatched() && element.getPrefixMatcher().cloneWithPrefix(element.getPrefixMatcher().getPrefix() + postfix).prefixMatches(element)) { + if (charTyped != '*' || filtersDecision != CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP) { + String postfix = lookup.getAdditionalPrefix() + charTyped; + final PrefixMatcher matcher = currentItem.getPrefixMatcher(); + if (matcher.cloneWithPrefix(matcher.getPrefix() + postfix).prefixMatches(currentItem)) { return CharFilter.Result.ADD_TO_PREFIX; } + for (final LookupElement element : lookup.getItems()) { + if (element.isPrefixMatched() && + element.getPrefixMatcher().cloneWithPrefix(element.getPrefixMatcher().getPrefix() + postfix).prefixMatches(element)) { + return CharFilter.Result.ADD_TO_PREFIX; + } + } } } - final CharFilter[] filters = Extensions.getExtensions(CharFilter.EP_NAME); - for (final CharFilter extension : filters) { + + if (filtersDecision != null) return filtersDecision; + throw new AssertionError("Typed char not handler by char filter: c=" + charTyped + + "; prefix=" + currentItem + + "; filters=" + Arrays.toString(getFilters())); + } + + @Nullable + private static CharFilter.Result getFiltersDecision(char charTyped, LookupImpl lookup) { + for (final CharFilter extension : getFilters()) { final CharFilter.Result result = extension.acceptChar(charTyped, lookup.getMinPrefixLength() + lookup.getAdditionalPrefix().length(), lookup); if (result != null) { return result; } } - throw new AssertionError("Typed char not handler by char filter: c=" + charTyped + "; prefix=" + currentItem + "; filters=" + Arrays.toString(filters)); + return null; + } + + private static CharFilter[] getFilters() { + return Extensions.getExtensions(CharFilter.EP_NAME); } } diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index de5bdc99cc18..61b6ee393d99 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -47,7 +47,6 @@ import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; @@ -61,6 +60,7 @@ import com.intellij.psi.impl.PsiManagerEx; import com.intellij.testFramework.LightVirtualFile; import com.intellij.ui.SideBorder; import com.intellij.util.FileContentUtil; +import com.intellij.util.ui.AbstractLayoutManager; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; @@ -88,7 +88,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { private final Document myEditorDocument; protected PsiFile myFile; - private final JPanel myPanel = new JPanel(new BorderLayout()); + private final JPanel myPanel = new JPanel(new MyLayout()); private String myTitle; private String myPrompt = "> "; @@ -125,20 +125,17 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { }; myConsoleEditor.setColorsScheme(scheme); myHistoryViewer.setColorsScheme(scheme); - myPanel.add(myHistoryViewer.getComponent(), BorderLayout.CENTER); - myPanel.add(myConsoleEditor.getComponent(), BorderLayout.SOUTH); + myPanel.add(myHistoryViewer.getComponent()); + myPanel.add(myConsoleEditor.getComponent()); setupComponents(); myPanel.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, new TypeSafeDataProviderAdapter(this)); myUpdateQueue = new MergingUpdateQueue("ConsoleUpdateQueue", 300, true, null); Disposer.register(this, myUpdateQueue); - myPanel.addComponentListener(new ComponentAdapter() { + myHistoryViewer.getComponent().addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent e) { - try { - myHistoryViewer.getScrollingModel().disableAnimation(); - updateSizes(true); - } - finally { - myHistoryViewer.getScrollingModel().enableAnimation(); + if (myForceScrollToEnd.getAndSet(false)) { + final JScrollBar scrollBar = myHistoryViewer.getScrollPane().getVerticalScrollBar(); + scrollBar.setValue(scrollBar.getMaximum()); } } @@ -158,8 +155,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { fileManager.closeFile(virtualFile); myFullEditor = null; myPanel.removeAll(); - myPanel.add(myHistoryViewer.getComponent(), BorderLayout.CENTER); - myPanel.add(myConsoleEditor.getComponent(), BorderLayout.SOUTH); + myPanel.add(myHistoryViewer.getComponent()); + myPanel.add(myConsoleEditor.getComponent()); myHistoryViewer.setHorizontalScrollbarVisible(false); } @@ -390,14 +387,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { public boolean shouldScrollHistoryToEnd() { final Rectangle visibleArea = myHistoryViewer.getScrollingModel().getVisibleArea(); - final LogicalPosition pos = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public LogicalPosition compute() { - return myHistoryViewer.xyToLogicalPosition(new Point(visibleArea.x, visibleArea.y + visibleArea.height)); - } - }); - final int lineCount = myHistoryViewer.getDocument().getLineCount(); - return pos.line >= lineCount - 1; + final Dimension contentSize = myHistoryViewer.getContentSize(); + return contentSize.getHeight() - visibleArea.getMaxY() < 2*myHistoryViewer.getLineHeight(); } private void scrollHistoryToEnd() { @@ -470,7 +461,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { myUpdateQueue.queue(new Update("UpdateUi") { public void run() { if (Disposer.isDisposed(LanguageConsoleImpl.this)) return; - updateSizes(myForceScrollToEnd.getAndSet(false)); + updateSizes(); if (myUiUpdateRunnable != null) { ApplicationManager.getApplication().runReadAction(myUiUpdateRunnable); } @@ -478,63 +469,10 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { }); } - private void updateSizes(boolean forceScrollToEnd) { + private void updateSizes() { if (myFullEditor != null) return; - final Dimension panelSize = myPanel.getSize(); - if (panelSize.getHeight() <= 0) return; - final Dimension historySize = myHistoryViewer.getContentSize(); - final Dimension editorSize = myConsoleEditor.getContentSize(); - final Dimension newEditorSize = new Dimension(); - - // deal with width - final int width = Math.max(editorSize.width, historySize.width); - newEditorSize.width = width + myConsoleEditor.getScrollPane().getHorizontalScrollBar().getHeight(); - myConsoleEditor.getSettings().setAdditionalColumnsCount(2 + (width - editorSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, myConsoleEditor)); - myHistoryViewer.getSettings().setAdditionalColumnsCount(2 + (width - historySize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, myHistoryViewer)); - - // deal with height - if (historySize.width == 0) historySize.height = 0; - final int minHistorySize = historySize.height > 0 ? 2 * myHistoryViewer.getLineHeight() + SEPARATOR_THICKNESS : 0; - final int minEditorSize = myConsoleEditor.isViewer()? 0 : myConsoleEditor.getLineHeight(); - final int editorPreferred = myConsoleEditor.isViewer()? 0 : Math.max(minEditorSize, editorSize.height); - final int historyPreferred = Math.max(minHistorySize, historySize.height); - if (panelSize.height < minEditorSize) { - newEditorSize.height = panelSize.height; - } - else if (panelSize.height < editorPreferred) { - newEditorSize.height = panelSize.height - minHistorySize; - } - else if (panelSize.height < editorPreferred + historyPreferred) { - newEditorSize.height = editorPreferred; - } - else { - newEditorSize.height = editorPreferred == 0? 0 : panelSize.height - historyPreferred; - } - final Dimension newHistorySize = new Dimension(width, panelSize.height - newEditorSize.height); - - // apply - boolean changed = false; - final Dimension curEditorSize = myConsoleEditor.getComponent().getPreferredSize(); - if (!curEditorSize.equals(newEditorSize)) { - myConsoleEditor.getComponent().setPreferredSize(newEditorSize); - changed = true; - } - final boolean scrollToEnd; - final Dimension curHistorySize = myHistoryViewer.getComponent().getPreferredSize(); - if (!curHistorySize.equals(newHistorySize) && (curHistorySize.height != 0 || newHistorySize.height != 0)) { - scrollToEnd = forceScrollToEnd || shouldScrollHistoryToEnd(); - myHistoryViewer.getComponent().setPreferredSize(newHistorySize); - changed = true; - } - else scrollToEnd = forceScrollToEnd; - - if (changed) { - // layout immediately - myPanel.doLayout(); - } - if (scrollToEnd) { - scrollHistoryToEnd(); - } + myPanel.revalidate(); + myPanel.repaint(); } public void dispose() { @@ -622,7 +560,6 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { ((PsiManagerEx)prevFile.getManager()).getFileManager().setViewProvider(file, null); } - final FileType type = language.getAssociatedFileType(); @NonNls final String name = getTitle(); final LightVirtualFile newVFile = new LightVirtualFile(name, language, myEditorDocument.getText()); FileDocumentManagerImpl.registerDocument(myEditorDocument, newVFile); @@ -701,4 +638,61 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { }, ModalityState.stateForComponent(console.getComponent())); } } + + private class MyLayout extends AbstractLayoutManager { + @Override + public Dimension preferredLayoutSize(final Container parent) { + return new Dimension(0, 0); + } + + @Override + public void layoutContainer(final Container parent) { + final int componentCount = parent.getComponentCount(); + if (componentCount == 0) return; + final EditorEx history = myHistoryViewer; + final EditorEx editor = componentCount == 2? myConsoleEditor : null; + + if (editor == null) { + parent.getComponent(0).setBounds(parent.getBounds()); + return; + } + + final Dimension panelSize = parent.getSize(); + if (panelSize.getHeight() <= 0) return; + final Dimension historySize = history.getContentSize(); + final Dimension editorSize = editor.getContentSize(); + final Dimension newEditorSize = new Dimension(); + + // deal with width + final int width = Math.max(editorSize.width, historySize.width); + newEditorSize.width = width + editor.getScrollPane().getHorizontalScrollBar().getHeight(); + editor.getSettings().setAdditionalColumnsCount(2 + (width - editorSize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, editor)); + history.getSettings().setAdditionalColumnsCount(2 + (width - historySize.width) / EditorUtil.getSpaceWidth(Font.PLAIN, history)); + + // deal with height + if (historySize.width == 0) historySize.height = 0; + final int minHistorySize = historySize.height > 0 ? 2 * history.getLineHeight() + SEPARATOR_THICKNESS : 0; + final int minEditorSize = editor.isViewer() ? 0 : editor.getLineHeight(); + final int editorPreferred = editor.isViewer() ? 0 : Math.max(minEditorSize, editorSize.height); + final int historyPreferred = Math.max(minHistorySize, historySize.height); + if (panelSize.height < minEditorSize) { + newEditorSize.height = panelSize.height; + } + else if (panelSize.height < editorPreferred) { + newEditorSize.height = panelSize.height - minHistorySize; + } + else if (panelSize.height < editorPreferred + historyPreferred) { + newEditorSize.height = editorPreferred; + } + else { + newEditorSize.height = editorPreferred == 0 ? 0 : panelSize.height - historyPreferred; + } + final Dimension newHistorySize = new Dimension(width, panelSize.height - newEditorSize.height); + + // apply + editor.getComponent().setBounds(0, newHistorySize.height, panelSize.width, newEditorSize.height); + myForceScrollToEnd.compareAndSet(false, shouldScrollHistoryToEnd()); + history.getComponent().setBounds(0, 0, panelSize.width, newHistorySize.height); + } + } } diff --git a/platform/lang-impl/src/com/intellij/execution/filters/TextConsoleBuilderImpl.java b/platform/lang-impl/src/com/intellij/execution/filters/TextConsoleBuilderImpl.java index 30b49a45d29a..773e5201278a 100644 --- a/platform/lang-impl/src/com/intellij/execution/filters/TextConsoleBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/filters/TextConsoleBuilderImpl.java @@ -62,4 +62,19 @@ public class TextConsoleBuilderImpl extends TextConsoleBuilder { myViewer = isViewer; } + protected Project getProject() { + return myProject; + } + + protected GlobalSearchScope getScope() { + return myScope; + } + + protected ArrayList getFilters() { + return myFilters; + } + + protected boolean isViewer() { + return myViewer; + } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleState.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleState.java index ef19d65e6da9..d1fe83536f95 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleState.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleState.java @@ -16,28 +16,15 @@ package com.intellij.execution.impl; -import com.intellij.execution.process.ProcessAdapter; -import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.ui.ConsoleViewContentType; -import com.intellij.execution.ExecutionBundle; -import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; public abstract class ConsoleState { - public static final ConsoleState NOT_STARTED = new ConsoleState(){ - public ConsoleState attachTo(final ConsoleViewImpl console, final ProcessHandler processHandler) { - return new RunningState(console, processHandler); - } - }; - - public ConsoleState dispose() { - return NOT_STARTED; - } + public abstract ConsoleState attachTo(ConsoleViewImpl console, ProcessHandler processHandler); + @NotNull + public abstract ConsoleState dispose(); public boolean isFinished() { return false; @@ -49,50 +36,17 @@ public abstract class ConsoleState { public void sendUserInput(final String input) throws IOException {} - public abstract ConsoleState attachTo(ConsoleViewImpl console, ProcessHandler processHandler); - - private static class RunningState extends ConsoleState { - private final ConsoleViewImpl myConsole; - private final ProcessAdapter myProcessListener = new ProcessAdapter() { - public void onTextAvailable(final ProcessEvent event, final Key outputType) { - myConsole.print(event.getText(), ConsoleViewContentType.getConsoleViewType(outputType)); - } - }; - private final ProcessHandler myProcessHandler; - private final Writer myUserInputWriter; - - public RunningState(final ConsoleViewImpl console, final ProcessHandler processHandler) { - myConsole = console; - myProcessHandler = processHandler; - processHandler.addProcessListener(myProcessListener); - final OutputStream processInput = myProcessHandler.getProcessInput(); - myUserInputWriter = processInput != null ? new OutputStreamWriter(processInput) : null; - } - + public abstract static class NotStartedStated extends ConsoleState { + @NotNull + @Override public ConsoleState dispose() { - if (myProcessHandler != null) { - myProcessHandler.removeProcessListener(myProcessListener); - } - return NOT_STARTED; + // not disposable + return this; } - public boolean isFinished() { - return myProcessHandler == null || myProcessHandler.isProcessTerminated(); - } - - public boolean isRunning() { - return myProcessHandler != null && !myProcessHandler.isProcessTerminated(); - } - - public void sendUserInput(final String input) throws IOException { - if (myUserInputWriter == null) - throw new IOException(ExecutionBundle.message("no.user.process.input.error.message")); - myUserInputWriter.write(input); - myUserInputWriter.flush(); - } - - public ConsoleState attachTo(final ConsoleViewImpl console, final ProcessHandler processHandler) { - return dispose().attachTo(console, processHandler); + @Override + public String toString() { + return "Not started state"; } } } 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 c7527036d028..91b44e999751 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -147,7 +147,8 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo private final DisposedPsiManagerCheck myPsiDisposedCheck; private final boolean isViewer; - private ConsoleState myState = ConsoleState.NOT_STARTED; + private ConsoleState myState; + private Computable myStateForUpdate; private static int getCycleBufferSize() { @@ -366,8 +367,20 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } public ConsoleViewImpl(final Project project, GlobalSearchScope searchScope, boolean viewer, FileType fileType) { + this(project, searchScope, viewer, fileType, + new ConsoleState.NotStartedStated() { + @Override + public ConsoleState attachTo(ConsoleViewImpl console, ProcessHandler processHandler) { + return new ConsoleViewRunningState(console, processHandler, this, true, true); + } + }); + } + + protected ConsoleViewImpl(final Project project, GlobalSearchScope searchScope, boolean viewer, FileType fileType, + @NotNull final ConsoleState initialState) { super(new BorderLayout()); isViewer = viewer; + myState = initialState; myPsiDisposedCheck = new DisposedPsiManagerCheck(project); myProject = project; myFileType = fileType; @@ -1061,7 +1074,10 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } }); - setEditorUpActions(editor); + if (!isViewer) { + setEditorUpActions(editor); + } + return editor; } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewRunningState.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewRunningState.java new file mode 100644 index 000000000000..59773c09ce9f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewRunningState.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.impl; + +import com.intellij.execution.ExecutionBundle; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + + +public class ConsoleViewRunningState extends ConsoleState { + private final ConsoleViewImpl myConsole; + private final ProcessHandler myProcessHandler; + private final ConsoleState myFinishedStated; + private final Writer myUserInputWriter; + + private final ProcessAdapter myProcessListener = new ProcessAdapter() { + public void onTextAvailable(final ProcessEvent event, final Key outputType) { + myConsole.print(event.getText(), ConsoleViewContentType.getConsoleViewType(outputType)); + } + }; + + public ConsoleViewRunningState(final ConsoleViewImpl console, final ProcessHandler processHandler, + final ConsoleState finishedStated, + final boolean attachToStdOut, + final boolean attachToStdIn) { + + myConsole = console; + myProcessHandler = processHandler; + myFinishedStated = finishedStated; + + // attach to process stdout + if (attachToStdOut) { + processHandler.addProcessListener(myProcessListener); + } + + // attach to process stdin + if (attachToStdIn) { + final OutputStream processInput = myProcessHandler.getProcessInput(); + myUserInputWriter = processInput != null ? new OutputStreamWriter(processInput) : null; + } else { + myUserInputWriter = null; + } + } + + @NotNull + public ConsoleState dispose() { + if (myProcessHandler != null) { + myProcessHandler.removeProcessListener(myProcessListener); + } + return myFinishedStated; + } + + public boolean isFinished() { + return myProcessHandler == null || myProcessHandler.isProcessTerminated(); + } + + public boolean isRunning() { + return myProcessHandler != null && !myProcessHandler.isProcessTerminated(); + } + + public void sendUserInput(final String input) throws IOException { + if (myUserInputWriter == null) + throw new IOException(ExecutionBundle.message("no.user.process.input.error.message")); + myUserInputWriter.write(input); + myUserInputWriter.flush(); + } + + public ConsoleState attachTo(final ConsoleViewImpl console, final ProcessHandler processHandler) { + return dispose().attachTo(console, processHandler); + } + + @Override + public String toString() { + return "Running state"; + } +} diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 8946f4cb1d7c..3c0f52c9ea64 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -468,6 +468,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec add(myReplacementPane, BorderLayout.SOUTH); myReplaceButton = new JButton("Replace"); + myReplaceButton.setFocusable(false); myReplaceButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { @@ -477,6 +478,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myReplaceButton.setMnemonic('p'); myReplaceAllButton = new JButton("Replace all"); + myReplaceAllButton.setFocusable(false); myReplaceAllButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { @@ -486,7 +488,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myReplaceAllButton.setMnemonic('a'); myExcludeButton = new JButton(""); - + myExcludeButton.setFocusable(false); myExcludeButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java index cba1b5543527..353068a6adf7 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java @@ -335,7 +335,7 @@ public class SearchResults { if (searchResult.getPrimaryRange().intersects(oldCursorRange)) { mayBeOldCursor = searchResult; } - if (searchResult.getPrimaryRange().equals(oldCursorRange)) { + if (searchResult.getPrimaryRange().getStartOffset() == oldCursorRange.getStartOffset()) { break; } } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java index 4daba937a186..33c059978838 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java @@ -25,6 +25,7 @@ import com.intellij.ide.plugins.cl.PluginClassLoader; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.components.ExportableComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -763,7 +764,9 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements Expo parentDir = topDir; } else { - if (topDir instanceof NewVirtualFile) { + final ApplicationEx app = (ApplicationEx)ApplicationManager.getApplication(); + if (topDir instanceof NewVirtualFile && (!app.holdsReadLock() || app.isDispatchThread())) { + // need dispatch-thread-check because sync refresh in non-awt thread may cause deadlock parentDir = ((NewVirtualFile)topDir).refreshAndFindChild(myDefaultTemplatesDir); } else { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java index 1d7bd30a3eaa..c31486f261e7 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java @@ -41,8 +41,10 @@ import com.intellij.psi.impl.file.PsiDirectoryFactory; import com.intellij.ui.LayeredIcon; import com.intellij.ui.RowIcon; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.IconUtil; import com.intellij.util.Icons; import com.intellij.util.PathUtil; +import com.intellij.util.PlatformUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -117,14 +119,26 @@ public class PsiDirectoryNode extends BasePsiNode implements Navig private void setupIcon(PresentationData data, PsiDirectory psiDirectory) { final VirtualFile virtualFile = psiDirectory.getVirtualFile(); - for (final IconProvider provider : Extensions.getExtensions(IconProvider.EXTENSION_POINT_NAME)) { - final Icon openIcon = provider.getIcon(psiDirectory, Iconable.ICON_FLAG_OPEN); + if (PlatformUtils.isCidr()) { + final Icon openIcon = IconUtil.getIcon(virtualFile, Iconable.ICON_FLAG_OPEN, myProject); if (openIcon != null) { - final Icon closedIcon = provider.getIcon(psiDirectory, Iconable.ICON_FLAG_CLOSED); + final Icon closedIcon = IconUtil.getIcon(virtualFile, Iconable.ICON_FLAG_CLOSED, myProject); if (closedIcon != null) { data.setOpenIcon(patchIcon(openIcon, virtualFile)); data.setClosedIcon(patchIcon(closedIcon, virtualFile)); - return; + } + } + } + else { + for (final IconProvider provider : Extensions.getExtensions(IconProvider.EXTENSION_POINT_NAME)) { + final Icon openIcon = provider.getIcon(psiDirectory, Iconable.ICON_FLAG_OPEN); + if (openIcon != null) { + final Icon closedIcon = provider.getIcon(psiDirectory, Iconable.ICON_FLAG_CLOSED); + if (closedIcon != null) { + data.setOpenIcon(patchIcon(openIcon, virtualFile)); + data.setClosedIcon(patchIcon(closedIcon, virtualFile)); + return; + } } } } diff --git a/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java b/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java index f74e28777500..a458b57396e3 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/util/DeleteHandler.java @@ -26,6 +26,7 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.DumbService; @@ -145,7 +146,7 @@ public class DeleteHandler { } if (safeDeleteApplicable && dumb) { - warningMessage += "\n\nWarning:\n Safe delete is not available while IntelliJ IDEA updates indices,\n no usages will be checked."; + warningMessage += "\n\nWarning:\n Safe delete is not available while " + ApplicationNamesInfo.getInstance().getFullProductName() + " updates indices,\n no usages will be checked."; } int result = Messages.showDialog(project, warningMessage, IdeBundle.message("title.delete"), diff --git a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java index e4cdd992ce52..2dfaaccb732f 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java @@ -19,10 +19,12 @@ package com.intellij.openapi.fileTypes.impl; import com.intellij.ide.FileIconProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.impl.ElementBase; import com.intellij.ui.DeferredIconImpl; +import com.intellij.ui.mac.foundation.Foundation; import com.intellij.util.Function; import com.intellij.util.ui.update.ComparableObject; import org.jetbrains.annotations.Nullable; @@ -43,10 +45,15 @@ public class NativeFileIconProvider implements FileIconProvider { private static final Ext NO_EXT = new Ext(null); - public Icon getIcon(VirtualFile file, int flags, @Nullable Project project) { + private static final Ext OPEN_DIR = new Ext(null, Iconable.ICON_FLAG_OPEN); + private static final Ext CLOSED_DIR = new Ext(null, Iconable.ICON_FLAG_CLOSED); + + private static final Icon DIR_OPEN_ICON = UIManager.getDefaults().getIcon( "Tree.openIcon" ); + + public Icon getIcon(VirtualFile file, final int flags, @Nullable Project project) { if (!isNativeFileType(file)) return null; - final Ext ext = file.getExtension() != null ? new Ext(file.getExtension()) : NO_EXT; + final Ext ext = getExtension(file, flags); final String filePath = file.getPath(); Icon icon; @@ -70,7 +77,13 @@ public class NativeFileIconProvider implements FileIconProvider { Icon icon; try { // VM will ensure lock to init -static final field--, note we should have no read access here, to avoid deadlock with EDT needed to init component assert SwingComponentHolder.ourFileChooser != null || !ApplicationManager.getApplication().isReadAccessAllowed(); - icon = SwingComponentHolder.ourFileChooser.getIcon(f); + + if (SystemInfo.isMac && virtualFile.isDirectory() && (flags & Iconable.ICON_FLAG_OPEN) == Iconable.ICON_FLAG_OPEN) { + icon = Foundation.isPackageAtPath(f) ? SwingComponentHolder.ourFileChooser.getIcon(f) : DIR_OPEN_ICON; + } + else { + icon = SwingComponentHolder.ourFileChooser.getIcon(f); + } } catch (Exception e) { // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4854174 return null; @@ -90,6 +103,18 @@ public class NativeFileIconProvider implements FileIconProvider { }); } + private static Ext getExtension(final VirtualFile file, final int flags) { + if (file.isDirectory()) { + if (file.getExtension() == null) { + return flags == Iconable.ICON_FLAG_OPEN ? OPEN_DIR : CLOSED_DIR; + } else { + return new Ext(file.getExtension(), flags); + } + } + + return file.getExtension() != null ? new Ext(file.getExtension()) : NO_EXT; + } + static class SwingComponentHolder { private static final JFileChooser ourFileChooser = new JFileChooser(); } @@ -99,13 +124,16 @@ public class NativeFileIconProvider implements FileIconProvider { } private static class Ext extends ComparableObject.Impl { - private final Object[] myText; private Ext(@Nullable String text) { myText = new Object[] {text}; } + private Ext(@Nullable String text, final int flags) { + myText = new Object[] {text, flags}; + } + public Object[] getEqualityObjects() { return myText; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java index 52c2ca83c492..58c8201cdb57 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/IndexCacheManagerImpl.java @@ -111,12 +111,13 @@ public class IndexCacheManagerImpl implements CacheManager{ if (vFiles.isEmpty()) return true; final ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex(); + final boolean globalScope = scope.isSearchOutsideRootModel(); final Processor virtualFileProcessor = new ReadActionProcessor() { @Override public boolean processInReadAction(VirtualFile virtualFile) { LOG.assertTrue(virtualFile.isValid()); - if (virtualFile.isValid() && scope.contains(virtualFile) && shouldBeFound(virtualFile, index)) { + if (virtualFile.isValid() && scope.contains(virtualFile) && (globalScope || shouldBeFound(virtualFile, index))) { final PsiFile psiFile = myPsiManager.findFile(virtualFile); return psiFile == null || psiFileProcessor.process(psiFile); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index aa180d5fae4a..b6d1302fb081 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.search; import com.intellij.codeInsight.CommentUtil; import com.intellij.concurrency.JobUtil; -import com.intellij.ide.todo.TodoConfiguration; import com.intellij.ide.todo.TodoIndexPatternProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; @@ -44,6 +43,7 @@ import com.intellij.psi.search.searches.IndexPatternSearch; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; +import com.intellij.util.SmartList; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.MultiMap; import com.intellij.util.indexing.FileBasedIndex; @@ -489,8 +489,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { refProcessor = new Processor() { @Override public boolean process(PsiReference psiReference) { - if (!myProcessor.process(psiReference)) return false; - return another.refProcessor.process(psiReference); + return myProcessor.process(psiReference) && another.refProcessor.process(psiReference); } }; } @@ -571,7 +570,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { progress.setText(PsiBundle.message("psi.scanning.files.progress")); } - final MultiMap candidateFiles = collectFiles(singles); + final MultiMap candidateFiles = collectFiles(singles, progress); if (candidateFiles.isEmpty()) { return true; @@ -593,7 +592,8 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { final VirtualFile vfile = psiRoot.getContainingFile().getVirtualFile(); for (final RequestWithProcessor singleRequest : candidateFiles.get(vfile)) { StringSearcher searcher = searchers.get(singleRequest); - if (!LowLevelSearchUtil.processElementsContainingWordInElement(adaptProcessor(singleRequest.request, singleRequest.refProcessor), psiRoot, searcher, false, progress)) { + TextOccurenceProcessor adapted = adaptProcessor(singleRequest.request, singleRequest.refProcessor); + if (!LowLevelSearchUtil.processElementsContainingWordInElement(adapted, psiRoot, searcher, false, progress)) { return false; } } @@ -616,9 +616,10 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { }; } - private MultiMap collectFiles(MultiMap, RequestWithProcessor> singles) { + private MultiMap collectFiles(MultiMap, RequestWithProcessor> singles, + ProgressIndicator progress) { final ProjectFileIndex index = ProjectRootManager.getInstance(myManager.getProject()).getFileIndex(); - final MultiMap result = new MultiMap(); + final MultiMap result = createMultiMap(); for (Set key : singles.keySet()) { if (key.isEmpty()) { continue; @@ -631,7 +632,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { boolean first = true; for (IdIndexEntry entry : key) { - final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope); + final MultiMap local = findFilesWithIndexEntry(entry, index, data, commonScope, progress); if (first) { intersection = local; first = false; @@ -648,6 +649,15 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { return result; } + private static MultiMap createMultiMap() { + return new MultiMap(){ + @Override + protected Collection createCollection() { + return new SmartList(); // usually there is just one request + } + }; + } + private static GlobalSearchScope uniteScopes(Collection requests) { GlobalSearchScope commonScope = null; for (RequestWithProcessor r : requests) { @@ -659,29 +669,31 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { } private static MultiMap findFilesWithIndexEntry(final IdIndexEntry entry, - final ProjectFileIndex index, - final Collection data, - final GlobalSearchScope commonScope) { - final MultiMap local = new MultiMap(); + final ProjectFileIndex index, + final Collection data, + final GlobalSearchScope commonScope, + final ProgressIndicator progress) { + final MultiMap local = createMultiMap(); + final boolean inRootsOnly = !commonScope.isSearchOutsideRootModel(); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { - ProgressManager.checkCanceled(); + if (progress != null) progress.checkCanceled(); FileBasedIndex.getInstance().processValues(IdIndex.NAME, entry, null, new FileBasedIndex.ValueProcessor() { - public boolean process(VirtualFile file, Integer value) { - ProgressManager.checkCanceled(); - if (!IndexCacheManagerImpl.shouldBeFound(file, index)) { + public boolean process(VirtualFile file, Integer value) { + if (progress != null) progress.checkCanceled(); + if (inRootsOnly && !IndexCacheManagerImpl.shouldBeFound(file, index)) { + return true; + } + int mask = value.intValue(); + for (RequestWithProcessor single : data) { + final PsiSearchRequest request = single.request; + if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) { + local.putValue(file, single); + } + } return true; } - int mask = value.intValue(); - for (RequestWithProcessor single : data) { - final PsiSearchRequest request = single.request; - if ((mask & request.searchContext) != 0 && ((GlobalSearchScope)request.searchScope).contains(file)) { - local.putValue(file, single); - } - } - return true; - } - }, commonScope); + }, commonScope); } }); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java index d0a32f6b3d22..423e4c1abdbb 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/ResolveCache.java @@ -17,7 +17,10 @@ package com.intellij.psi.impl.source.resolve; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; @@ -26,13 +29,11 @@ import com.intellij.psi.impl.PsiManagerEx; import com.intellij.reference.SoftReference; import com.intellij.util.containers.ConcurrentWeakHashMap; import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; import java.lang.ref.Reference; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; @@ -48,6 +49,7 @@ public class ResolveCache { private final PsiManagerEx myManager; private final List myRunnablesToRunOnDropCaches = ContainerUtil.createEmptyCOWList(); + private final RecursionGuard myGuard = RecursionManager.createGuard("resolveCache"); public interface AbstractResolver { TResult resolve(TRef ref, boolean incompleteCode); @@ -88,8 +90,6 @@ public class ResolveCache { for (Runnable r : myRunnablesToRunOnDropCaches) { r.run(); } - - blockedElements.remove(); } public void addRunnableToRunOnDropCaches(Runnable r) { @@ -97,32 +97,33 @@ public class ResolveCache { } @Nullable - private TResult resolve(TRef ref, - AbstractResolver resolver, - Map>[] maps, + private TResult resolve(final TRef ref, + final AbstractResolver resolver, + final Map>[] maps, boolean needToPreventRecursion, - boolean incompleteCode) { + final boolean incompleteCode) { ProgressManager.checkCanceled(); - int clearCountOnStart = myClearCount.intValue(); + final int clearCountOnStart = myClearCount.intValue(); - boolean physical = ref.getElement().isPhysical(); - TResult result = getCached(ref, maps, physical, incompleteCode); + final boolean physical = ref.getElement().isPhysical(); + final TResult result = getCached(ref, maps, physical, incompleteCode); if (result != null) { return result; } - if (needToPreventRecursion && !lockElement(ref)) return null; - try { - result = resolver.resolve(ref, incompleteCode); - } - finally { - if (needToPreventRecursion) { - unlockElement(ref); + Computable computable = new Computable() { + @Override + public TResult compute() { + RecursionGuard.StackStamp stamp = myGuard.markStack(); + TResult result = resolver.resolve(ref, incompleteCode); + if (stamp.mayCacheNow()) { + cache(ref, result, maps, physical, incompleteCode, clearCountOnStart); + } + return result; } - } - cache(ref, result, maps, physical, incompleteCode, clearCountOnStart); - return result; + }; + return needToPreventRecursion ? myGuard.doPreventingRecursion(ref, computable) : computable.compute(); } public ResolveResult[] resolveWithCaching(T ref, @@ -140,23 +141,6 @@ public class ResolveCache { return resolve(ref, resolver, myResolveMaps, needToPreventRecursion, incompleteCode); } - private static final ThreadLocal> blockedElements = new ThreadLocal>() { - @Override - protected Set initialValue() { - return new THashSet(); - } - }; - - private static boolean lockElement(PsiReference ref) { - Set blocked = blockedElements.get(); - return blocked.add(ref.getElement()); - } - - private static void unlockElement(PsiReference ref) { - Set blocked = blockedElements.get(); - blocked.remove(ref.getElement()); - } - private static int getIndex(boolean physical, boolean incompleteCode){ return (physical ? 0 : 1) << 1 | (incompleteCode ? 1 : 0); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesProcessor.java index 0979ccb9a3dd..7fe6e08c5917 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesProcessor.java @@ -18,6 +18,7 @@ package com.intellij.refactoring.move.moveFilesOrDirectories; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.paths.PsiDynaReference; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiDirectory; @@ -172,14 +173,14 @@ public class MoveFilesOrDirectoriesProcessor extends BaseRefactoringProcessor { } }); - retargetUsages(usages, oldToNewMap); - // fix references in moved files to outer files for (PsiFile movedFile : movedFiles) { MoveFileHandler.forElement(movedFile).updateMovedFile(movedFile); FileReferenceContextUtil.decodeFileReferences(movedFile); } + retargetUsages(usages, oldToNewMap); + // Perform CVS "add", "remove" commands on moved files. if (myMoveCallback != null) { @@ -226,7 +227,7 @@ public class MoveFilesOrDirectoriesProcessor extends BaseRefactoringProcessor { final MyUsageInfo info = (MyUsageInfo)usageInfo; final PsiElement element = myElementsToMove[info.myIndex]; - if (info.getReference() instanceof FileReference) { + if (info.getReference() instanceof FileReference || info.getReference() instanceof PsiDynaReference) { final PsiElement usageElement = info.getElement(); if (usageElement != null) { final PsiFile usageFile = usageElement.getContainingFile(); diff --git a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java index 909dbaa4ce47..0e44cf18b46e 100644 --- a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java @@ -21,18 +21,14 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.LowMemoryWatcher; +import com.intellij.openapi.util.*; import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.impl.source.tree.LazyParseableElement; import com.intellij.psi.util.PsiModificationTracker; -import com.intellij.util.ConcurrencyUtil; -import com.intellij.util.NullableFunction; -import com.intellij.util.Processor; -import com.intellij.util.SmartList; +import com.intellij.util.*; import com.intellij.util.containers.ConcurrentWeakHashMap; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; @@ -181,7 +177,7 @@ public class SemServiceImpl extends SemService{ } @Nullable - public List getSemElements(SemKey key, @NotNull PsiElement psi) { + public List getSemElements(final SemKey key, @NotNull final PsiElement psi) { final PsiElement root = getRootElement(psi); if (root == null) { return Collections.emptyList(); @@ -192,21 +188,24 @@ public class SemServiceImpl extends SemService{ return cached; } + RecursionGuard.StackStamp stamp = RecursionManager.createGuard("semService").markStack(); + + LinkedHashSet result = new LinkedHashSet(); final Map> map = new THashMap>(); - LinkedHashSet result = null; for (final SemKey each : myInheritors.get(key)) { List list = createSemElements(each, psi); map.put(each, list); - if (!list.isEmpty()) { - if (result == null) result = new LinkedHashSet(); - result.addAll((List)list); + result.addAll((List)list); + } + + if (stamp.mayCacheNow()) { + final ConcurrentMap> persistent = cacheOrGetMap(psi, root); + for (SemKey semKey : map.keySet()) { + persistent.putIfAbsent(semKey, map.get(semKey)); } } - final ConcurrentMap> persistent = cacheOrGetMap(psi, root); - for (SemKey semKey : map.keySet()) { - persistent.putIfAbsent(semKey, map.get(semKey)); - } - return result == null ? Collections.emptyList() : new ArrayList(result); + + return new ArrayList(result); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java index b741c10630e8..4d4cbcc8f7b9 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndex.java @@ -977,7 +977,11 @@ public class FileBasedIndex implements ApplicationComponent { public void scheduleRebuild(final ID indexId, final Throwable e) { LOG.info(e); requestRebuild(indexId); - checkRebuild(indexId, false); + try { + checkRebuild(indexId, false); + } + catch (ProcessCanceledException ignored) { + } } private void checkRebuild(final ID indexId, final boolean cleanupOnly) { diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index f4796f4d1141..e7b17eae0e2b 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -234,6 +234,14 @@ public class Messages { return showDialog(message, title, new String[]{YES_BUTTON, NO_BUTTON}, 0, icon); } + public static int showYesNoDialog(Component parent, String message, String title, int defaultOptionIndex, int focusedOptionIndex, Icon icon) { + return showDialog(parent, message, title, new String[]{YES_BUTTON, NO_BUTTON}, defaultOptionIndex, focusedOptionIndex, icon); + } + + public static int showYesNoDialog(Project project, String message, String title, int defaultOptionIndex, int focusedOptionIndex, Icon icon) { + return showDialog(project, message, title, new String[]{YES_BUTTON, NO_BUTTON}, defaultOptionIndex, focusedOptionIndex, icon); + } + public static int showOkCancelDialog(Project project, String message, String title, Icon icon) { return showDialog(project, message, title, new String[]{OK_BUTTON, CANCEL_BUTTON}, 0, icon); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/TreeComboBox.java b/platform/platform-api/src/com/intellij/openapi/ui/TreeComboBox.java index ac05c293125e..08a7a62cbe73 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/TreeComboBox.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/TreeComboBox.java @@ -43,6 +43,7 @@ public class TreeComboBox extends JComboBox { final static int INDENT = UIUtil.getTreeLeftChildIndent(); private TreeModel myTreeModel; private String myDefaultText; + private boolean myShowRootNode; public TreeComboBox(@NotNull final TreeModel model) { this(model, true); @@ -55,6 +56,7 @@ public class TreeComboBox extends JComboBox { public TreeComboBox(@NotNull final TreeModel model, final boolean showRootNode, final String defaultText) { myTreeModel = model; myDefaultText = defaultText; + myShowRootNode = showRootNode; setModel(new TreeModelWrapper(myTreeModel, showRootNode)); setRenderer(new TreeListCellRenderer(this, showRootNode, defaultText)); if (SystemInfo.isMac && UIUtil.isUnderAquaLookAndFeel()) setMaximumRowCount(25); @@ -69,6 +71,12 @@ public class TreeComboBox extends JComboBox { return myTreeModel; } + public JTree createFakeTree() { + final JTree tree = new JTree(getTreeModel()); + tree.setRootVisible(myShowRootNode); + return tree; + } + private static class TreeListCellRenderer extends SimpleColoredRenderer implements ListCellRenderer { private static final Border SELECTION_PAINTER = (Border)UIManager.get("MenuItem.selectedBackgroundPainter"); diff --git a/platform/platform-api/src/com/intellij/openapi/util/RecursionGuard.java b/platform/platform-api/src/com/intellij/openapi/util/RecursionGuard.java new file mode 100644 index 000000000000..bcfa3415ced4 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/util/RecursionGuard.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** +* @author peter +*/ +public interface RecursionGuard { + @Nullable + T doPreventingRecursion(Object key, Computable computation); + + StackStamp markStack(); + + List currentStack(); + + void prohibitResultCaching(Object since); + + interface StackStamp { + boolean mayCacheNow(); + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/util/RecursionManager.java b/platform/platform-api/src/com/intellij/openapi/util/RecursionManager.java new file mode 100644 index 000000000000..ce4d7ce92d24 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/util/RecursionManager.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.util; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author peter + */ +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) +public class RecursionManager { + private static final ThreadLocal ourStamp = new ThreadLocal() { + @Override + protected Integer initialValue() { + return 0; + } + }; + private static final ThreadLocal, Integer>> ourProgress = new ThreadLocal, Integer>>() { + @Override + protected LinkedHashMap, Integer> initialValue() { + return new LinkedHashMap, Integer>(); + } + }; + + public static RecursionGuard createGuard(final String id) { + return new RecursionGuard() { + @Override + public T doPreventingRecursion(Object key, Computable computation) { + Pair realKey = Pair.create(id, key); + LinkedHashMap, Integer> progressMap = ourProgress.get(); + if (progressMap.containsKey(realKey)) { + prohibitResultCaching(key); + + return null; + } + + progressMap.put(realKey, ourStamp.get()); + + try { + return computation.compute(); + } + finally { + ourStamp.set(progressMap.remove(realKey)); + } + } + + @Override + public StackStamp markStack() { + final Integer stamp = ourStamp.get(); + return new StackStamp() { + @Override + public boolean mayCacheNow() { + return Comparing.equal(stamp, ourStamp.get()); + } + }; + } + + @Override + public List currentStack() { + ArrayList result = new ArrayList(); + LinkedHashMap, Integer> map = ourProgress.get(); + for (Pair pair : map.keySet()) { + if (pair.first == id) { + result.add(pair.second); + } + } + return result; + } + + @Override + public void prohibitResultCaching(Object since) { + int stamp = ourStamp.get() + 1; + ourStamp.set(stamp); + + boolean inLoop = false; + for (Map.Entry, Integer> entry: ourProgress.get().entrySet()) { + if (inLoop) { + entry.setValue(stamp); + } + else if (entry.getKey().first.equals(id) && entry.getKey().second.equals(since)) { + inLoop = true; + } + } + } + }; + } + +} diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java index eb099fce193a..8070ec8d2236 100644 --- a/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java +++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredComponent.java @@ -383,7 +383,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { g.fillRect(0, 0, icon.getIconWidth() + myIpad.left + myIconTextGap, getHeight()); } - icon.paintIcon(this, g, myIpad.left, (getHeight() - icon.getIconHeight()) / 2); + paintIcon(g, icon); xOffset += myIpad.left + icon.getIconWidth() + myIconTextGap; } @@ -405,6 +405,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible { final List searchMatches = new ArrayList(); // Paint text + applyAdditionalHints(g); UIUtil.applyRenderingHints(g); for (int i = 0; i < myFragments.size(); i++) { final SimpleTextAttributes attributes = myAttributes.get(i); @@ -497,6 +498,13 @@ public class SimpleColoredComponent extends JComponent implements Accessible { } } + protected void paintIcon(Graphics g, Icon icon) { + icon.paintIcon(this, g, myIpad.left, (getHeight() - icon.getIconHeight()) / 2); + } + + protected void applyAdditionalHints(final Graphics g) { + } + @Override public int getBaseline(int width, int height) { super.getBaseline(width, height); diff --git a/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java b/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java index 65e97cca94fc..1cfc6661df48 100644 --- a/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java +++ b/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java @@ -19,6 +19,8 @@ import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Application; @@ -29,12 +31,20 @@ import org.jetbrains.annotations.NotNull; import javax.swing.FocusManager; import javax.swing.*; +import javax.swing.event.CaretListener; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentListener; import javax.swing.plaf.basic.BasicPopupMenuUI; +import javax.swing.text.AbstractDocument; +import javax.swing.text.Document; import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.dnd.DragGestureRecognizer; +import java.awt.event.AWTEventListener; +import java.awt.event.HierarchyEvent; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.EventListener; /** * This class listens event from ProjectManager and cleanup some @@ -181,6 +191,60 @@ public final class SwingCleanuper implements ApplicationComponent{ } } ); + + Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { + @Override + public void eventDispatched(AWTEvent event) { + if (!SystemInfo.isMac || !Registry.is("jvmbugfix.mac.caccessibleLeak")) return; + + HierarchyEvent he = (HierarchyEvent)event; + if ((he.getChangeFlags() & (HierarchyEvent.SHOWING_CHANGED)) > 0) { + if (he.getComponent() != null && !he.getComponent().isShowing()) { + Component c = he.getComponent(); + if (c instanceof JTextComponent) { + JTextComponent textComponent = (JTextComponent)c; + + CaretListener[] carets = textComponent.getListeners(CaretListener.class); + for (CaretListener each : carets) { + if (isCAccessibleListener(each)) { + textComponent.removeCaretListener(each); + } + } + + Document document = textComponent.getDocument(); + if (document instanceof AbstractDocument) { + DocumentListener[] documentListeners = ((AbstractDocument)document).getDocumentListeners(); + for (DocumentListener each : documentListeners) { + if (isCAccessibleListener(each)) { + document.removeDocumentListener(each); + } + } + } + } else if (c instanceof JProgressBar) { + JProgressBar bar = (JProgressBar)c; + ChangeListener[] changeListeners = bar.getChangeListeners(); + for (ChangeListener each : changeListeners) { + if (isCAccessibleListener(each)) { + bar.removeChangeListener(each); + } + } + } else if (c instanceof JSlider) { + JSlider slider = (JSlider)c; + ChangeListener[] changeListeners = slider.getChangeListeners(); + for (ChangeListener each : changeListeners) { + if (isCAccessibleListener(each)) { + slider.removeChangeListener(each); + } + } + } + } + } + } + }, HierarchyEvent.HIERARCHY_EVENT_MASK); + } + + private boolean isCAccessibleListener(EventListener listener) { + return listener != null && listener.toString().contains("AXTextChangeNotifier"); } private static void resetField(Object object, Class type, @NonNls String name) { diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextField.java b/platform/platform-impl/src/com/intellij/ui/EditorTextField.java index 22dae7d783a5..6e217d4d1beb 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextField.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextField.java @@ -562,6 +562,9 @@ public class EditorTextField extends NonOpaquePanel implements DocumentListener, } public Dimension getPreferredSize() { + if (super.isPreferredSizeSet()) { + return super.getPreferredSize(); + } if (myEditor != null) { final Dimension preferredSize = new Dimension(myEditor.getComponent().getPreferredSize()); final Insets insets = getInsets(); diff --git a/platform/platform-impl/src/com/intellij/util/CachedValueBase.java b/platform/platform-impl/src/com/intellij/util/CachedValueBase.java index 8caa460fb5e1..d8d71dbbef68 100644 --- a/platform/platform-impl/src/com/intellij/util/CachedValueBase.java +++ b/platform/platform-impl/src/com/intellij/util/CachedValueBase.java @@ -19,9 +19,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.ModificationTracker; -import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.*; import com.intellij.psi.util.CachedValueProvider; import com.intellij.reference.SoftReference; import gnu.trove.TLongArrayList; @@ -76,9 +74,6 @@ public abstract class CachedValueBase { myData = null; } - public void setDataLocked(boolean value) { - } - public boolean hasUpToDateValue() { return getUpToDateOrNull(false) != null; } @@ -186,10 +181,15 @@ public abstract class CachedValueBase { return value == ObjectUtils.NULL ? null : value; } + RecursionGuard.StackStamp stamp = RecursionManager.createGuard("cachedValue").markStack(); + // compute outside lock to avoid deadlock CachedValueProvider.Result result = doCompute(param); - return setValue(result); + if (stamp.mayCacheNow()) { + return setValue(result); + } + return result == null ? null : result.getValue(); } protected abstract

CachedValueProvider.Result doCompute(P param); diff --git a/platform/platform-resources-en/src/messages/XmlErrorMessages.properties b/platform/platform-resources-en/src/messages/XmlErrorMessages.properties index c88534f96060..7a375eae8ebe 100644 --- a/platform/platform-resources-en/src/messages/XmlErrorMessages.properties +++ b/platform/platform-resources-en/src/messages/XmlErrorMessages.properties @@ -11,7 +11,7 @@ element.is.not.allowed.here=Element {0} is not allowed here element.must.be.declared=Element {0} must be declared element.doesnt.have.required.attribute=Element {0} doesn''t have required attribute {1} wrong.root.element=Wrong root element -unbound.namespace=Namespace {0} is not bound +unbound.namespace=Namespace ''{0}'' is not bound unbound.namespace.no.param=Namespace is not bound attribute.is.not.allowed.here=Attribute {0} is not allowed here empty.attribute.is.not.allowed=Empty attribute {0} is not allowed diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 474e36f5ba89..64f450c97174 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -123,3 +123,5 @@ navbar.newpopup=true inspectionGadgets.telemetry.enabled=false minuscule.humps.matching=false minuscule.humps.matching.description=Camel Case without holding Shift in Ctrl+N/Ctrl+Shift+N etc + +jvmbugfix.mac.caccessibleLeak=true diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 5fb1d1d608aa..cde3e2a62c58 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -591,7 +591,6 @@ - diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 068d692e20fa..e9715e61c764 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -157,7 +157,8 @@ - + diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/SMTestRunnerConnectionUtil.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/SMTestRunnerConnectionUtil.java index fa6ec89e36a5..926310c5741c 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/SMTestRunnerConnectionUtil.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/SMTestRunnerConnectionUtil.java @@ -92,6 +92,7 @@ public class SMTestRunnerConnectionUtil { @Override public void attachToProcess(final ProcessHandler processHandler) { // attach listeners + super.attachToProcess(processHandler); attachEventsProcessors(consoleProperties, getResultsViewer(), getResultsViewer().getStatisticsPane(), processHandler, testFrameworkName); @@ -177,9 +178,9 @@ public class SMTestRunnerConnectionUtil { final ProcessHandler processHandler, @NotNull final String testFrameworkName) { //build messages consumer - final OutputToGeneralTestEventsConverter outputConsumer = consoleProperties instanceof SMCustomMessagesParsing ? - ((SMCustomMessagesParsing)consoleProperties).createTestEventsConverter(testFrameworkName) : - new OutputToGeneralTestEventsConverter(testFrameworkName); + final OutputToGeneralTestEventsConverter outputConsumer = consoleProperties instanceof SMCustomMessagesParsing + ? ((SMCustomMessagesParsing)consoleProperties).createTestEventsConverter(testFrameworkName) + : new OutputToGeneralTestEventsConverter(testFrameworkName); //events processor final GeneralToSMTRunnerEventsConvertor eventsProcessor = new GeneralToSMTRunnerEventsConvertor(resultsViewer.getTestsRootNode(), diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java index 4e9265bf7ed5..8312b0f3b88a 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/SMTRunnerConsoleView.java @@ -112,6 +112,7 @@ public class SMTRunnerConsoleView extends BaseTestsOutputConsoleView { } public void attachToProcess(final ProcessHandler processHandler) { + super.attachToProcess(processHandler); if (processHandler == null) { return; } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java b/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java index ad68caf50dee..52e6351a2ad9 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java @@ -132,6 +132,20 @@ public abstract class TestConsoleProperties extends StoringPropertyContainer imp public abstract RuntimeConfiguration getConfiguration(); + /** + * Allows to make console editable and disable/enable input sending in process stdin stream. + * Normally tests shouldn't ask anything in stdin so console is view only by default. + * + * NB: Process input support feature isn't fully implemented. Input text will be lost after + * switching to any other test/suite in tests results view. It's highly not recommended to change + * default behaviour. Please do it only in critical cases and only if you are sure that you need this feature. + * + * @return False for view-only mode and true for stdin support. + */ + public boolean isEditable() { + return false; + } + protected ExecutionConsole getConsole() { return myConsole; } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java new file mode 100644 index 000000000000..a8f9a8366b8d --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java @@ -0,0 +1,110 @@ +package com.intellij.execution.testframework.autotest; + +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.RunContentManagerImpl; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.event.DocumentAdapter; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.content.Content; +import com.intellij.util.Alarm; +import com.intellij.util.containers.WeakList; + +import java.util.Collection; + +/** + * @author yole + */ +public class AutoTestManager { + private final Project myProject; + private final Alarm myAutoTestAlarm; + + private static final int AUTOTEST_DELAY = 2000; + private final Runnable myRunTestsRunnable; + private boolean myListenerAttached; + private final MyDocumentAdapter myListener; + + public static AutoTestManager getInstance(Project project) { + return ServiceManager.getService(project, AutoTestManager.class); + } + + private final Collection myEnabledDescriptors = new WeakList(); + + public AutoTestManager(Project project) { + myProject = project; + myAutoTestAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project); + myRunTestsRunnable = new Runnable() { + public void run() { + runAutoTests(); + } + }; + myListener = new MyDocumentAdapter(); + } + + public void setAutoTestEnabled(RunContentDescriptor descriptor, boolean enabled) { + Content content = descriptor.getAttachedContent(); + if (enabled) { + if (!myEnabledDescriptors.contains(content)) { + myEnabledDescriptors.add(content); + } + if (!myListenerAttached) { + myListenerAttached = true; + EditorFactory.getInstance().getEventMulticaster().addDocumentListener(myListener, myProject); + } + } + else { + myEnabledDescriptors.remove(content); + if (myEnabledDescriptors.isEmpty() && myListenerAttached) { + myListenerAttached = false; + EditorFactory.getInstance().getEventMulticaster().removeDocumentListener(myListener); + } + } + } + + public boolean isAutoTestEnabled(RunContentDescriptor descriptor) { + return myEnabledDescriptors.contains(descriptor.getAttachedContent()); + } + + public void runAutoTests() { + for (Content content : myEnabledDescriptors) { + runAutoTest(content); + } + } + + private static void runAutoTest(Content content) { + RunContentDescriptor descriptor = RunContentManagerImpl.getRunContentDescriptorByContent(content); + if (descriptor == null) { + return; + } + Runnable restarter = descriptor.getRestarter(); + if (restarter == null) { + return; + } + final ProcessHandler processHandler = descriptor.getProcessHandler(); + if (processHandler != null && !processHandler.isProcessTerminated()) { + return; + } + restarter.run(); + } + + private class MyDocumentAdapter extends DocumentAdapter { + public void documentChanged(DocumentEvent event) { + final Document document = event.getDocument(); + final VirtualFile vFile = FileDocumentManager.getInstance().getFile(document); + if (vFile != null) { + final FileEditor[] editors = FileEditorManager.getInstance(myProject).getEditors(vFile); + if (editors.length > 0) { + myAutoTestAlarm.cancelAllRequests(); + myAutoTestAlarm.addRequest(myRunTestsRunnable, AUTOTEST_DELAY); + } + } + } + } +} \ No newline at end of file diff --git a/platform/testRunner/src/com/intellij/execution/testframework/autotest/ToggleAutoTestAction.java b/platform/testRunner/src/com/intellij/execution/testframework/autotest/ToggleAutoTestAction.java new file mode 100644 index 000000000000..e900bda821a8 --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/autotest/ToggleAutoTestAction.java @@ -0,0 +1,37 @@ +package com.intellij.execution.testframework.autotest; + +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.execution.ui.RunContentManager; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.IconLoader; + +/** + * @author yole + */ +public class ToggleAutoTestAction extends ToggleAction { + public ToggleAutoTestAction() { + super("Toggle auto-test", "Toggle automatic rerun of tests on code changes", + IconLoader.getIcon("/actions/swapPanels.png")); + } + + @Override + public boolean isSelected(AnActionEvent e) { + Project project = e.getData(PlatformDataKeys.PROJECT); + RunContentDescriptor descriptor = e.getData(RunContentManager.RUN_CONTENT_DESCRIPTOR); + return project == null || descriptor == null + ? false + : AutoTestManager.getInstance(project).isAutoTestEnabled(descriptor); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + Project project = e.getData(PlatformDataKeys.PROJECT); + RunContentDescriptor descriptor = e.getData(RunContentManager.RUN_CONTENT_DESCRIPTOR); + if (project != null && descriptor != null) { + AutoTestManager.getInstance(project).setAutoTestEnabled(descriptor, state); + } + } +} 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 97f92c7351f1..c2b8f7600c05 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/BaseTestsOutputConsoleView.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/BaseTestsOutputConsoleView.java @@ -10,14 +10,14 @@ * 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 + * See the Lice the specific language governing permissions and * limitations under the License. */ package com.intellij.execution.testframework.ui; import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.HyperlinkInfo; -import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.testframework.*; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; @@ -37,7 +37,10 @@ public abstract class BaseTestsOutputConsoleView implements ConsoleView, Observa public BaseTestsOutputConsoleView(final TestConsoleProperties properties, final AbstractTestProxy unboundOutputRoot) { myProperties = properties; - myConsole = TextConsoleBuilderFactory.getInstance().createBuilder(properties.getProject(), myProperties.getScope()).getConsole(); + + myConsole = new TestsConsoleBuilderImpl(properties.getProject(), + myProperties.getScope(), + !properties.isEditable()).getConsole(); myPrinter = new TestsOutputConsolePrinter(myConsole, properties, unboundOutputRoot); myProperties.setConsole(this); @@ -53,6 +56,10 @@ public abstract class BaseTestsOutputConsoleView implements ConsoleView, Observa protected abstract TestResultsPanel createTestResultsPanel(); + public void attachToProcess(final ProcessHandler processHandler) { + myConsole.attachToProcess(processHandler); + } + public void print(final String s, final ConsoleViewContentType contentType) { printNew(new Printable() { public void printOn(final Printer printer) { diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsConsoleBuilderImpl.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsConsoleBuilderImpl.java new file mode 100644 index 000000000000..024aa639e199 --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsConsoleBuilderImpl.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.testframework.ui; + +import com.intellij.execution.filters.TextConsoleBuilderImpl; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.project.Project; +import com.intellij.psi.search.GlobalSearchScope; + +/** + * @author Roman.Chernyatchik + */ +public class TestsConsoleBuilderImpl extends TextConsoleBuilderImpl { + public TestsConsoleBuilderImpl(final Project project, + final GlobalSearchScope scope, + boolean isViewer) { + super(project, scope); + setViewer(isViewer); + } + + @Override + protected ConsoleView createConsole() { + return new TestsConsoleViewImpl(getProject(), getScope(), isViewer(), null); + } +} diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsConsoleViewImpl.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsConsoleViewImpl.java new file mode 100644 index 000000000000..bdc2771d0063 --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestsConsoleViewImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.testframework.ui; + +import com.intellij.execution.impl.ConsoleState; +import com.intellij.execution.impl.ConsoleViewImpl; +import com.intellij.execution.impl.ConsoleViewRunningState; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.psi.search.GlobalSearchScope; + +/** + * @author Roman.Chernyatchik + */ +public class TestsConsoleViewImpl extends ConsoleViewImpl { + + public TestsConsoleViewImpl(final Project project, + final GlobalSearchScope searchScope, + final boolean viewer, + final FileType fileType) { + super(project, searchScope, viewer, fileType, + new ConsoleState.NotStartedStated() { + @Override + public ConsoleState attachTo(ConsoleViewImpl console, ProcessHandler processHandler) { + return new ConsoleViewRunningState(console, processHandler, this, false, !viewer); + } + }); + } +} diff --git a/platform/util/src/com/intellij/ide/ui/ListCellRendererWrapper.java b/platform/util/src/com/intellij/ide/ui/ListCellRendererWrapper.java index 943f13cefc79..9c83b38427b6 100644 --- a/platform/util/src/com/intellij/ide/ui/ListCellRendererWrapper.java +++ b/platform/util/src/com/intellij/ide/ui/ListCellRendererWrapper.java @@ -32,6 +32,7 @@ public abstract class ListCellRendererWrapper implements ListCellRenderer { private Icon myIcon; private String myText; private String myToolTipText; + private Color myForeground; /** * A combo box for which this cell renderer is created should be passed here. @@ -62,6 +63,7 @@ public abstract class ListCellRendererWrapper implements ListCellRenderer { final JLabel label = (JLabel)component; label.setIcon(myIcon); if (myText != null) label.setText(myText); + if (myForeground != null) label.setForeground(myForeground); label.setToolTipText(myToolTipText); } return component; @@ -97,4 +99,7 @@ public abstract class ListCellRendererWrapper implements ListCellRenderer { myToolTipText = toolTipText; } + public void setForeground(final Color foreground) { + myForeground = foreground; + } } diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 033038071288..5d9283210452 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -82,7 +82,6 @@ public class NameUtil { } index++; } - if (upperCaseCount == 0 && lowerCaseCount == 0 && digitCount == 0) continue; String word = name.substring(wordStart, index); array.add(word); } @@ -290,7 +289,7 @@ public class NameUtil { String prevWord = words[i - 1]; if (upperCaseStyle) { word = word.toUpperCase(); - if (prevWord.charAt(prevWord.length() - 1) != '_') { + if (prevWord.charAt(prevWord.length() - 1) != '_' && word.charAt(0) != '_') { word = "_" + word; } } @@ -380,7 +379,7 @@ public class NameUtil { } public static Matcher buildCompletionMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, true), false); + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, true), exactPrefixLen > 0); } public static Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { diff --git a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java index b090176309ef..227f9fd3b0f4 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java @@ -19,7 +19,9 @@ import com.intellij.util.containers.HashMap; import com.sun.jna.Callback; import com.sun.jna.Native; import com.sun.jna.Pointer; +import org.jetbrains.annotations.NotNull; +import java.io.File; import java.io.UnsupportedEncodingException; import java.util.Map; @@ -89,6 +91,18 @@ public class Foundation { return toStringViaUTF8(myFoundationLibrary.NSFullUserName()); } + public static boolean isPackageAtPath(@NotNull final String path) { + final ID workspace = invoke("NSWorkspace", "sharedWorkspace"); + final ID result = invoke(workspace, createSelector("isFilePackageAtPath:"), cfString(path)); + + return result.intValue() == 1; + } + + public static boolean isPackageAtPath(@NotNull final File file) { + if (!file.isDirectory()) return false; + return isPackageAtPath(file.getPath()); + } + /** * Return a CFString as an ID, toll-free bridged to NSString. *

diff --git a/platform/util/src/com/intellij/util/ui/FormBuilder.java b/platform/util/src/com/intellij/util/ui/FormBuilder.java index 9e17a2a96b67..6a590c170b78 100644 --- a/platform/util/src/com/intellij/util/ui/FormBuilder.java +++ b/platform/util/src/com/intellij/util/ui/FormBuilder.java @@ -46,7 +46,7 @@ public class FormBuilder { this(false, 5); } - public FormBuilder addLabeledComponent(String labelText, JComponent component) { + public FormBuilder addLabeledComponent(String labelText, JComponent component, final int verticalSpace) { JLabel label = null; if (labelText != null) { label = new JLabel(UIUtil.removeMnemonic(labelText)); @@ -55,7 +55,7 @@ public class FormBuilder { } GridBagConstraints c = new GridBagConstraints(); - int verticalInset = line > 0 ? 10 : 0; + int verticalInset = line > 0 ? verticalSpace : 0; if (vertical) { c.gridwidth = 1; @@ -103,6 +103,10 @@ public class FormBuilder { return this; } + public FormBuilder addLabeledComponent(String labelText, JComponent component) { + return addLabeledComponent(labelText, component, 10); + } + public JPanel getPanel() { return panel; } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java index 22a0f918c844..258e9c9f572b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/TryFinallyCanBeTryWithResourcesInspection.java @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.HardcodedMethodConstants; @@ -337,6 +338,19 @@ public class TryFinallyCanBeTryWithResourcesInspection extends BaseInspection { final int index = findInitialization(tryBlockStatements, variable, hasInitializer); if (index >= 0 ^ hasInitializer) { + final VariableUsedOutsideContextVisitor visitor = + new VariableUsedOutsideContextVisitor(variable, + tryStatement); + final PsiElement context = + PsiTreeUtil.getParentOfType(variable, + PsiCodeBlock.class); + if (context == null) { + continue; + } + context.accept(visitor); + if (visitor.variableIsUsed()) { + continue; + } found = true; break; } @@ -483,7 +497,7 @@ public class TryFinallyCanBeTryWithResourcesInspection extends BaseInspection { final PsiClassType classType = (PsiClassType) type; final PsiClass aClass = classType.resolve(); return aClass != null && InheritanceUtil.isInheritor(aClass, - "java.io.Closeable"); + "java.lang.AutoCloseable"); } static int findInitialization( @@ -521,4 +535,47 @@ public class TryFinallyCanBeTryWithResourcesInspection extends BaseInspection { } return result; } + + static class VariableUsedOutsideContextVisitor + extends JavaRecursiveElementVisitor { + + private boolean used = false; + @NotNull private final PsiVariable variable; + private final PsiElement skipContext; + + public VariableUsedOutsideContextVisitor(@NotNull PsiVariable variable, + PsiElement skipContext){ + this.variable = variable; + this.skipContext = skipContext; + } + + @Override public void visitElement(@NotNull PsiElement element){ + if (element.equals(skipContext)) { + return; + } + if (used) { + return; + } + super.visitElement(element); + } + + @Override public void visitReferenceExpression( + @NotNull PsiReferenceExpression referenceExpression){ + if(used){ + return; + } + super.visitReferenceExpression(referenceExpression); + final PsiElement target = referenceExpression.resolve(); + if(target == null){ + return; + } + if(target.equals(variable)){ + used = true; + } + } + + public boolean variableIsUsed(){ + return used; + } + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlock.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlock.java index 2bc1772906d3..61925b2ea77f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlock.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/GroovyBlock.java @@ -111,7 +111,7 @@ public class GroovyBlock implements Block, GroovyElementTypes { } /** - * Returns spacing between neighrbour elements + * Returns spacing between neighbour elements * * @param child1 left element * @param child2 right element @@ -120,7 +120,7 @@ public class GroovyBlock implements Block, GroovyElementTypes { @Nullable public Spacing getSpacing(Block child1, Block child2) { if ((child1 instanceof GroovyBlock) && (child2 instanceof GroovyBlock)) { - Spacing spacing = GroovySpacingProcessor.getSpacing(((GroovyBlock) child1), ((GroovyBlock) child2), mySettings); + Spacing spacing = new GroovySpacingProcessor(((GroovyBlock)child2).getNode(), mySettings).getSpacing(); return spacing != null ? spacing : GroovySpacingProcessorBasic.getSpacing(((GroovyBlock) child1), ((GroovyBlock) child2), mySettings); } return null; @@ -188,7 +188,7 @@ public class GroovyBlock implements Block, GroovyElementTypes { * @param node Tree node * @return true if node is incomplete */ - public boolean isIncomplete(@NotNull final ASTNode node) { + public static boolean isIncomplete(@NotNull final ASTNode node) { if (node.getElementType() instanceof ILazyParseableElementType) return false; ASTNode lastChild = node.getLastChildNode(); while (lastChild != null && diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java index 3a372ce2cbd8..cf1129da26b3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/formatter/processors/GroovySpacingProcessor.java @@ -18,7 +18,6 @@ package org.jetbrains.plugins.groovy.formatter.processors; import com.intellij.formatting.Spacing; import com.intellij.lang.ASTNode; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiIdentifier; @@ -26,12 +25,10 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.tree.IElementType; -import org.jetbrains.plugins.groovy.formatter.GroovyBlock; import org.jetbrains.plugins.groovy.lang.editor.actions.GroovyEditorActionUtil; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.*; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; @@ -70,519 +67,451 @@ import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.mRCURL /** * @author ilyas */ -public class GroovySpacingProcessor extends GroovyPsiElementVisitor { - private static final ThreadLocal mySharedProcessorAllocator = new ThreadLocal(); - protected MyGroovySpacingVisitor myGroovyElementVisitor; - protected static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.formatter.processors.GroovySpacingProcessor"); +public class GroovySpacingProcessor extends GroovyElementVisitor { + private PsiElement myParent; + private final CodeStyleSettings mySettings; - private GroovySpacingProcessor(MyGroovySpacingVisitor visitor) { - super(visitor); - myGroovyElementVisitor = visitor; - } + private Spacing myResult; + private ASTNode myChild1; + private ASTNode myChild2; - public static Spacing getSpacing(GroovyBlock child1, GroovyBlock child2, CodeStyleSettings settings) { - return getSpacing(child2.getNode(), settings); - } + public GroovySpacingProcessor(ASTNode node, CodeStyleSettings settings) { + mySettings = settings; - private static Spacing getSpacing(ASTNode node, CodeStyleSettings settings) { - GroovySpacingProcessor spacingProcessor = mySharedProcessorAllocator.get(); - try { - if (spacingProcessor == null) { - spacingProcessor = new GroovySpacingProcessor(new MyGroovySpacingVisitor(node, settings)); - mySharedProcessorAllocator.set(spacingProcessor); - } else { - spacingProcessor.setVisitor(new MyGroovySpacingVisitor(node, settings)); + _init(node); + + if (myChild1 == null || myChild2 == null) { + return; + } + + PsiElement psi1 = myChild1.getPsi(); + PsiElement psi2 = myChild2.getPsi(); + if (psi1 == null || psi2 == null) return; + if (psi1.getLanguage() != GROOVY_LANGUAGE || psi2.getLanguage() != GROOVY_LANGUAGE) { + return; + } + + if (myChild2 != null && mySettings.KEEP_FIRST_COLUMN_COMMENT && SpacingUtil.COMMENT_BIT_SET.contains(myChild2.getElementType())) { + if (myChild1.getElementType() != IMPORT_STATEMENT) { + myResult = Spacing.createKeepingFirstColumnSpacing(0, Integer.MAX_VALUE, true, 1); } - spacingProcessor.doInit(); - return spacingProcessor.getResult(); + return; } - catch (Exception e) { - LOG.error(e); - return null; + + if (myChild1 != null && myChild2 != null && myChild1.getElementType() == mNLS) { + final ASTNode prev = SpacingUtil.getPrevElementType(myChild1); + if (prev != null && prev.getElementType() == mSL_COMMENT) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + return; + } } - finally { - spacingProcessor.clear(); + + if (myParent instanceof GroovyPsiElement) { + ((GroovyPsiElement) myParent).accept(this); } } - - private void doInit() { - myGroovyElementVisitor.doInit(); - } - - private void clear() { - if (myGroovyElementVisitor != null) { - myGroovyElementVisitor.clear(); - } - } - - private Spacing getResult() { - return myGroovyElementVisitor.getResult(); - } - - public void setVisitor(MyGroovySpacingVisitor visitor) { - myGroovyElementVisitor = visitor; - } - - /** - * Visitor to adjust spaces via user Code Style Settings - */ - private static class MyGroovySpacingVisitor extends GroovyElementVisitor { - private PsiElement myParent; - private final CodeStyleSettings mySettings; - - private Spacing myResult; - private ASTNode myChild1; - private ASTNode myChild2; - - public MyGroovySpacingVisitor(ASTNode node, CodeStyleSettings settings) { - mySettings = settings; - init(node); - } - - private void init(final ASTNode child) { - if (child == null) return; + private void _init(final ASTNode child) { + if (child != null) { ASTNode treePrev = child.getTreePrev(); while (treePrev != null && SpacingUtil.isWhiteSpace(treePrev)) { treePrev = treePrev.getTreePrev(); } if (treePrev == null) { - init(child.getTreeParent()); - } else { + _init(child.getTreeParent()); + } + else { myChild2 = child; myChild1 = treePrev; - final CompositeElement parent = (CompositeElement) treePrev.getTreeParent(); + final CompositeElement parent = (CompositeElement)treePrev.getTreeParent(); myParent = SourceTreeToPsiMap.treeElementToPsi(parent); } } + } - /* - Method to start visiting - */ - private void doInit() { - if (myChild1 == null || myChild2 == null) return; - PsiElement psi1 = myChild1.getPsi(); - PsiElement psi2 = myChild2.getPsi(); - if (psi1 == null || psi2 == null) return; - if (psi1.getLanguage() != GROOVY_LANGUAGE || - psi2.getLanguage() != GROOVY_LANGUAGE) { - return; - } + @Override + public void visitAnnotation(GrAnnotation annotation) { + if (myChild2.getElementType() == ANNOTATION_ARGUMENTS) { + myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } - if (myChild2 != null && mySettings.KEEP_FIRST_COLUMN_COMMENT && SpacingUtil.COMMENT_BIT_SET.contains(myChild2.getElementType())) { - if (myChild1.getElementType() != IMPORT_STATEMENT) { - myResult = Spacing.createKeepingFirstColumnSpacing(0, Integer.MAX_VALUE, true, 1); - } - return; - } + public void visitArgumentList(GrArgumentList list) { + if (myChild1.getElementType() == mLBRACK || myChild2.getElementType() == mRBRACK) { + createSpaceInCode(mySettings.SPACE_WITHIN_BRACKETS); + } + // todo add other cases + } - if (myChild1 != null && myChild2 != null && myChild1.getElementType() == mNLS) { - final ASTNode prev = SpacingUtil.getPrevElementType(myChild1); - if (prev != null && prev.getElementType() == mSL_COMMENT) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - return; - } - } + @Override + public void visitMethodCallExpression(GrMethodCallExpression methodCallExpression) { + if (myChild2.getElementType() == ARGUMENTS) createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES); + } - if (myParent instanceof GroovyPsiElement) { - ((GroovyPsiElement) myParent).accept(this); + public void visitClosure(GrClosableBlock closure) { + if ((myChild1.getElementType() == mLCURLY && myChild2.getElementType() != PARAMETERS_LIST && myChild2.getElementType() != mCLOSABLE_BLOCK_OP) + || myChild2.getElementType() == mRCURLY) { + myResult = Spacing.createDependentLFSpacing(0, Integer.MAX_VALUE, closure.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else if (myChild1.getElementType() == mCLOSABLE_BLOCK_OP) { + GrStatement[] statements = closure.getStatements(); + if (statements.length > 0) { + TextRange range = new TextRange(statements[0].getTextRange().getStartOffset(), statements[statements.length - 1].getTextRange().getEndOffset()); + myResult = Spacing.createDependentLFSpacing(1, Integer.MAX_VALUE, range, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); } } + } - @Override - public void visitAnnotation(GrAnnotation annotation) { - if (myChild2.getElementType() == ANNOTATION_ARGUMENTS) { - myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } + public void visitOpenBlock(GrOpenBlock block) { + if (myChild1.getElementType() == mLCURLY && myChild2.getElementType() == mRCURLY && block.getParent() instanceof GrBlockStatement) { + myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else + if (myChild1.getElementType() == mLCURLY && !GroovyEditorActionUtil.isMultilineStringElement(myChild2) || + myChild2.getElementType() == mRCURLY && !GroovyEditorActionUtil.isMultilineStringElement(myChild1)) { + myResult = Spacing.createDependentLFSpacing(0, 1, block.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); } + } - public void visitArgumentList(GrArgumentList list) { - if (myChild1.getElementType() == mLBRACK || myChild2.getElementType() == mRBRACK) { - createSpaceInCode(mySettings.SPACE_WITHIN_BRACKETS); - } - // todo add other cases - } - - @Override - public void visitMethodCallExpression(GrMethodCallExpression methodCallExpression) { - if (myChild2.getElementType() == ARGUMENTS) createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES); - } - - public void visitClosure(GrClosableBlock closure) { - if ((myChild1.getElementType() == mLCURLY && myChild2.getElementType() != PARAMETERS_LIST && myChild2.getElementType() != mCLOSABLE_BLOCK_OP) - || myChild2.getElementType() == mRCURLY) { - myResult = Spacing.createDependentLFSpacing(0, Integer.MAX_VALUE, closure.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else if (myChild1.getElementType() == mCLOSABLE_BLOCK_OP) { - GrStatement[] statements = closure.getStatements(); - if (statements.length > 0) { - TextRange range = new TextRange(statements[0].getTextRange().getStartOffset(), statements[statements.length - 1].getTextRange().getEndOffset()); - myResult = Spacing.createDependentLFSpacing(1, Integer.MAX_VALUE, range, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - } - - public void visitOpenBlock(GrOpenBlock block) { - if (myChild1.getElementType() == mLCURLY && myChild2.getElementType() == mRCURLY && block.getParent() instanceof GrBlockStatement) { - myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else - if (myChild1.getElementType() == mLCURLY && !GroovyEditorActionUtil.isMultilineStringElement(myChild2) || - myChild2.getElementType() == mRCURLY && !GroovyEditorActionUtil.isMultilineStringElement(myChild1)) { - myResult = Spacing.createDependentLFSpacing(0, 1, block.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - - public void visitNewExpression(GrNewExpression newExpression) { - if (myChild1.getElementType() == kNEW) { - createSpaceInCode(true); - } else if (myChild2.getElementType() == ARGUMENTS) { - createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES); - } - } - - public void visitTypeDefinition(GrTypeDefinition typeDefinition) { - if (myChild2.getElementType() == CLASS_BODY) { - PsiIdentifier nameIdentifier = typeDefinition.getNameIdentifier(); - int dependanceStart = nameIdentifier == null ? myParent.getTextRange().getStartOffset() : nameIdentifier.getTextRange().getStartOffset(); - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_CLASS_LBRACE, mySettings.CLASS_BRACE_STYLE, - new TextRange(dependanceStart, myChild1.getTextRange().getEndOffset()), false); - } - } - - public void visitTypeDefinitionBody(GrTypeDefinitionBody typeDefinitionBody) { - if (myChild1.getElementType() == mLCURLY && myChild2.getElementType() == mRCURLY) { - myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); - } else if (myChild1.getElementType() == mLCURLY) { - myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_CLASS_HEADER + 1, - mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); - } else if (myChild2.getElementType() == mRCURLY) { - myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); - } - } - - public void visitMethod(GrMethod method) { - if (myChild2.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_PARENTHESES); - } else if (myChild2.getElementType() == mRPAREN && myChild2.getElementType() == THROW_CLAUSE) { - createSpaceInCode(true); - } else if (isOpenBlock(myChild2)) { - PsiElement methodName = method.getNameIdentifier(); - int dependancyStart = methodName == null ? myParent.getTextRange().getStartOffset() : methodName.getTextRange().getStartOffset(); - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_METHOD_LBRACE, mySettings.METHOD_BRACE_STYLE, - new TextRange(dependancyStart, myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_METHODS_IN_ONE_LINE); - } else if (myChild1.getElementType() == MODIFIERS) { - processModifierList(myChild1); - } else if (COMMENT_SET.contains(myChild1.getElementType()) - && (myChild2.getElementType() == MODIFIERS || myChild2.getElementType() == REFERENCE_ELEMENT)) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0); - } - - } - - private static boolean isOpenBlock(final ASTNode node) { - return node.getElementType() == OPEN_BLOCK || node.getElementType() == CONSTRUCTOR_BODY; - } - - public void visitDocMethodReference(GrDocMethodReference reference) { - visitDocMember(); - } - - - public void visitDocFieldReference(GrDocFieldReference reference) { - visitDocMember(); - } - - private void visitDocMember() { - myResult = Spacing.createSpacing(0, 0, 0, false, 0); - } - - public void visitDocMethodParameterList(GrDocMethodParams params) { - if (myChild1.getElementType() == mGDOC_TAG_VALUE_LPAREN || myChild2.getElementType() == mGDOC_TAG_VALUE_RPAREN) { - myResult = Spacing.createSpacing(0, 0, 0, false, 0); - return; - } - if (myChild2.getElementType() == mGDOC_TAG_VALUE_COMMA) { - myResult = Spacing.createSpacing(0, 0, 0, false, 0); - return; - } + public void visitNewExpression(GrNewExpression newExpression) { + if (myChild1.getElementType() == kNEW) { createSpaceInCode(true); + } else if (myChild2.getElementType() == ARGUMENTS) { + createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_CALL_PARENTHESES); } + } - public void visitDocMethodParameter(GrDocMethodParameter parameter) { - if (myChild1.getTreePrev() == null) { - createSpaceInCode(true); - } + public void visitTypeDefinition(GrTypeDefinition typeDefinition) { + if (myChild2.getElementType() == CLASS_BODY) { + PsiIdentifier nameIdentifier = typeDefinition.getNameIdentifier(); + int dependanceStart = nameIdentifier == null ? myParent.getTextRange().getStartOffset() : nameIdentifier.getTextRange().getStartOffset(); + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_CLASS_LBRACE, mySettings.CLASS_BRACE_STYLE, + new TextRange(dependanceStart, myChild1.getTextRange().getEndOffset()), false); } + } - public void visitWhileStatement(GrWhileStatement statement) { - if (myChild2.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_BEFORE_WHILE_PARENTHESES); - } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { - createSpaceInCode(mySettings.SPACE_WITHIN_WHILE_PARENTHESES); - } else if (myChild2.getPsi() instanceof GrBlockStatement) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_WHILE_LBRACE, mySettings.BRACE_STYLE, - new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } else { - createSpacingBeforeElementInsideControlStatement(); - } + public void visitTypeDefinitionBody(GrTypeDefinitionBody typeDefinitionBody) { + if (myChild1.getElementType() == mLCURLY && myChild2.getElementType() == mRCURLY) { + myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); + } else if (myChild1.getElementType() == mLCURLY) { + myResult = Spacing.createSpacing(0, 0, mySettings.BLANK_LINES_AFTER_CLASS_HEADER + 1, + mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); + } else if (myChild2.getElementType() == mRCURLY) { + myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); } + } - public void visitCatchClause(GrCatchClause catchClause) { - if (isOpenBlock(myChild2)) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } + public void visitMethod(GrMethod method) { + if (myChild2.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_BEFORE_METHOD_PARENTHESES); + } else if (myChild2.getElementType() == mRPAREN && myChild2.getElementType() == THROW_CLAUSE) { + createSpaceInCode(true); + } else if (isOpenBlock(myChild2)) { + PsiElement methodName = method.getNameIdentifier(); + int dependancyStart = methodName == null ? myParent.getTextRange().getStartOffset() : methodName.getTextRange().getStartOffset(); + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_METHOD_LBRACE, mySettings.METHOD_BRACE_STYLE, + new TextRange(dependancyStart, myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_METHODS_IN_ONE_LINE); + } else if (myChild1.getElementType() == MODIFIERS) { + processModifierList(myChild1); + } else if (COMMENT_SET.contains(myChild1.getElementType()) + && (myChild2.getElementType() == MODIFIERS || myChild2.getElementType() == REFERENCE_ELEMENT)) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, 0); } - public void visitFinallyClause(GrFinallyClause catchClause) { - if (isOpenBlock(myChild2)) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } - } - - public void visitTryStatement(GrTryCatchStatement tryCatchStatement) { - if (myChild2.getElementType() == FINALLY_CLAUSE) { - processOnNewLineCondition(mySettings.FINALLY_ON_NEW_LINE); - } else if (isOpenBlock(myChild2)) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } else if (myChild2.getElementType() == CATCH_CLAUSE) { - processOnNewLineCondition(mySettings.CATCH_ON_NEW_LINE); - } - } - - public void visitSwitchStatement(GrSwitchStatement switchStatement) { - if (myChild1.getElementType() == kSWITCH && myChild2.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_BEFORE_SWITCH_PARENTHESES); - } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { - createSpaceInCode(mySettings.SPACE_WITHIN_SWITCH_PARENTHESES); - } else if (myChild2.getElementType() == mLCURLY) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_SWITCH_LBRACE, mySettings.BRACE_STYLE, null, - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } - } - - public void visitSynchronizedStatement(GrSynchronizedStatement synchronizedStatement) { - if (myChild1.getElementType() == kSYNCHRONIZED || myChild2.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_BEFORE_SYNCHRONIZED_PARENTHESES); - } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { - createSpaceInCode(mySettings.SPACE_WITHIN_SYNCHRONIZED_PARENTHESES); - } else if (isOpenBlock(myChild2)) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE, - mySettings.BRACE_STYLE, null, - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } - - } - - public void visitDocComment(GrDocComment comment) { - if (myChild1.getElementType() == GDOC_TAG && - myChild2.getElementType() == GDOC_TAG && - mySettings.JD_LEADING_ASTERISKS_ARE_ENABLED) { - IElementType type = myChild1.getLastChildNode().getElementType(); - if (type == mGDOC_ASTERISKS) { - myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - } - - public void visitDocTag(GrDocTag docTag) { - if (myChild1.getElementType() == mGDOC_INLINE_TAG_START || - myChild2.getElementType() == mGDOC_INLINE_TAG_END) { - myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - - public void visitIfStatement(GrIfStatement ifStatement) { - if (myChild2.getElementType() == kELSE) { - if (!isOpenBlock(myChild1) && myChild1.getElementType() != BLOCK_STATEMENT) { - myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - if (mySettings.ELSE_ON_NEW_LINE) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - createSpaceProperty(true, false, 0); - } - } - } else if (myChild1.getElementType() == kELSE) { - if (myChild2.getElementType() == IF_STATEMENT) { - if (mySettings.SPECIAL_ELSE_IF_TREATMENT) { - createSpaceProperty(true, false, 0); - } else { - myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } else { - if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_ELSE_LBRACE, mySettings.BRACE_STYLE, - null, - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } else { - createSpacingBeforeElementInsideControlStatement(); - } - } - } else if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { - boolean space = myChild2.getPsi() == ((GrIfStatement) myParent).getElseBranch() ? mySettings.SPACE_BEFORE_ELSE_LBRACE : mySettings.SPACE_BEFORE_IF_LBRACE; - myResult = getSpaceBeforeLBrace(space, mySettings.BRACE_STYLE, new TextRange(myParent.getTextRange().getStartOffset(), - myChild1.getTextRange().getEndOffset()), - mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } else if (myChild2.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_BEFORE_IF_PARENTHESES); - } else if (myChild1.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES); - } else if (myChild2.getElementType() == mRPAREN) { - createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES); - } else if (((GrIfStatement) myParent).getThenBranch() == myChild2.getPsi()) { - createSpacingBeforeElementInsideControlStatement(); - } - } - - public void visitForStatement(GrForStatement forStatement) { - if (myChild2.getElementType() == mLPAREN) { - createSpaceInCode(mySettings.SPACE_BEFORE_FOR_PARENTHESES); - } else if (myChild1.getElementType() == mLPAREN) { - ASTNode rparenth = findFrom(myChild2, mRPAREN, true); - if (rparenth == null) { - createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES); - } else { - createParenSpace(mySettings.FOR_STATEMENT_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES, - new TextRange(myChild1.getTextRange().getStartOffset(), rparenth.getTextRange().getEndOffset())); - } - } else if (myChild2.getElementType() == mRPAREN) { - ASTNode lparenth = findFrom(myChild2, mLPAREN, false); - if (lparenth == null) { - createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES); - } else { - createParenSpace(mySettings.FOR_STATEMENT_RPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES, - new TextRange(lparenth.getTextRange().getStartOffset(), myChild2.getTextRange().getEndOffset())); - } - - } else if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { - if (myChild2.getElementType() == BLOCK_STATEMENT) { - myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_FOR_LBRACE, mySettings.BRACE_STYLE, - new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); - } else if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE) { - myResult = Spacing.createDependentLFSpacing(1, 1, myParent.getTextRange(), false, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - myResult = Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - } - - private void createParenSpace(final boolean onNewLine, final boolean space) { - createParenSpace(onNewLine, space, myParent.getTextRange()); - } - - private void createParenSpace(final boolean onNewLine, final boolean space, final TextRange dependance) { - if (onNewLine) { - final int spaces = space ? 1 : 0; - myResult = Spacing - .createDependentLFSpacing(spaces, spaces, dependance, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - createSpaceInCode(space); - } - } - - - private static ASTNode findFrom(ASTNode current, final IElementType expected, boolean forward) { - while (current != null) { - if (current.getElementType() == expected) return current; - current = forward ? current.getTreeNext() : current.getTreePrev(); - } - return null; - } - - - private void processOnNewLineCondition(final boolean onNewLine) { - if (onNewLine) { - if (!mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - myResult = Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } else { - createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - - - private void createSpacingBeforeElementInsideControlStatement() { - if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE && myChild1.getElementType() != mSL_COMMENT) { - createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - - - private void processModifierList(ASTNode modifierList) { - if (modifierList.getLastChildNode().getElementType() == ANNOTATION && mySettings.METHOD_ANNOTATION_WRAP == CodeStyleSettings.WRAP_ALWAYS) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - else if (mySettings.MODIFIER_LIST_WRAP) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - else { - createSpaceProperty(true, false, 0); - } - } - - - protected void clear() { - myResult = null; - myChild2 = myChild1 = null; - myParent = null; - } - - protected Spacing getResult() { - final Spacing result = myResult; - clear(); - return result; - } - - private void createSpaceInCode(final boolean space) { - createSpaceProperty(space, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - - private void createSpaceProperty(boolean space, int keepBlankLines) { - createSpaceProperty(space, mySettings.KEEP_LINE_BREAKS, keepBlankLines); - } - - private void createSpaceProperty(boolean space, boolean keepLineBreaks, final int keepBlankLines) { - final ASTNode prev = SpacingUtil.getPrevElementType(myChild2); - if (prev != null && prev.getElementType() == mSL_COMMENT) { - myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - myResult = Spacing.createSpacing(space ? 1 : 0, space ? 1 : 0, 0, keepLineBreaks, keepBlankLines); - } - } - - private Spacing getSpaceBeforeLBrace(final boolean spaceBeforeLbrace, int braceStyle, TextRange dependantRange, boolean keepOneLine) { - if (dependantRange != null && braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) { - int space = spaceBeforeLbrace ? 1 : 0; - return createNonLFSpace(space, dependantRange, false); - } else if (braceStyle == CodeStyleSettings.END_OF_LINE || braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) { - int space = spaceBeforeLbrace ? 1 : 0; - return createNonLFSpace(space, null, false); - } else if (keepOneLine) { - int space = spaceBeforeLbrace ? 1 : 0; - return Spacing.createDependentLFSpacing(space, space, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - return Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - - private Spacing createNonLFSpace(int spaces, final TextRange dependantRange, final boolean keepLineBreaks) { - final ASTNode prev = SpacingUtil.getPrevElementType(myChild2); - if (prev != null && prev.getElementType() == mSL_COMMENT) { - return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else if (dependantRange != null) { - return Spacing.createDependentLFSpacing(spaces, spaces, dependantRange, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE); - } else { - return Spacing.createSpacing(spaces, spaces, 0, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE); - } - } - - } + + private static boolean isOpenBlock(final ASTNode node) { + return node.getElementType() == OPEN_BLOCK || node.getElementType() == CONSTRUCTOR_BODY; + } + + public void visitDocMethodReference(GrDocMethodReference reference) { + visitDocMember(); + } + + + public void visitDocFieldReference(GrDocFieldReference reference) { + visitDocMember(); + } + + private void visitDocMember() { + myResult = Spacing.createSpacing(0, 0, 0, false, 0); + } + + public void visitDocMethodParameterList(GrDocMethodParams params) { + if (myChild1.getElementType() == mGDOC_TAG_VALUE_LPAREN || myChild2.getElementType() == mGDOC_TAG_VALUE_RPAREN) { + myResult = Spacing.createSpacing(0, 0, 0, false, 0); + return; + } + if (myChild2.getElementType() == mGDOC_TAG_VALUE_COMMA) { + myResult = Spacing.createSpacing(0, 0, 0, false, 0); + return; + } + createSpaceInCode(true); + } + + public void visitDocMethodParameter(GrDocMethodParameter parameter) { + if (myChild1.getTreePrev() == null) { + createSpaceInCode(true); + } + } + + public void visitWhileStatement(GrWhileStatement statement) { + if (myChild2.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_BEFORE_WHILE_PARENTHESES); + } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { + createSpaceInCode(mySettings.SPACE_WITHIN_WHILE_PARENTHESES); + } else if (myChild2.getPsi() instanceof GrBlockStatement) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_WHILE_LBRACE, mySettings.BRACE_STYLE, + new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } else { + createSpacingBeforeElementInsideControlStatement(); + } + } + + public void visitCatchClause(GrCatchClause catchClause) { + if (isOpenBlock(myChild2)) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } + } + + public void visitFinallyClause(GrFinallyClause catchClause) { + if (isOpenBlock(myChild2)) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } + } + + public void visitTryStatement(GrTryCatchStatement tryCatchStatement) { + if (myChild2.getElementType() == FINALLY_CLAUSE) { + processOnNewLineCondition(mySettings.FINALLY_ON_NEW_LINE); + } else if (isOpenBlock(myChild2)) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_TRY_LBRACE, mySettings.BRACE_STYLE, null, + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } else if (myChild2.getElementType() == CATCH_CLAUSE) { + processOnNewLineCondition(mySettings.CATCH_ON_NEW_LINE); + } + } + + public void visitSwitchStatement(GrSwitchStatement switchStatement) { + if (myChild1.getElementType() == kSWITCH && myChild2.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_BEFORE_SWITCH_PARENTHESES); + } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { + createSpaceInCode(mySettings.SPACE_WITHIN_SWITCH_PARENTHESES); + } else if (myChild2.getElementType() == mLCURLY) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_SWITCH_LBRACE, mySettings.BRACE_STYLE, null, + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } + } + + public void visitSynchronizedStatement(GrSynchronizedStatement synchronizedStatement) { + if (myChild1.getElementType() == kSYNCHRONIZED || myChild2.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_BEFORE_SYNCHRONIZED_PARENTHESES); + } else if (myChild1.getElementType() == mLPAREN || myChild2.getElementType() == mRPAREN) { + createSpaceInCode(mySettings.SPACE_WITHIN_SYNCHRONIZED_PARENTHESES); + } else if (isOpenBlock(myChild2)) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE, + mySettings.BRACE_STYLE, null, + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } + + } + + public void visitDocComment(GrDocComment comment) { + if (myChild1.getElementType() == GDOC_TAG && + myChild2.getElementType() == GDOC_TAG && + mySettings.JD_LEADING_ASTERISKS_ARE_ENABLED) { + IElementType type = myChild1.getLastChildNode().getElementType(); + if (type == mGDOC_ASTERISKS) { + myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + } + + public void visitDocTag(GrDocTag docTag) { + if (myChild1.getElementType() == mGDOC_INLINE_TAG_START || + myChild2.getElementType() == mGDOC_INLINE_TAG_END) { + myResult = Spacing.createSpacing(0, 0, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + + public void visitIfStatement(GrIfStatement ifStatement) { + if (myChild2.getElementType() == kELSE) { + if (!isOpenBlock(myChild1) && myChild1.getElementType() != BLOCK_STATEMENT) { + myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + if (mySettings.ELSE_ON_NEW_LINE) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + createSpaceProperty(true, false, 0); + } + } + } else if (myChild1.getElementType() == kELSE) { + if (myChild2.getElementType() == IF_STATEMENT) { + if (mySettings.SPECIAL_ELSE_IF_TREATMENT) { + createSpaceProperty(true, false, 0); + } else { + myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } else { + if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_ELSE_LBRACE, mySettings.BRACE_STYLE, + null, + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } else { + createSpacingBeforeElementInsideControlStatement(); + } + } + } else if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { + boolean space = myChild2.getPsi() == ((GrIfStatement) myParent).getElseBranch() ? mySettings.SPACE_BEFORE_ELSE_LBRACE : mySettings.SPACE_BEFORE_IF_LBRACE; + myResult = getSpaceBeforeLBrace(space, mySettings.BRACE_STYLE, new TextRange(myParent.getTextRange().getStartOffset(), + myChild1.getTextRange().getEndOffset()), + mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } else if (myChild2.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_BEFORE_IF_PARENTHESES); + } else if (myChild1.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES); + } else if (myChild2.getElementType() == mRPAREN) { + createSpaceInCode(mySettings.SPACE_WITHIN_IF_PARENTHESES); + } else if (((GrIfStatement) myParent).getThenBranch() == myChild2.getPsi()) { + createSpacingBeforeElementInsideControlStatement(); + } + } + + public void visitForStatement(GrForStatement forStatement) { + if (myChild2.getElementType() == mLPAREN) { + createSpaceInCode(mySettings.SPACE_BEFORE_FOR_PARENTHESES); + } else if (myChild1.getElementType() == mLPAREN) { + ASTNode rparenth = findFrom(myChild2, mRPAREN, true); + if (rparenth == null) { + createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES); + } else { + createParenSpace(mySettings.FOR_STATEMENT_LPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES, + new TextRange(myChild1.getTextRange().getStartOffset(), rparenth.getTextRange().getEndOffset())); + } + } else if (myChild2.getElementType() == mRPAREN) { + ASTNode lparenth = findFrom(myChild2, mLPAREN, false); + if (lparenth == null) { + createSpaceInCode(mySettings.SPACE_WITHIN_FOR_PARENTHESES); + } else { + createParenSpace(mySettings.FOR_STATEMENT_RPAREN_ON_NEXT_LINE, mySettings.SPACE_WITHIN_FOR_PARENTHESES, + new TextRange(lparenth.getTextRange().getStartOffset(), myChild2.getTextRange().getEndOffset())); + } + + } else if (myChild2.getElementType() == BLOCK_STATEMENT || isOpenBlock(myChild2)) { + if (myChild2.getElementType() == BLOCK_STATEMENT) { + myResult = getSpaceBeforeLBrace(mySettings.SPACE_BEFORE_FOR_LBRACE, mySettings.BRACE_STYLE, + new TextRange(myParent.getTextRange().getStartOffset(), myChild1.getTextRange().getEndOffset()), mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE); + } else if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE) { + myResult = Spacing.createDependentLFSpacing(1, 1, myParent.getTextRange(), false, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + myResult = Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + } + + private void createParenSpace(final boolean onNewLine, final boolean space) { + createParenSpace(onNewLine, space, myParent.getTextRange()); + } + + private void createParenSpace(final boolean onNewLine, final boolean space, final TextRange dependance) { + if (onNewLine) { + final int spaces = space ? 1 : 0; + myResult = Spacing + .createDependentLFSpacing(spaces, spaces, dependance, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + createSpaceInCode(space); + } + } + + + private static ASTNode findFrom(ASTNode current, final IElementType expected, boolean forward) { + while (current != null) { + if (current.getElementType() == expected) return current; + current = forward ? current.getTreeNext() : current.getTreePrev(); + } + return null; + } + + + private void processOnNewLineCondition(final boolean onNewLine) { + if (onNewLine) { + if (!mySettings.KEEP_SIMPLE_BLOCKS_IN_ONE_LINE) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + myResult = Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } else { + createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + + + private void createSpacingBeforeElementInsideControlStatement() { + if (mySettings.KEEP_CONTROL_STATEMENT_IN_ONE_LINE && myChild1.getElementType() != mSL_COMMENT) { + createSpaceProperty(true, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + + + private void processModifierList(ASTNode modifierList) { + if (modifierList.getLastChildNode().getElementType() == ANNOTATION && mySettings.METHOD_ANNOTATION_WRAP == CodeStyleSettings.WRAP_ALWAYS) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + else if (mySettings.MODIFIER_LIST_WRAP) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + else { + createSpaceProperty(true, false, 0); + } + } + + public Spacing getSpacing() { + return myResult; + } + + private void createSpaceInCode(final boolean space) { + createSpaceProperty(space, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + + private void createSpaceProperty(boolean space, int keepBlankLines) { + createSpaceProperty(space, mySettings.KEEP_LINE_BREAKS, keepBlankLines); + } + + private void createSpaceProperty(boolean space, boolean keepLineBreaks, final int keepBlankLines) { + final ASTNode prev = SpacingUtil.getPrevElementType(myChild2); + if (prev != null && prev.getElementType() == mSL_COMMENT) { + myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + myResult = Spacing.createSpacing(space ? 1 : 0, space ? 1 : 0, 0, keepLineBreaks, keepBlankLines); + } + } + + private Spacing getSpaceBeforeLBrace(final boolean spaceBeforeLbrace, int braceStyle, TextRange dependantRange, boolean keepOneLine) { + if (dependantRange != null && braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) { + int space = spaceBeforeLbrace ? 1 : 0; + return createNonLFSpace(space, dependantRange, false); + } else if (braceStyle == CodeStyleSettings.END_OF_LINE || braceStyle == CodeStyleSettings.NEXT_LINE_IF_WRAPPED) { + int space = spaceBeforeLbrace ? 1 : 0; + return createNonLFSpace(space, null, false); + } else if (keepOneLine) { + int space = spaceBeforeLbrace ? 1 : 0; + return Spacing.createDependentLFSpacing(space, space, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + return Spacing.createSpacing(0, 0, 1, false, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + + private Spacing createNonLFSpace(int spaces, final TextRange dependantRange, final boolean keepLineBreaks) { + final ASTNode prev = SpacingUtil.getPrevElementType(myChild2); + if (prev != null && prev.getElementType() == mSL_COMMENT) { + return Spacing.createSpacing(0, Integer.MAX_VALUE, 1, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else if (dependantRange != null) { + return Spacing.createDependentLFSpacing(spaces, spaces, dependantRange, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE); + } else { + return Spacing.createSpacing(spaces, spaces, 0, keepLineBreaks, mySettings.KEEP_BLANK_LINES_IN_CODE); + } + } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 60c6b7a58362..0721d3e3b227 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -362,7 +362,6 @@ public class GroovyCompletionContributor extends CompletionContributor { final ElementFilter classFilter = getClassFilter(position); - final boolean showCapitalizedClasses = JavaCompletionContributor.showCapitalizedClasses(result); reference.processVariants(new Consumer() { public void consume(Object element) { if (element instanceof PsiClass && inheritors.alreadyProcessed((PsiClass)element)) { @@ -384,10 +383,6 @@ public class GroovyCompletionContributor extends CompletionContributor { object = ((GroovyResolveResult)object).getElement(); } - if (!showCapitalizedClasses && object instanceof PsiClass && StringUtil.isCapitalized(((PsiClass)object).getName())) { - return; - } - final boolean autopopup = parameters.getInvocationCount() == 0; //skip default groovy methods if (!secondCompletionInvoked && @@ -458,7 +453,7 @@ public class GroovyCompletionContributor extends CompletionContributor { } }); - if (StringUtil.isCapitalized(prefix)) { + if (StringUtil.isNotEmpty(result.getPrefixMatcher().getPrefix())) { addAllClasses(parameters, result, inheritors); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/template/expressions/ChooseTypeExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/template/expressions/ChooseTypeExpression.java index 5d78bdff42f6..b2cc84051433 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/template/expressions/ChooseTypeExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/template/expressions/ChooseTypeExpression.java @@ -29,7 +29,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier; import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SubtypeConstraint; import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint; import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint; -import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeEquals; import java.util.LinkedHashSet; import java.util.Set; @@ -52,9 +51,7 @@ public class ChooseTypeExpression extends Expression { Set result = new LinkedHashSet(); for (TypeConstraint constraint : constraints) { - if (constraint instanceof TypeEquals) { - result.add(PsiTypeLookupItem.createLookupItem(constraint.getType(), null)); - } else if (constraint instanceof SubtypeConstraint) { + if (constraint instanceof SubtypeConstraint) { result.add(PsiTypeLookupItem.createLookupItem(constraint.getDefaultType(), null)); } else if (constraint instanceof SupertypeConstraint) { processSupertypes(constraint.getType(), result); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java index 57e8e0283299..d1b609dfafa5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/GroovyExpectedTypesProvider.java @@ -272,6 +272,7 @@ public class GroovyExpectedTypesProvider { expression, PsiType.EMPTY_ARRAY).length > 0; } + @NotNull @Override public PsiType getDefaultType() { return PsiType.INT; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SubtypeConstraint.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SubtypeConstraint.java index 80821405f521..70b418b2a3bf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SubtypeConstraint.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SubtypeConstraint.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiType; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType; @@ -30,7 +31,7 @@ import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions. public class SubtypeConstraint extends TypeConstraint { private final PsiType myDefaultType; - protected SubtypeConstraint(PsiType type, PsiType defaultType) { + protected SubtypeConstraint(@NotNull PsiType type, @NotNull PsiType defaultType) { super(type); myDefaultType = defaultType; } @@ -39,24 +40,16 @@ public class SubtypeConstraint extends TypeConstraint { return TypesUtil.isAssignableByMethodCallConversion(getType(), type, manager, scope); } + @NotNull public PsiType getDefaultType() { return myDefaultType; } - public static SubtypeConstraint create (PsiType type, PsiType defaultType) { - return new SubtypeConstraint(type, defaultType); - } - - public static SubtypeConstraint create (String fqName, String defaultFqName, PsiElement context) { - return new SubtypeConstraint(createType(fqName, context), - createType(defaultFqName, context)); - } - - public static SubtypeConstraint create (PsiType type) { + public static SubtypeConstraint create(@NotNull PsiType type) { return new SubtypeConstraint(type, type); } - public static SubtypeConstraint create (String fqName, PsiElement context) { + public static SubtypeConstraint create(String fqName, PsiElement context) { PsiClassType type = createType(fqName, context); return new SubtypeConstraint(type, type); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SupertypeConstraint.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SupertypeConstraint.java index f982d7a069a2..1cbbc9d463fd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SupertypeConstraint.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/SupertypeConstraint.java @@ -15,22 +15,19 @@ */ package org.jetbrains.plugins.groovy.lang.psi.expectedTypes; -import com.intellij.psi.PsiClassType; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiType; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType; - /** * @author ven */ public class SupertypeConstraint extends TypeConstraint { private final PsiType myDefaultType; - protected SupertypeConstraint(PsiType type, PsiType defaultType) { + protected SupertypeConstraint(@NotNull PsiType type, @NotNull PsiType defaultType) { super(type); myDefaultType = defaultType; } @@ -39,25 +36,17 @@ public class SupertypeConstraint extends TypeConstraint { return TypesUtil.isAssignableByMethodCallConversion(type, getType(), manager, scope); } + @NotNull public PsiType getDefaultType() { return myDefaultType; } - public static SupertypeConstraint create (PsiType type, PsiType defaultType) { + public static SupertypeConstraint create(@NotNull PsiType type, @NotNull PsiType defaultType) { return new SupertypeConstraint(type, defaultType); } - public static SupertypeConstraint create (String fqName, String defaultFqName, PsiElement context) { - return new SupertypeConstraint(createType(fqName, context), - createType(defaultFqName, context)); - } - - public static SupertypeConstraint create (PsiType type) { + public static SupertypeConstraint create(@NotNull PsiType type) { return new SupertypeConstraint(type, type); } - public static SupertypeConstraint create (String fqName, PsiElement context) { - PsiClassType type = createType(fqName, context); - return new SupertypeConstraint(type, type); - } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeConstraint.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeConstraint.java index b0820455d8c3..78aa8407756e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeConstraint.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeConstraint.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.lang.psi.expectedTypes; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiType; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; /** * @author ven @@ -29,12 +30,14 @@ public abstract class TypeConstraint { public abstract boolean satisfied(PsiType type, PsiManager manager, GlobalSearchScope scope); + @NotNull public abstract PsiType getDefaultType(); - protected TypeConstraint(PsiType type) { + protected TypeConstraint(@NotNull PsiType type) { myType = type; } + @NotNull public PsiType getType() { return myType; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeEquals.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeEquals.java deleted file mode 100644 index 2f45163941d3..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/expectedTypes/TypeEquals.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.plugins.groovy.lang.psi.expectedTypes; - -import com.intellij.psi.PsiClassType; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiManager; -import com.intellij.psi.PsiType; -import com.intellij.psi.search.GlobalSearchScope; - -import static org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType; - -/** - * @author ven - */ -public class TypeEquals extends TypeConstraint { - protected TypeEquals(PsiType type) { - super(type); - } - - public boolean satisfied(PsiType type, PsiManager manager, GlobalSearchScope scope){ - return type.equals(myType); - } - - public PsiType getDefaultType() { - return getType(); - } - - public static TypeEquals create (PsiType type) { - return new TypeEquals(type); - } - - public static TypeEquals create (String fqName, PsiElement context) { - PsiClassType type = createType(fqName, context); - return new TypeEquals(type); - } -} \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java index c4d40ba3f623..5a115f91f232 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiManager.java @@ -16,8 +16,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; import com.google.common.collect.Sets; import com.intellij.ProjectTopics; import com.intellij.openapi.components.ServiceManager; @@ -26,6 +24,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; import com.intellij.openapi.roots.ModuleRootListener; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.search.GlobalSearchScope; @@ -46,7 +46,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.stubs.GroovyShortNamesCache; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -74,6 +73,7 @@ public class GroovyPsiManager { private final TypeInferenceHelper myTypeInferenceHelper; private static final String SYNTHETIC_CLASS_TEXT = "class __ARRAY__ { public int length }"; + private static final RecursionGuard ourGuard = RecursionManager.createGuard("groovyPsiManager"); public GroovyPsiManager(Project project) { myProject = project; @@ -156,46 +156,22 @@ public class GroovyPsiManager { return result; } - private final ThreadLocal> inferring = new ThreadLocal>(){ - @Override - protected Multiset initialValue() { - return HashMultiset.create(); - } - }; - - private boolean lock(GroovyPsiElement element) { - final Multiset set = inferring.get(); - boolean alreadyContains = set.contains(element); - inferring.get().add(element); - return alreadyContains; - } - - private void unlock(GroovyPsiElement element) { - inferring.get().remove(element); - } - @Nullable public PsiType getType(T element, Function calculator) { PsiType type = myCalculatedTypes.get(element); if (type == null) { - try { - boolean locked = lock(element); - type = calculator.fun(element); - if (type == null) { - type = PsiType.NULL; - } - if (locked) { - final PsiType alreadyInferred = myCalculatedTypes.get(element); - if (alreadyInferred != null) { - type = alreadyInferred; - } - } - else { - type = ConcurrencyUtil.cacheOrGet(myCalculatedTypes, element, type); - } + RecursionGuard.StackStamp stamp = ourGuard.markStack(); + type = calculator.fun(element); + if (type == null) { + type = PsiType.NULL; } - finally { - unlock(element); + if (stamp.mayCacheNow()) { + type = ConcurrencyUtil.cacheOrGet(myCalculatedTypes, element, type); + } else { + final PsiType alreadyInferred = myCalculatedTypes.get(element); + if (alreadyInferred != null) { + type = alreadyInferred; + } } } if (!type.isValid()) { @@ -217,30 +193,15 @@ public class GroovyPsiManager { return myArrayClass; } - private static final ThreadLocal> myElementsWithTypesBeingInferred = new ThreadLocal>() { - protected List initialValue() { - return new ArrayList(); - } - }; - @Nullable public static PsiType inferType(PsiElement element, Computable computable) { - final List curr = myElementsWithTypesBeingInferred.get(); - if (curr.size() > 7) { //don't end up walking the whole project PSI + List stack = ourGuard.currentStack(); + if (stack.size() > 7) { //don't end up walking the whole project PSI + ourGuard.prohibitResultCaching(stack.get(0)); return null; } - try { - curr.add(element); - return computable.compute(); - } - finally { - curr.remove(element); - } - } - - public static boolean isTypeBeingInferred(PsiElement element) { - return myElementsWithTypesBeingInferred.get().contains(element); + return ourGuard.doPreventingRecursion(element, computable); } public GroovyShortNamesCache getNamesCache() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableBaseImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableBaseImpl.java index 414d4b612e42..ac5d1ea0a7a0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableBaseImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrVariableBaseImpl.java @@ -17,6 +17,9 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.search.LocalSearchScope; @@ -55,7 +58,7 @@ import javax.swing.*; public abstract class GrVariableBaseImpl extends GrStubElementBase implements GrVariable { public static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrVariableImpl"); - private final ThreadLocal isInferringType = new ThreadLocal(); + private final RecursionGuard myGuard = RecursionManager.createGuard("grVariableInitializer"); public GrVariableBaseImpl(ASTNode node) { super(node); @@ -143,7 +146,7 @@ public abstract class GrVariableBaseImpl extends GrStubEl @Nullable public PsiType getTypeGroovy() { - GrExpression initializer = getInitializerGroovy(); + final GrExpression initializer = getInitializerGroovy(); final PsiElement parent = getParent(); if (parent instanceof GrTupleDeclaration && initializer != null){ @@ -159,10 +162,13 @@ public abstract class GrVariableBaseImpl extends GrStubEl } } - if (initializer != null && isInferringType.get() == null) { - isInferringType.set(Boolean.TRUE); - PsiType initializerType = initializer.getType(); // WARNING may give rise to SOE - isInferringType.set(null); + if (initializer != null) { + PsiType initializerType = myGuard.doPreventingRecursion(this, new NullableComputable() { + @Override + public PsiType compute() { + return initializer.getType(); + } + }); if (initializerType != null) { if (declaredType != null && initializerType instanceof PsiClassType) { final PsiClass declaredClass = ((PsiClassType)declaredType).resolve(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java index e6d1488e6c06..0da8e56ad589 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java @@ -218,9 +218,6 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock @Nullable public PsiType getReturnType() { - if (GroovyPsiManager.isTypeBeingInferred(this)) { - return null; - } return GroovyPsiManager.getInstance(getProject()).getType(this, ourTypesCalculator); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index cd57d81ee9be..8d59132d8a46 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -426,7 +426,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl i if (block == null) return null; assert block.isValid() : "invalid code block"; - if (GroovyPsiManager.isTypeBeingInferred(method)) { - return null; - } - return GroovyPsiManager.inferType(method, new MethodTypeInferencer(block)); } }; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy index 82688c38d129..763ad3db5494 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy @@ -1,15 +1,17 @@ package org.jetbrains.plugins.groovy.lang +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiDocumentManager +import com.intellij.testFramework.IdeaTestUtil import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.annotations.NotNull import org.jetbrains.plugins.groovy.LightGroovyTestCase import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod -import org.jetbrains.annotations.NotNull -import com.intellij.psi.PsiDocumentManager -import com.intellij.testFramework.IdeaTestUtil +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager -/** + /** * @author peter */ class GroovyStressTest extends LightCodeInsightFixtureTestCase { @@ -19,24 +21,41 @@ class GroovyStressTest extends LightCodeInsightFixtureTestCase { } public void testDontWalkLongInferenceChain() throws Exception { + Map classes = [:] myFixture.addFileToProject "Foo0.groovy", """class Foo0 { def foo() { return 0 } }""" def max = 100 for (i in 1..max) { - myFixture.addFileToProject "Foo${i}.groovy", """class Foo$i { - def foo() { return Foo${i-1}.foo() } - }""" + def file = myFixture.addFileToProject("Foo${i}.groovy", """class Foo$i { + def foo() { return Foo${i - 1}.foo() } + }""") + classes[i] = (file as GroovyFile).classes[0] } def deepFile = myFixture.addFileToProject("DeepTest.groovy", "def test() { return Foo${max}.foo() }") as GroovyFile - assert Object.name == (deepFile.scriptClass.findMethodsByName("test", false)[0] as GrMethod).inferredReturnType.canonicalText + assert Object.name == inferredType(deepFile.scriptClass, 'test') def shallowFile = myFixture.addFileToProject("ShallowTest.groovy", "def test() { return Foo2.foo() }") as GroovyFile - assert Integer.name == (shallowFile.scriptClass.findMethodsByName("test", false)[0] as GrMethod).inferredReturnType.canonicalText + assert Integer.name == inferredType(shallowFile.scriptClass, 'test') + int border = (1..max).find { int i -> + GroovyPsiManager.getInstance(project).dropTypesCache() + return inferredType(classes[i], 'foo') == Object.name + } + + assert border + + GroovyPsiManager.getInstance(project).dropTypesCache() + assert inferredType(classes[border], 'foo') == Object.name + assert inferredType(classes[border - 1], 'foo') == Integer.name } + String inferredType(PsiClass clazz, String method) { + (clazz.findMethodsByName(method, false)[0] as GrMethod).inferredReturnType.canonicalText + } + + public void testQuickIncrementalReparse() { def story = '''scenario { given "some precondition", { diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java index 656cc5c1b221..567aafbc5397 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java @@ -18,7 +18,6 @@ package com.intellij.execution.junit2.ui; import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; import com.intellij.execution.configurations.RunnerSettings; -import com.intellij.execution.junit2.TestProxy; import com.intellij.execution.junit2.ui.model.JUnitRunningModel; import com.intellij.execution.junit2.ui.model.TreeCollapser; import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties; @@ -53,6 +52,7 @@ public class JUnitTreeConsoleView extends BaseTestsOutputConsoleView { } public void attachToProcess(final ProcessHandler processHandler) { + super.attachToProcess(processHandler); myConsolePanel.onProcessStarted(processHandler); } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java index af994c2069a4..666f9850f69f 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java @@ -94,9 +94,13 @@ public class JUnit4TestResultsSender extends RunListener { catch (Throwable ignore) {} } - if (assertion.getMessage() != null) { - final Matcher matcher = - Pattern.compile("\nExpected: \"(.*)\"\n got: \"(.*)\"\n", Pattern.DOTALL).matcher(assertion.getMessage()); + final String message = assertion.getMessage(); + if (message != null) { + Matcher matcher = + Pattern.compile("\nExpected: (.*)\n\\s*got: (.*)", Pattern.DOTALL).matcher(message); + if (!matcher.matches()) { + matcher = Pattern.compile("expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message); + } if (matcher.matches()) { return ComparisonDetailsExtractor .create(assertion, matcher.group(1).replaceAll("\\\\n", "\n"), matcher.group(2).replaceAll("\\\\n", "\n")); diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java index 20b58ee7f3ac..ec08cbfcc025 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/TestNGConsoleView.java @@ -25,8 +25,6 @@ package com.theoryinpractice.testng.ui; import com.intellij.execution.Executor; import com.intellij.execution.configurations.ConfigurationPerRunnerSettings; import com.intellij.execution.configurations.RunnerSettings; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.testframework.AbstractTestProxy; import com.intellij.execution.testframework.TestTreeView; import com.intellij.execution.testframework.ui.BaseTestsOutputConsoleView; import com.intellij.execution.testframework.ui.TestResultsPanel; @@ -124,9 +122,6 @@ public class TestNGConsoleView extends BaseTestsOutputConsoleView { } } - public void attachToProcess(ProcessHandler processHandler) { - } - public TestProxy getCurrentTest() { return currentTest; } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 3b689a9c771a..df485bacd239 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -179,6 +179,8 @@ + + diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/CustomDomChildrenDescriptionImpl.java b/xml/dom-impl/src/com/intellij/util/xml/impl/CustomDomChildrenDescriptionImpl.java index 931d59e66953..be2c90094140 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/CustomDomChildrenDescriptionImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/CustomDomChildrenDescriptionImpl.java @@ -89,4 +89,14 @@ public class CustomDomChildrenDescriptionImpl extends AbstractDomChildDescriptio public TagNameDescriptor getTagNameDescriptor() { return myTagNameDescriptor; } + + @Override + public boolean equals(Object obj) { + return obj instanceof CustomDomChildrenDescriptionImpl; + } + + @Override + public int hashCode() { + return 239; + } } diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java index 6461a6dbc214..55a2bd96e7eb 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomSemContributor.java @@ -16,28 +16,30 @@ package com.intellij.util.xml.impl; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.NullableComputable; +import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; import com.intellij.psi.PsiElement; -import com.intellij.psi.xml.*; -import com.intellij.semantic.SemContributor; -import com.intellij.semantic.SemRegistrar; -import com.intellij.semantic.SemService; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlElementType; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.semantic.*; import com.intellij.util.NullableFunction; import com.intellij.util.Processor; +import com.intellij.openapi.util.RecursionManager; import com.intellij.util.xml.EvaluatedXmlName; import com.intellij.util.xml.XmlName; import com.intellij.util.xml.reflect.CustomDomChildrenDescription; import com.intellij.util.xml.reflect.DomChildrenDescription; import com.intellij.util.xml.reflect.DomCollectionChildDescription; import com.intellij.util.xml.reflect.DomFixedChildDescription; -import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Type; import java.util.Collection; -import java.util.Set; import static com.intellij.patterns.XmlPatterns.*; @@ -142,12 +144,7 @@ public class DomSemContributor extends SemContributor { }); registrar.registerSemElementProvider(DomManagerImpl.DOM_CUSTOM_HANDLER_KEY, nonRootTag, new NullableFunction() { - private final ThreadLocal> myCalculating = new ThreadLocal>() { - @Override - protected Set initialValue() { - return new THashSet(); - } - }; + private final RecursionGuard myGuard = RecursionManager.createGuard("customDomParent"); public CollectionElementInvocationHandler fun(XmlTag tag) { if (StringUtil.isEmpty(tag.getName())) return null; @@ -155,17 +152,12 @@ public class DomSemContributor extends SemContributor { final XmlTag parentTag = PhysicalDomParentStrategy.getParentTag(tag); assert parentTag != null; - if (!myCalculating.get().add(tag)) { - return null; - } - DomInvocationHandler parent; - try { - parent = mySemService.getSemElement(DomManagerImpl.DOM_HANDLER_KEY, parentTag); - } - finally { - myCalculating.get().remove(tag); - } - + DomInvocationHandler parent = myGuard.doPreventingRecursion(tag, new NullableComputable() { + @Override + public DomInvocationHandler compute() { + return mySemService.getSemElement(DomManagerImpl.DOM_HANDLER_KEY, parentTag); + } + }); if (parent == null) return null; DomGenericInfoEx info = parent.getGenericInfo(); diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java index f9eed39d6e84..69b876c16c71 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java +++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DynamicGenericInfo.java @@ -17,7 +17,10 @@ package com.intellij.util.xml.impl; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.psi.xml.XmlElement; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; @@ -39,9 +42,9 @@ import java.util.Set; * @author peter */ public class DynamicGenericInfo extends DomGenericInfoEx { + private static final RecursionGuard ourGuard = RecursionManager.createGuard("dynamicGenericInfo"); private final StaticGenericInfo myStaticGenericInfo; @NotNull private final DomInvocationHandler myInvocationHandler; - private final ThreadLocal myComputing = new ThreadLocal(); private volatile boolean myInitialized; private volatile ChildrenDescriptionsHolder myAttributes; private volatile ChildrenDescriptionsHolder myFixeds; @@ -65,29 +68,26 @@ public class DynamicGenericInfo extends DomGenericInfoEx { if (myInitialized) return true; myStaticGenericInfo.buildMethodMaps(); - if (myComputing.get() == Boolean.TRUE) return false; - final XmlElement element = myInvocationHandler.getXmlElement(); if (element == null) return true; - myComputing.set(Boolean.TRUE); - try { - DomExtensionsRegistrarImpl registrar = runDomExtenders(); + return ourGuard.doPreventingRecursion(element, new Computable() { + @Override + public Boolean compute() { + DomExtensionsRegistrarImpl registrar = runDomExtenders(); - //noinspection SynchronizationOnLocalVariableOrMethodParameter - synchronized (element) { - if (myInitialized) return true; - - if (registrar != null) { - applyExtensions(registrar); + //noinspection SynchronizationOnLocalVariableOrMethodParameter + synchronized (element) { + if (!myInitialized) { + if (registrar != null) { + applyExtensions(registrar); + } + myInitialized = true; + } } - myInitialized = true; + return Boolean.TRUE; } - } - finally { - myComputing.set(null); - } - return true; + }) == Boolean.TRUE; } private void applyExtensions(DomExtensionsRegistrarImpl registrar) { diff --git a/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java b/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java index 96a1f9501c39..232bdad2e1ce 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/EvaluatedXmlNameImpl.java @@ -75,7 +75,7 @@ public class EvaluatedXmlNameImpl implements EvaluatedXmlName { @Override public boolean equals(final Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (o == null || !(o instanceof EvaluatedXmlNameImpl)) return false; final EvaluatedXmlNameImpl that = (EvaluatedXmlNameImpl)o; diff --git a/xml/impl/resources/standardSchemas/xhtml11/xhtml-events-1.mod b/xml/impl/resources/standardSchemas/xhtml11/xhtml-events-1.mod new file mode 100644 index 000000000000..03fd46cbb5c0 --- /dev/null +++ b/xml/impl/resources/standardSchemas/xhtml11/xhtml-events-1.mod @@ -0,0 +1,135 @@ + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java index 84e18201c9e5..a16b24febf39 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java @@ -25,8 +25,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.PomManager; import com.intellij.pom.PomModel; @@ -39,6 +38,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.meta.MetaRegistry; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import com.intellij.psi.impl.source.tree.*; +import com.intellij.psi.impl.source.tree.Factory; import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.psi.search.PsiElementProcessor; @@ -96,6 +96,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { @NonNls private static final String XML_NS_PREFIX = "xml"; private final int myHC = ourHC++; + private static final RecursionGuard ourGuard = RecursionManager.createGuard("xmlTag"); @Override public final int hashCode() { @@ -251,56 +252,53 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { protected final Map> initNSDescriptorsMap() { Map> map = myNSDescriptorsMap; if (map == null) { - boolean exceptionOccurred = false; - try { - // XSD aware attributes processing - - final String noNamespaceDeclaration = getAttributeValue("noNamespaceSchemaLocation", XmlUtil.XML_SCHEMA_INSTANCE_URI); - final String schemaLocationDeclaration = getAttributeValue("schemaLocation", XmlUtil.XML_SCHEMA_INSTANCE_URI); - - if (noNamespaceDeclaration != null) { - map = initializeSchema(XmlUtil.EMPTY_URI, null, noNamespaceDeclaration, map); - } - if (schemaLocationDeclaration != null) { - final StringTokenizer tokenizer = new StringTokenizer(schemaLocationDeclaration); - while (tokenizer.hasMoreTokens()) { - final String uri = tokenizer.nextToken(); - if (tokenizer.hasMoreTokens()) { - map = initializeSchema(uri, null, tokenizer.nextToken(), map); - } - } - } - // namespace attributes processing (XSD declaration via ExternalResourceManager) - - if (hasNamespaceDeclarations()) { - for (final XmlAttribute attribute : getAttributes()) { - if (attribute.isNamespaceDeclaration()) { - String ns = attribute.getValue(); - if (ns == null) ns = XmlUtil.EMPTY_URI; - ns = getRealNs(ns); - - if (map == null || !map.containsKey(ns)) { - map = initializeSchema(ns, getNSVersion(ns, this), getNsLocation(ns), map); - } - } - } - } + RecursionGuard.StackStamp stamp = ourGuard.markStack(); + map = computeNsDescriptorMap(); + if (stamp.mayCacheNow()) { + myNSDescriptorsMap = map; } - catch (RuntimeException e) { - myNSDescriptorsMap = null; - exceptionOccurred = true; - throw e; - } - finally { - if (map == null && !exceptionOccurred) { - map = Collections.emptyMap(); - } - } - myNSDescriptorsMap = map; } return map; } + @NotNull + private Map> computeNsDescriptorMap() { + Map> map = null; + // XSD aware attributes processing + + final String noNamespaceDeclaration = getAttributeValue("noNamespaceSchemaLocation", XmlUtil.XML_SCHEMA_INSTANCE_URI); + final String schemaLocationDeclaration = getAttributeValue("schemaLocation", XmlUtil.XML_SCHEMA_INSTANCE_URI); + + if (noNamespaceDeclaration != null) { + map = initializeSchema(XmlUtil.EMPTY_URI, null, noNamespaceDeclaration, map); + } + if (schemaLocationDeclaration != null) { + final StringTokenizer tokenizer = new StringTokenizer(schemaLocationDeclaration); + while (tokenizer.hasMoreTokens()) { + final String uri = tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) { + map = initializeSchema(uri, null, tokenizer.nextToken(), map); + } + } + } + // namespace attributes processing (XSD declaration via ExternalResourceManager) + + if (hasNamespaceDeclarations()) { + for (final XmlAttribute attribute : getAttributes()) { + if (attribute.isNamespaceDeclaration()) { + String ns = attribute.getValue(); + if (ns == null) ns = XmlUtil.EMPTY_URI; + ns = getRealNs(ns); + + if (map == null || !map.containsKey(ns)) { + map = initializeSchema(ns, getNSVersion(ns, this), getNsLocation(ns), map); + } + } + } + } + return map == null ? Collections.>emptyMap() : map; + } + @Nullable private static String getNSVersion(String ns, final XmlTagImpl xmlTag) { String versionValue = xmlTag.getAttributeValue("version"); @@ -414,7 +412,13 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { if (myExtResourcesModCount != curExtResourcesModCount) { myNSDescriptorsMap = null; } - myCachedDescriptor = computeElementDescriptor(); + RecursionGuard.StackStamp stamp = ourGuard.markStack(); + XmlElementDescriptor descriptor = computeElementDescriptor(); + if (!stamp.mayCacheNow()) { + return descriptor; + } + + myCachedDescriptor = descriptor; myDescriptorModCount = curModCount; myExtResourcesModCount = curExtResourcesModCount; } @@ -694,8 +698,12 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { if (cachedNamespace != null && myModCount == curModCount) { return cachedNamespace; } - final String prefix = getNamespacePrefix(); - cachedNamespace = getNamespaceByPrefix(prefix); + RecursionGuard.StackStamp stamp = ourGuard.markStack(); + cachedNamespace = getNamespaceByPrefix(getNamespacePrefix()); + if (!stamp.mayCacheNow()) { + return cachedNamespace; + } + myCachedNamespace = cachedNamespace; myModCount = curModCount; return cachedNamespace; @@ -706,8 +714,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { return XmlUtil.findPrefixByQualifiedName(getName()); } - private static final ThreadLocal ourGetNsByPrefixRecursionLock = new ThreadLocal(); - @NotNull public String getNamespaceByPrefix(String prefix) { final PsiElement parent = getParent(); @@ -723,22 +729,26 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { if (prefix.length() > 0 && !hasNamespaceDeclarations() && - getNamespacePrefix().equals(prefix) && - ourGetNsByPrefixRecursionLock.get() == null) { + getNamespacePrefix().equals(prefix)) { // When there is no namespace declarations then qualified names should be just used in dtds // this implies that we may have "" namespace prefix ! (see last paragraph in Namespaces in Xml, Section 5) - ourGetNsByPrefixRecursionLock.set(Boolean.TRUE); - try { - final String nsFromEmptyPrefix = getNamespaceByPrefix(""); - final XmlNSDescriptor nsDescriptor = getNSDescriptor(nsFromEmptyPrefix, false); - final XmlElementDescriptor descriptor = nsDescriptor != null ? nsDescriptor.getElementDescriptor(this) : null; - final String nameFromRealDescriptor = - descriptor != null && descriptor.getDeclaration() != null && descriptor.getDeclaration().isPhysical() ? descriptor.getName() : ""; - if (nameFromRealDescriptor.equals(getName())) return nsFromEmptyPrefix; - } - finally { - ourGetNsByPrefixRecursionLock.set(null); + String result = ourGuard.doPreventingRecursion("getNsByPrefix", new Computable() { + @Override + public String compute() { + final String nsFromEmptyPrefix = getNamespaceByPrefix(""); + final XmlNSDescriptor nsDescriptor = getNSDescriptor(nsFromEmptyPrefix, false); + final XmlElementDescriptor descriptor = nsDescriptor != null ? nsDescriptor.getElementDescriptor(XmlTagImpl.this) : null; + final String nameFromRealDescriptor = + descriptor != null && descriptor.getDeclaration() != null && descriptor.getDeclaration().isPhysical() + ? descriptor.getName() + : ""; + if (nameFromRealDescriptor.equals(getName())) return nsFromEmptyPrefix; + return XmlUtil.EMPTY_URI; + } + }); + if (result != null) { + return result; } } return XmlUtil.EMPTY_URI; @@ -788,8 +798,23 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { @Nullable private BidirectionalMap initNamespaceMaps(PsiElement parent) { BidirectionalMap map = myNamespaceMap; - if (map == null && hasNamespaceDeclarations()) { - final BidirectionalMap namespaceMap = new BidirectionalMap(); + + if (map == null) { + RecursionGuard.StackStamp stamp = ourGuard.markStack(); + map = computeNamespaceMap(parent); + if (stamp.mayCacheNow()) { + myNamespaceMap = map; + } + } + + return map; + } + + @Nullable + private BidirectionalMap computeNamespaceMap(PsiElement parent) { + BidirectionalMap map = null; + if (hasNamespaceDeclarations()) { + map = new BidirectionalMap(); final XmlAttribute[] attributes = getAttributes(); for (final XmlAttribute attribute : attributes) { @@ -800,17 +825,14 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { if (value != null) { if (splitIndex < 0) { - namespaceMap.put("", value); + map.put("", value); } else { - namespaceMap.put(XmlUtil.findLocalNameByQualifiedName(name), value); + map.put(XmlUtil.findLocalNameByQualifiedName(name), value); } } } } - - myNamespaceMap = map = - namespaceMap; // assign to field should be as last statement, to prevent incomplete initialization due to ProcessCancelledException } if (parent instanceof XmlDocument) { @@ -818,15 +840,12 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { if (extension != null) { final String[][] defaultNamespace = extension.getNamespacesFromDocument((XmlDocument)parent, map != null); if (defaultNamespace != null) { - final BidirectionalMap namespaceMap = new BidirectionalMap(); - if (map != null) { - namespaceMap.putAll(map); + if (map == null) { + map = new BidirectionalMap(); } for (final String[] prefix2ns : defaultNamespace) { - namespaceMap.put(prefix2ns[0], getRealNs(prefix2ns[1])); + map.put(prefix2ns[0], getRealNs(prefix2ns[1])); } - myNamespaceMap = map = - namespaceMap; // assign to field should be as last statement, to prevent incomplete initialization due to ProcessCancelledException } } } diff --git a/xml/impl/src/com/intellij/xml/util/XmlUtil.java b/xml/impl/src/com/intellij/xml/util/XmlUtil.java index 14f7bab98943..1112b7799934 100644 --- a/xml/impl/src/com/intellij/xml/util/XmlUtil.java +++ b/xml/impl/src/com/intellij/xml/util/XmlUtil.java @@ -17,7 +17,6 @@ package com.intellij.xml.util; import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.codeInsight.daemon.Validator; -import com.intellij.codeInsight.daemon.impl.analysis.XmlHighlightVisitor; import com.intellij.javaee.ExternalResourceManager; import com.intellij.javaee.ExternalResourceManagerEx; import com.intellij.javaee.ExternalResourceManagerImpl; @@ -35,7 +34,10 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; @@ -55,7 +57,10 @@ import com.intellij.psi.impl.source.xml.XmlEntityRefImpl; import com.intellij.psi.scope.processor.FilterElementProcessor; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.*; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.*; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; @@ -144,7 +149,6 @@ public class XmlUtil { @NonNls public static final String TARGET_NAMESPACE_ATTR_NAME = "targetNamespace"; @NonNls public static final String XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace"; public static final List ourSchemaUrisList = Arrays.asList(SCHEMA_URIS); - private static final ThreadLocal XML_FILE_IN_PROGRESS = new ThreadLocal(); public static final Key ANT_FILE_SIGN = new Key("FORCED ANT FILE"); @NonNls public static final String TAG_DIR_NS_PREFIX = "urn:jsptagdir:"; @NonNls public static final String VALUE_ATTR_NAME = "value";