diff --git a/RegExpSupport/test/org/intellij/lang/regexp/RegExpParseTest.java b/RegExpSupport/test/org/intellij/lang/regexp/RegExpParseTest.java index 7aa073894522..d9a06ed1fb33 100644 --- a/RegExpSupport/test/org/intellij/lang/regexp/RegExpParseTest.java +++ b/RegExpSupport/test/org/intellij/lang/regexp/RegExpParseTest.java @@ -103,6 +103,10 @@ public class RegExpParseTest extends BaseParseTestCase { return super.getTestDataPath() + "/gen/"; } + public void testOptions() throws Exception { + doTest("options/"); + } + public void testSimple() throws Exception { doTest("simple/"); } diff --git a/RegExpSupport/testData/RETest.xml b/RegExpSupport/testData/RETest.xml index 3e81b2ec2e89..12ec11dbd6e3 100644 --- a/RegExpSupport/testData/RETest.xml +++ b/RegExpSupport/testData/RETest.xml @@ -919,6 +919,21 @@ + + + Zm)abc]]> + OK + + + (?idmsuxU)nice + OK + + + (?idm-suxU)one(?suxU-idm)two + OK + + + abc) ERR diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java index 99d7bdeb25fa..c5ab2a7a67e7 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java @@ -182,7 +182,7 @@ public class DuplicatesFinder { if (sibling == null) return null; if (!canBeEquivalent(element, sibling)) return null; candidates.add(sibling); - sibling = PsiTreeUtil.skipSiblingsForward(sibling, PsiWhiteSpace.class, PsiComment.class); + sibling = PsiTreeUtil.skipSiblingsForward(sibling, PsiWhiteSpace.class, PsiComment.class, PsiEmptyStatement.class); } LOG.assertTrue(myPattern.length == candidates.size()); if (myPattern.length == 1 && myPattern[0] instanceof PsiExpression) { @@ -340,7 +340,7 @@ public class DuplicatesFinder { } if (pattern instanceof PsiAssignmentExpression) { - final PsiExpression lExpression = ((PsiAssignmentExpression)pattern).getLExpression(); + final PsiExpression lExpression = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)pattern).getLExpression()); if (lExpression.getType() instanceof PsiPrimitiveType && lExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)lExpression).resolve() instanceof PsiParameter) { @@ -541,9 +541,11 @@ public class DuplicatesFinder { return true; } - private static boolean checkParameterModification(final PsiExpression expression, + private static boolean checkParameterModification(PsiExpression expression, final IElementType sign, PsiExpression candidate) { + expression = PsiUtil.skipParenthesizedExprDown(expression); + candidate = PsiUtil.skipParenthesizedExprDown(candidate); if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() instanceof PsiParameter && (sign.equals(JavaTokenType.MINUSMINUS)|| sign.equals(JavaTokenType.PLUSPLUS))) { if (candidate instanceof PsiReferenceExpression && ((PsiReferenceExpression)candidate).resolve() instanceof PsiParameter) { @@ -597,7 +599,7 @@ public class DuplicatesFinder { return match.registerReturnValue(new VariableReturnValue(variable)); } else if (candidate instanceof PsiReturnStatement) { - final PsiExpression returnValue = ((PsiReturnStatement)candidate).getReturnValue(); + final PsiExpression returnValue = PsiUtil.skipParenthesizedExprDown(((PsiReturnStatement)candidate).getReturnValue()); if (myMultipleExitPoints) { return match.registerReturnValue(new ConditionalReturnStatementValue(returnValue)); } @@ -607,7 +609,7 @@ public class DuplicatesFinder { if (classOrLambda == null || !PsiTreeUtil.isAncestor(commonParent, classOrLambda, false)) { if (returnValue != null && !match.registerReturnValue(ReturnStatementReturnValue.INSTANCE)) return false; //do not register return value for return; statement } - return matchPattern(patternReturnStatement.getReturnValue(), returnValue, candidates, match); + return matchPattern(PsiUtil.skipParenthesizedExprDown(patternReturnStatement.getReturnValue()), returnValue, candidates, match); } } else return false; @@ -654,20 +656,27 @@ public class DuplicatesFinder { return false; } - private static PsiElement[] getFilteredChildren(PsiElement element1) { + public static PsiElement[] getFilteredChildren(PsiElement element1) { PsiElement[] children1 = element1.getChildren(); ArrayList array = new ArrayList(); for (PsiElement child : children1) { - if (!(child instanceof PsiWhiteSpace) && !(child instanceof PsiComment)) { + if (!(child instanceof PsiWhiteSpace) && !(child instanceof PsiComment) && !(child instanceof PsiEmptyStatement)) { if (child instanceof PsiBlockStatement) { - Collections.addAll(array, getFilteredChildren(child)); - continue; - } else if (child instanceof PsiCodeBlock) { + child = ((PsiBlockStatement)child).getCodeBlock(); + } + if (child instanceof PsiCodeBlock) { final PsiStatement[] statements = ((PsiCodeBlock)child).getStatements(); - if (statements.length == 1) { - array.add(statements[0]); - continue; + for (PsiStatement statement : statements) { + if (statement instanceof PsiBlockStatement) { + Collections.addAll(array, getFilteredChildren(statement)); + } else if (!(statement instanceof PsiEmptyStatement)) { + array.add(statement); + } } + continue; + } else if (child instanceof PsiParenthesizedExpression) { + array.add(PsiUtil.skipParenthesizedExprDown((PsiParenthesizedExpression)child)); + continue; } array.add(child); } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java index 264da49fb74f..6793f954d3a8 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java @@ -83,7 +83,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase cached = getOrComputeSubClasses(project, baseClass); + Iterable cached = getOrComputeSubClasses(project, baseClass, searchScope); for (final PsiClass subClass : cached) { ProgressManager.checkCanceled(); @@ -99,7 +99,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase getOrComputeSubClasses(@NotNull Project project, @NotNull PsiClass baseClass) { + private static Iterable getOrComputeSubClasses(@NotNull Project project, @NotNull PsiClass baseClass, @NotNull SearchScope searchScopeForNonPhysical) { ConcurrentMap> map = HighlightingCaches.getInstance(project).ALL_SUB_CLASSES; Iterable cached = map.get(baseClass); if (cached == null) { @@ -108,8 +108,11 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase ApplicationManager.getApplication().runReadAction((Computable)() -> (PsiClass)anchor.retrieve()); Predicate applicableFilter = candidate -> !(candidate instanceof PsiAnonymousClass) && candidate != null && !candidate.hasModifierProperty(PsiModifier.FINAL); + // for non-physical elements ignore the cache completely because non-physical elements created so often/unpredictably so I can't figure out when to clear caches in this case + boolean isPhysical = ApplicationManager.getApplication().runReadAction((Computable)baseClass::isPhysical); + SearchScope scopeToUse = isPhysical ? GlobalSearchScope.allScope(project) : searchScopeForNonPhysical; LazyConcurrentCollection.MoreElementsGenerator generator = (candidate, processor) -> - DirectClassInheritorsSearch.search(candidate, GlobalSearchScope.allScope(project)).forEach(subClass -> { + DirectClassInheritorsSearch.search(candidate, scopeToUse).forEach(subClass -> { ProgressManager.checkCanceled(); PsiAnchor pointer = ApplicationManager.getApplication().runReadAction((Computable)() -> PsiAnchor.create(subClass)); // append found result to subClasses as early as possible to allow other waiting threads to continue @@ -120,8 +123,6 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase)() -> PsiAnchor.create(baseClass)); // lazy collection: store underlying queue as PsiAnchors, generate new elements by running direct inheritors Iterable computed = new LazyConcurrentCollection<>(seed, converter, applicableFilter, generator); - // for non-physical elements ignore the cache completely because non-physical elements created so often/unpredictably so I can't figure out when to clear caches in this case - boolean isPhysical = ApplicationManager.getApplication().runReadAction((Computable)baseClass::isPhysical); // make sure concurrent calls of this method always return the same collection to avoid expensive duplicate work cached = isPhysical ? ConcurrencyUtil.cacheOrGet(map, baseClass, computed) : computed; } @@ -158,13 +159,6 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase implements Iterable { // If more elements requested for this iterator, the processMoreSubclasses() is called which tries to populate 'subClasses' with more inheritors. private final HashSetQueue subClasses; // guarded by lock private final Object lock = new Object(); // MUST NOT acquire read action inside this lock - @NotNull private final Function myConvertor; + @NotNull private final Function myAnchorToValueConvertor; @NotNull private final MoreElementsGenerator myGenerator; - @NotNull private final Predicate myApplicableFilter; + @NotNull private final Predicate myApplicableForGenerationFilter; private final Semaphore currentlyProcessingClasses = new Semaphore(); private final HashSetQueue.PositionalIterator candidatesToFindSubclassesIterator; // guarded by lock @@ -67,13 +68,13 @@ class LazyConcurrentCollection implements Iterable { LazyConcurrentCollection(@NotNull T seedElement, @NotNull Function convertor, - @NotNull Predicate applicableFilter, + @NotNull Predicate applicableForGenerationFilter, @NotNull MoreElementsGenerator generator) { subClasses = new HashSetQueue<>(); subClasses.add(seedElement); - myConvertor = convertor; + myAnchorToValueConvertor = convertor; myGenerator = generator; - myApplicableFilter = applicableFilter; + myApplicableForGenerationFilter = applicableForGenerationFilter; candidatesToFindSubclassesIterator = subClasses.iterator(); } @@ -111,55 +112,58 @@ class LazyConcurrentCollection implements Iterable { synchronized (lock) { next = subClassIterator.next(); } - return myConvertor.fun(next); + return myAnchorToValueConvertor.fun(next); } }; } - private Pair.NonNull findNextClassInQueue(@NotNull HashSetQueue.PositionalIterator.IteratorPosition position) { - // find the first class which is fit (not anonymous and not final and retrievable from PsiAnchor) and not already processed (flag PROCESSING_SUBCLASSES_STATUS in class user data) - // couldn't call iterator.next() until class is processed, so use position.peek()/position.next() which don't advance iterator - while (position != null) { - ProgressManager.checkCanceled(); - T anchor = position.peek(); - V value = myConvertor.fun(anchor); - boolean isAccepted = value != null && myApplicableFilter.apply(value); - - if (isAccepted && !classesProcessed.contains(anchor) && classesBeingProcessed.add(anchor)) { - return Pair.createNonNull(anchor, value); - } - // the candidate is already being processed in the other thread, try the next one (not advancing iterator!) - position = position.next(); - } - return null; - } - // polls 'subClasses' for more sub classes and call DirectClassInheritorsSearch for them - private void processMoreSubclasses(@NotNull Iterator subClassIterator) { + // returns true if some classes were found + private boolean processMoreSubclasses(@NotNull Iterator subClassIterator) { while (true) { ProgressManager.checkCanceled(); Pair.NonNull pair = - ApplicationManager.getApplication().runReadAction(new Computable>() { - @Override - public Pair.NonNull compute() { - synchronized (lock) { - // Find the classes in subClasses collection to operate on - // (without advancing the candidatesToFindSubclassesIterator iterator - it will be moved after the class successfully handled - to protect against PCE, INRE, etc) - // The found class will be marked as being analyzed - placed in classesBeingProcessed collection - HashSetQueue.PositionalIterator.IteratorPosition startPosition = candidatesToFindSubclassesIterator.position().next(); - Pair.NonNull pair = startPosition == null ? null : findNextClassInQueue(startPosition); - if (pair != null) { - currentlyProcessingClasses.down(); - } - return pair; + ApplicationManager.getApplication().runReadAction((Computable>)() -> { + synchronized (lock) { + // Find the classes in subClasses collection to operate on + // (without advancing the candidatesToFindSubclassesIterator iterator - it will be moved after the class successfully handled - to protect against PCE, INRE, etc) + // The found class will be marked as being analyzed - placed in classesBeingProcessed collection + HashSetQueue.PositionalIterator.IteratorPosition startPosition = candidatesToFindSubclassesIterator.position().next(); + Pair.NonNull next = startPosition == null ? null : findNextClassInQueue(startPosition); + if (next != null) { + currentlyProcessingClasses.down(); + classesBeingProcessed.add(next.getFirst()); } + return next; } }); if (pair == null) { // no candidates left in queue, exit // but first, wait for other threads to process their candidates - break; + synchronized (lock) { + advanceIteratorOnSuccess(); // to skip unsuitable classes like final etc from the queue + if (subClassIterator.hasNext()) { + return true; + } + } + + boolean producedSomething = waitForOtherThreadsToFinishProcessing(subClassIterator); + if (producedSomething) { + return true; + } + + // aaaaaaaa! Other threads were unable to produce anything. That can be because: + // - the whole queue has been processed. => exit, return false + // - the other thread has been interrupted. => check the queue again to pickup the work it dropped. + synchronized (lock) { + advanceIteratorOnSuccess(); // to skip unsuitable classes like final etc from the queue + if (!candidatesToFindSubclassesIterator.hasNext()) { + return false; + } + } + + continue; // check again } V candidate = pair.getSecond(); @@ -170,29 +174,33 @@ class LazyConcurrentCollection implements Iterable { subClasses.add(generatedElement); } }); + synchronized (lock) { + classesProcessed.add(anchor); + advanceIteratorOnSuccess(); + if (subClassIterator.hasNext()) { + // we've added something to subClasses so we can return and the iterator can move forward at least once; + // more elements will be added on the subsequent call to .next() + return true; + } + } } finally { - currentlyProcessingClasses.up(); - } - - synchronized (lock) { - classesBeingProcessed.remove(anchor); - classesProcessed.add(anchor); - advanceIteratorOnSuccess(); - if (subClassIterator.hasNext()) { - // we've added something to subClasses so we can return and the iterator can move forward at least once; - // more elements will be added on the subsequent call to .next() - return; + synchronized (lock) { + classesBeingProcessed.remove(anchor); + currentlyProcessingClasses.up(); } } } + } + private boolean waitForOtherThreadsToFinishProcessing(@NotNull final Iterator subClassIterator) { // Found nothing, have to wait for other threads because: // The first thread comes and takes a class off the queue to search for inheritors, // the second thread comes and sees there is no classes in the queue. // The second thread should not return nothing, it should wait for the first thread to finish. // // Wait within managedBlock to signal FJP this thread is locked (to avoid thread starvation and deadlocks) + AtomicBoolean hasNext = new AtomicBoolean(); try { ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() { @Override @@ -204,7 +212,10 @@ class LazyConcurrentCollection implements Iterable { @Override public boolean isReleasable() { synchronized (lock) { - return !currentlyProcessingClasses.isDown() || subClassIterator.hasNext(); + // other thread produced something or all of them reached the end of list + boolean producedSomething = subClassIterator.hasNext(); + hasNext.set(producedSomething); // store the result to avoid locking again after exit + return producedSomething || !candidatesToFindSubclassesIterator.hasNext() || classesBeingProcessed.isEmpty(); } } }); @@ -212,20 +223,41 @@ class LazyConcurrentCollection implements Iterable { catch (InterruptedException e) { throw new RuntimeException(e); } + return hasNext.get(); } - private void advanceIteratorOnSuccess() { - HashSetQueue.PositionalIterator.IteratorPosition position = candidatesToFindSubclassesIterator.position().next(); + // under lock + private Pair.NonNull findNextClassInQueue(@NotNull HashSetQueue.PositionalIterator.IteratorPosition position) { + // find the first class suitable for analyzing inheritors of (not anonymous and not final and retrievable from PsiAnchor) and not already processed or being processed (by other thread) + // couldn't call iterator.next() until class is processed, so use position.peek()/position.next() which don't advance iterator while (position != null) { - T next = position.peek(); - if (classesProcessed.contains(next)) { + ProgressManager.checkCanceled(); + T anchor = position.peek(); + if (!classesProcessed.contains(anchor) && !classesBeingProcessed.contains(anchor)) { + V value = myAnchorToValueConvertor.fun(anchor); + boolean isAccepted = value != null && myApplicableForGenerationFilter.apply(value); + if (isAccepted) { + return Pair.createNonNull(anchor, value); + } + classesProcessed.add(anchor); + } + // the candidate is already being processed in the other thread, try the next one (not advancing iterator!) + position = position.next(); + } + return null; + } + + // under lock + private void advanceIteratorOnSuccess() { + while (candidatesToFindSubclassesIterator.hasNext()) { + T next = candidatesToFindSubclassesIterator.position().next().peek(); + boolean removed = classesProcessed.remove(next); + if (removed) { candidatesToFindSubclassesIterator.next(); - classesProcessed.remove(next); } else { break; } - position = position.next(); } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaGenericsUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/daemon/impl/analysis/JavaGenericsUtil.java similarity index 100% rename from java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaGenericsUtil.java rename to java/java-psi-api/src/com/intellij/codeInsight/daemon/impl/analysis/JavaGenericsUtil.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java b/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java index 3b9181141105..74168755e6a7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/ScopedClassHierarchy.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.RecursionManager; import com.intellij.openapi.util.text.StringUtil; @@ -29,7 +30,6 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.util.PairProcessor; import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; -import gnu.trove.THashMap; import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -165,16 +165,14 @@ class ScopedClassHierarchy { List list = myImmediateSupersWithCapturing; if (list == null) { RecursionGuard.StackStamp stamp = ourGuard.markStack(); - list = ContainerUtil.newArrayList(); - for (PsiClassType type : myPlaceClass.getSuperTypes()) { - PsiClassType corrected = PsiClassImplUtil.correctType(type, myResolveScope); - if (corrected == null) continue; - - PsiClassType.ClassResolveResult result = ((PsiClassType)PsiUtil.captureToplevelWildcards(corrected, myPlaceClass)).resolveGenerics(); - PsiClass superClass = result.getElement(); - if (superClass == null || !PsiSearchScopeUtil.isInScope(myResolveScope, superClass)) continue; - - list.add(result); + list = ourGuard.doPreventingRecursion(this, true, new Computable>() { + @Override + public List compute() { + return calcImmediateSupersWithCapturing(); + } + }); + if (list == null) { + return Collections.emptyList(); } if (stamp.mayCacheNow()) { myImmediateSupersWithCapturing = list; @@ -183,6 +181,23 @@ class ScopedClassHierarchy { return list; } + @NotNull + private List calcImmediateSupersWithCapturing() { + List list; + list = ContainerUtil.newArrayList(); + for (PsiClassType type : myPlaceClass.getSuperTypes()) { + PsiClassType corrected = PsiClassImplUtil.correctType(type, myResolveScope); + if (corrected == null) continue; + + PsiClassType.ClassResolveResult result = ((PsiClassType)PsiUtil.captureToplevelWildcards(corrected, myPlaceClass)).resolveGenerics(); + PsiClass superClass = result.getElement(); + if (superClass == null || !PsiSearchScopeUtil.isInScope(myResolveScope, superClass)) continue; + + list.add(result); + } + return list; + } + @NotNull private Map calcAllMemberSupers(final LanguageLevel level) { final Map map = ContainerUtil.newTroveMap(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java index e216d4cf2baa..ae5516715aa3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java @@ -172,8 +172,13 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P final PsiType[] args = classParameters.length == 0 ? null : new ClsReferenceParameterListImpl(this, classParameters).getTypeArguments(); final PsiTypeParameter[] typeParameters = containingClass.getTypeParameters(); for (int i = 0; i < typeParameters.length; i++) { - if (args != null && i < args.length) { - substitutionMap.put(typeParameters[i], args[i]); + if (args != null) { + if (i < args.length) { + substitutionMap.put(typeParameters[i], args[i]); + } + } + else { + substitutionMap.put(typeParameters[i], null); } } if (!containingClass.hasModifierProperty(PsiModifier.STATIC)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java index 9c8d851c6147..18ed26bd5e43 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.tree.java; +import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.projectRoots.JavaSdkVersion; @@ -254,14 +255,18 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements // If unchecked conversion was necessary for the method to be applicable, // the parameter types of the invocation type are the parameter types of the method's type, // and the return type and thrown types are given by the erasures of the return type and thrown types of the method's type. - if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && - (method.hasTypeParameters() || JavaVersionService.getInstance().isAtLeast(call, JavaSdkVersion.JDK_1_8)) && + if ((!languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && method.hasTypeParameters() || + !method.hasTypeParameters() && JavaVersionService.getInstance().isAtLeast(call, JavaSdkVersion.JDK_1_8)) && result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isApplicable()) { final PsiType[] args = call.getArgumentList().getExpressionTypes(); - final boolean allowUncheckedConversion = false; - final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, args, languageLevel, allowUncheckedConversion, true); - if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) { - return TypeConversionUtil.erasure(substitutedReturnType); + final PsiParameter[] parameters = method.getParameterList().getParameters(); + final boolean varargs = ((MethodCandidateInfo)result).getApplicabilityLevel() == MethodCandidateInfo.ApplicabilityLevel.VARARGS; + for (int i = 0; i < args.length; i++) { + final PsiType parameterType = substitutor.substitute(PsiTypesUtil.getParameterType(parameters, i, varargs)); + final PsiType expressionType = args[i]; + if (expressionType != null && parameterType != null && JavaGenericsUtil.isRawToGeneric(parameterType, expressionType)) { + return TypeConversionUtil.erasure(substitutedReturnType); + } } } diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/IDEA157254.java b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA157254.java new file mode 100644 index 000000000000..e058977c7355 --- /dev/null +++ b/java/java-tests/testData/codeInsight/clsHighlighting/IDEA157254.java @@ -0,0 +1,11 @@ +import p.AccountCalculator; +import p.ObjectParameterDescriptor; + +import java.io.IOException; + +class Test { + public static void calc(AccountCalculator calculator, + ObjectParameterDescriptor.Holder holder) throws IOException{ + calculator.getMetrics(holder); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA157254.jar b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA157254.jar new file mode 100644 index 000000000000..fcd28bfeec68 Binary files /dev/null and b/java/java-tests/testData/codeInsight/clsHighlighting/libs/IDEA157254.jar differ diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ErasureOfReturnTypeOfNonGenericMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ErasureOfReturnTypeOfNonGenericMethod.java new file mode 100644 index 000000000000..e760794e35be --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/ErasureOfReturnTypeOfNonGenericMethod.java @@ -0,0 +1,19 @@ +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Test { + public static List sort(Comparator comp, Stream stream) { + return stream.sorted(comp).collect(Collectors.toList()); + } + + //accept unbounded wildcards + List get(List lists) { + return null; + } + + void foo(List l) { + String p = get(l).get(0); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithEmptyStatementsBlocksParentheses.java b/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithEmptyStatementsBlocksParentheses.java new file mode 100644 index 000000000000..56ecb9c586a2 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithEmptyStatementsBlocksParentheses.java @@ -0,0 +1,15 @@ +class Test { + + public void method1() + { + System.out.println(((1))); + ;; + System.out.println(2); + } + + public void method2() + { + System.out.println(1); + System.out.println(2); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithEmptyStatementsBlocksParentheses_after.java b/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithEmptyStatementsBlocksParentheses_after.java new file mode 100644 index 000000000000..423e6dac4153 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/CodeDuplicatesWithEmptyStatementsBlocksParentheses_after.java @@ -0,0 +1,17 @@ +class Test { + + public void method1() + { + newMethod(); + } + + public void method2() + { + newMethod(); + } + + private void newMethod() { + System.out.println(1); + System.out.println(2); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java index eda9b832191a..a4fe79931be7 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/ClsGenerics18HighlightingTest.java @@ -35,6 +35,10 @@ public class ClsGenerics18HighlightingTest extends ClsGenericsHighlightingTest { doTest(); } + public void testIDEA157254() throws Exception { + doTest(); + } + public void testOuterClassTypeArgs() throws Exception { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index cc65c975318e..0c929899f9bc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -994,4 +994,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { public void testNestedCaptures() throws Exception { doTest(); } + + public void testErasureOfReturnTypeOfNonGenericMethod() throws Exception { + doTest(); + } } diff --git a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java index 7cbc01bc9d8e..21e7aa9fdd04 100644 --- a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java @@ -27,6 +27,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.ResolveTestCase; @@ -203,12 +204,17 @@ public class ResolveClassTest extends ResolveTestCase { public void testStaticImportInTheSameClassPerformance() throws Exception { PsiReference ref = configure(); + ensureIndexUpToDate(); long start = System.currentTimeMillis(); assertNull(ref.resolve()); long elapsed = System.currentTimeMillis() - start; PlatformTestUtil.assertTiming("exponent?", 500, elapsed); } + private void ensureIndexUpToDate() { + getJavaFacade().findClass(CommonClassNames.JAVA_UTIL_LIST, GlobalSearchScope.allScope(myProject)); + } + public void testStaticImportNetworkPerformance() throws Exception { PsiReference ref = configure(); int count = 15; @@ -222,6 +228,7 @@ public class ResolveClassTest extends ResolveTestCase { createFile(myModule, "Foo" + i + ".java", imports + "class Foo" + i + " extends Bar1, Bar2, Bar3 {}"); } + ensureIndexUpToDate(); System.gc(); long start = System.currentTimeMillis(); assertNull(ref.resolve()); diff --git a/java/java-tests/testSrc/com/intellij/psi/search/ClassInheritorsTest.java b/java/java-tests/testSrc/com/intellij/psi/search/ClassInheritorsTest.java index 965809599a48..e8a26c8bb95e 100644 --- a/java/java-tests/testSrc/com/intellij/psi/search/ClassInheritorsTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/search/ClassInheritorsTest.java @@ -16,17 +16,30 @@ package com.intellij.psi.search; import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; +import com.intellij.concurrency.JobScheduler; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.StandardProgressIndicatorBase; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiJavaFile; import com.intellij.psi.impl.compiled.ClsClassImpl; import com.intellij.psi.impl.source.PsiClassImpl; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.util.CommonProcessors; +import gnu.trove.THashSet; +import java.io.File; +import java.io.IOException; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; public class ClassInheritorsTest extends DaemonAnalyzerTestCase { @@ -49,4 +62,43 @@ public class ClassInheritorsTest extends DaemonAnalyzerTestCase { List allFqn = allSubClasses.stream().map(PsiClass::getQualifiedName).sorted().collect(Collectors.toList()); assertEquals(allFqn.toString(), allFqn.size(), new HashSet<>(allFqn).size()); } + + public void testStressInPresenceOfPCEs() throws IOException { + ApplicationManager.getApplication().assertIsDispatchThread(); // no write action can go through while we test + File tempDirectory = createTempDirectory(); + VirtualFile dir = getVirtualFile(tempDirectory); + addSourceContentToRoots(getModule(), dir); + int N = 1000; + PsiJavaFile file0 = (PsiJavaFile)createFile(myModule, dir, "C0.java", "class C0 { }"); + for (int i=1;i { + Collection inheritors = Collections.synchronizedSet(new THashSet<>()); + ProgressManager.getInstance().executeProcessUnderProgress(()-> { + boolean success = ClassInheritorsSearch.search(class0).forEach(new CommonProcessors.CollectProcessor<>(inheritors)); + if (N - 1 != inheritors.size() || !success) { + assertEquals(N - 1, inheritors.size()); + } + }, progress); + }); + myPsiManager.dropResolveCaches(); + //System.out.println("Iterated all"); + delayToCancel--; + } + catch (ProcessCanceledException e) { + //System.out.println("e = " + e); + delayToCancel++; + } + } + } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index c3c5f39dc746..4578edfe355e 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -273,6 +273,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doDuplicatesTest(); } + public void testCodeDuplicatesWithEmptyStatementsBlocksParentheses() throws Exception { + doDuplicatesTest(); + } + public void testCodeDuplicatesWithMultExitPoints() throws Exception { doDuplicatesTest(); } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/library/JpsLibraryTableSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/library/JpsLibraryTableSerializer.java index cb6b581d4f55..eaa2293cb824 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/library/JpsLibraryTableSerializer.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/library/JpsLibraryTableSerializer.java @@ -111,7 +111,7 @@ public class JpsLibraryTableSerializer { } for (Element rootsElement : libraryElement.getChildren()) { final String rootTypeId = rootsElement.getName(); - if (!rootTypeId.equals(JAR_DIRECTORY_TAG)) { + if (!rootTypeId.equals(JAR_DIRECTORY_TAG) && !rootTypeId.equals(PROPERTIES_TAG)) { final JpsOrderRootType rootType = getRootType(rootTypeId); for (Element rootElement : JDOMUtil.getChildren(rootsElement, ROOT_TAG)) { String url = rootElement.getAttributeValue(URL_ATTRIBUTE); diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index 1a6352a76b4f..eeacd0eb13f2 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -385,18 +385,7 @@ public class CompositeElement extends TreeElement { return false; } - @Override - protected int textMatches(@NotNull CharSequence buffer, int start) { - int curOffset = start; - for (TreeElement child = getFirstChildNode(); child != null; child = child.getTreeNext()) { - curOffset = child.textMatches(buffer, curOffset); - if (curOffset < 0) return curOffset; - } - return curOffset; - } - - /* - protected int textMatches(final CharSequence buffer, final int start) { + protected int textMatches(@NotNull final CharSequence buffer, final int start) { final int[] curOffset = {start}; acceptTree(new RecursiveTreeElementWalkingVisitor() { @Override @@ -406,7 +395,7 @@ public class CompositeElement extends TreeElement { private void matchText(TreeElement leaf) { curOffset[0] = leaf.textMatches(buffer, curOffset[0]); - if (curOffset[0] == -1) { + if (curOffset[0] < 0) { stopWalking(); } } @@ -423,7 +412,6 @@ public class CompositeElement extends TreeElement { }); return curOffset[0]; } - */ @Nullable public final PsiElement findChildByRoleAsPsiElement(int role) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index bed9845eceaf..cd4dec4d040b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -39,6 +39,7 @@ import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.diagnostic.FrequentEventDetector; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -125,6 +126,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers private final PassExecutorService myPassExecutorService; private volatile boolean allowToInterrupt = true; + private final FrequentEventDetector myFrequentEventDetector = new FrequentEventDetector(5, 1000); public DaemonCodeAnalyzerImpl(@NotNull Project project, @NotNull DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, @@ -602,13 +604,16 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements Pers return isRunning() || !myAlarm.isEmpty(); } - synchronized void stopProcess(boolean toRestartAlarm, @NonNls String reason) { + synchronized void stopProcess(boolean toRestartAlarm, @NotNull @NonNls String reason) { if (!allowToInterrupt) throw new RuntimeException("Cannot interrupt daemon"); cancelUpdateProgress(toRestartAlarm, reason); myAlarm.cancelAllRequests(); boolean restart = toRestartAlarm && !myDisposed && myInitialized; if (restart) { + if (LOG.isDebugEnabled()) { + myFrequentEventDetector.eventHappened(reason); + } UIUtil.invokeLaterIfNeeded(() -> { if (myAlarm.isEmpty()) { myAlarm.addRequest(myUpdateRunnable, mySettings.AUTOREPARSE_DELAY); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 70a6f69c2eb3..e73df3cf3817 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -266,7 +266,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } public void reinitSettings() { - revalidateMarkup(); + updateSize(false, true); repaint(); } diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index 1c5a17c9ca3e..fa464ca5daf6 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -826,7 +826,9 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { myFadedIn = true; - startFadeoutTimer((int)myFadeoutTime); + if (!myFadeoutAlarm.isDisposed()) { + startFadeoutTimer((int)myFadeoutTime); + } } else { layeredPane.remove(myComp); diff --git a/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java b/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java index 1bbc323877ae..6e17f4b08a41 100644 --- a/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java +++ b/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -15,6 +15,7 @@ */ package org.jetbrains.io; +import com.intellij.openapi.diagnostic.Logger; import io.netty.channel.*; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.ChannelGroupFuture; @@ -22,12 +23,15 @@ import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.ImmediateEventExecutor; import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @ChannelHandler.Sharable public final class ChannelRegistrar extends ChannelInboundHandlerAdapter { - private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); + private static final Logger LOG = Logger.getInstance(ChannelRegistrar.class); + + private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE, true); public boolean isEmpty() { return openChannels.isEmpty(); @@ -64,8 +68,12 @@ public final class ChannelRegistrar extends ChannelInboundHandlerAdapter { Future result; try { + Object[] channels = openChannels.toArray(new Channel[]{}); ChannelGroupFuture groupFuture = openChannels.close(); - groupFuture.awaitUninterruptibly(30, TimeUnit.SECONDS); + // server channels are closed in first turn, so, small timeout is relatively ok + if (!groupFuture.awaitUninterruptibly(10, TimeUnit.SECONDS)) { + LOG.warn("Cannot close all channels for 10 seconds, channels: " + Arrays.toString(channels)); + } result = groupFuture; } finally { diff --git a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java index e311e1a04c75..f68ceef76ad3 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java @@ -328,7 +328,6 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { WriteCommandAction.runWriteCommandAction(null, () -> document.deleteString(0, "/**/".length())); waitTenSecondsForCommit(document); assertTrue("Still not committed: " + document, getPsiDocumentManager().isCommitted(document)); - //System.out.println("i = " + i); } } @@ -629,7 +628,6 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { waitTenSecondsForCommit(document); assertTrue("Still not committed: " + document, getPsiDocumentManager().isCommitted(document)); - System.out.println("i = " + i); } } diff --git a/platform/util/src/com/intellij/util/concurrency/Semaphore.java b/platform/util/src/com/intellij/util/concurrency/Semaphore.java index 079e5acfc6a0..aa48040f3e55 100644 --- a/platform/util/src/com/intellij/util/concurrency/Semaphore.java +++ b/platform/util/src/com/intellij/util/concurrency/Semaphore.java @@ -98,8 +98,4 @@ public class Semaphore { if (sync.tryAcquireShared(1) >= 0) return true; return sync.tryAcquireSharedNanos(1, TimeUnit.MILLISECONDS.toNanos(msTimeout)); } - - public boolean isDown() { - return sync.isAcquired(); - } } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java index 97b13359f297..dd51f9bd0072 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java @@ -72,13 +72,16 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr myVcsManager.addInitializationRequest(VcsInitObject.DIRTY_SCOPE_MANAGER, new Runnable() { @Override public void run() { + boolean ready = false; synchronized (LOCK) { if (!myProject.isDisposed()) { - myReady = true; + myReady = ready = true; } } - VcsDirtyScopeVfsListener.install(myProject); - markEverythingDirty(); + if (ready) { + VcsDirtyScopeVfsListener.install(myProject); + markEverythingDirty(); + } } }); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeVfsListener.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeVfsListener.java index 522b0ce876ae..18bad6462fa5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeVfsListener.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeVfsListener.java @@ -87,6 +87,9 @@ public class VcsDirtyScopeVfsListener implements BulkFileListener, Disposable { } public static void install(@NotNull Project project) { + if (!project.isOpen()) { + throw new RuntimeException("Already closed: " + project); + } getInstance(project); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java index d41d72387a1a..1c9d81536484 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.extractMethod.InputVariables; -import com.intellij.refactoring.util.duplicates.ConditionalReturnStatementValue; -import com.intellij.refactoring.util.duplicates.DuplicatesFinder; -import com.intellij.refactoring.util.duplicates.Match; -import com.intellij.refactoring.util.duplicates.ReturnValue; +import com.intellij.refactoring.util.duplicates.*; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -163,25 +160,31 @@ public class IfStatementWithIdenticalBranchesInspection private static class IfStatementWithIdenticalBranchesVisitor extends BaseInspectionVisitor { + private static PsiStatement unwrap(PsiStatement statement) { + if (statement == null) { + return null; + } + final PsiElement[] children = DuplicatesFinder.getFilteredChildren(statement); + if (children.length == 1 && children[0] instanceof PsiStatement) { + return (PsiStatement) children[0]; + } + return statement; + } + @Override public void visitIfStatement(@NotNull PsiIfStatement ifStatement) { super.visitIfStatement(ifStatement); - final PsiStatement elseBranch = ifStatement.getElseBranch(); - final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = unwrap(ifStatement.getElseBranch()); + final PsiStatement thenBranch = unwrap(ifStatement.getThenBranch()); if (thenBranch == null) { return; } final Project project = ifStatement.getProject(); - final InputVariables inputVariables = - new InputVariables(Collections.emptyList(), - project, new LocalSearchScope(thenBranch), false); - final DuplicatesFinder finder = - new DuplicatesFinder(new PsiElement[]{thenBranch}, - inputVariables, null, - Collections.emptyList()); + final InputVariables inputVariables = new InputVariables(Collections.emptyList(), project, new LocalSearchScope(thenBranch), false); + final DuplicatesFinder finder = new DuplicatesFinder(new PsiElement[]{thenBranch}, inputVariables, null, Collections.emptyList()); if (elseBranch instanceof PsiIfStatement) { final PsiIfStatement statement = (PsiIfStatement)elseBranch; - final PsiStatement branch = statement.getThenBranch(); + final PsiStatement branch = unwrap(statement.getThenBranch()); if (branch == null) { return; } @@ -192,6 +195,9 @@ public class IfStatementWithIdenticalBranchesInspection !matchReturnValue.isEquivalent(buildReturnValue(thenBranch))) { return; } + else if (matchReturnValue instanceof ExpressionReturnValue) { + return; + } registerStatementError(ifStatement, statement); return; } @@ -207,6 +213,9 @@ public class IfStatementWithIdenticalBranchesInspection !matchReturnValue.isEquivalent(buildReturnValue(thenBranch))) { return; } + else if (matchReturnValue instanceof ExpressionReturnValue) { + return; + } registerStatementError(ifStatement); } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java index fef2e0f1f6ff..4c57ca5c142d 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/IfStatementWithIdenticalBranches.java @@ -173,4 +173,45 @@ class NotADup { } System.out.println("j = " + j); } + + void n(int i) { + if (i == 0) { + System.out.println(((i))); + ; + ; + { + } + } + else System.out.println(i); + } + + public static String o(List list) { + String tmp = null; + for (final String comp : list) { + if (!comp.contains("bad")) { + return comp; + } else if (tmp == null) { + tmp = comp; + } + } + return tmp; + } + + Object foo() { + Object a = new Object(); + + while (true) { + Object b = bar(a); + if (b == a) { + return b; + } + else { + a = b; + } + } + } + + private Object bar(Object x) { + return null; + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java index 5cdcd6f4c599..cf37e29068cb 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java @@ -47,7 +47,7 @@ public abstract class GroovyNamedArgumentProvider { @Nullable String argumentName, boolean forCompletion, Map result) { - throw new UnsupportedOperationException(); + // no op } public void getNamedArguments(@NotNull GrCall call, diff --git a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/RepositoryLibraryDescriptor.java b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/RepositoryLibraryDescriptor.java new file mode 100644 index 000000000000..c821d94b31e6 --- /dev/null +++ b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/RepositoryLibraryDescriptor.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2016 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.jps.maven.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Eugene Zhuravlev + * Date: 13-Jun-16 + */ +public class RepositoryLibraryDescriptor { + private final String myMavenId; + private final String myGroupId; + private final String myArtifactId; + private final String myVersion; + + public RepositoryLibraryDescriptor(@NotNull String groupId, @NotNull String artifactId, @NotNull String version) { + myGroupId = groupId; + myArtifactId = artifactId; + myVersion = version; + myMavenId = groupId + ":" + artifactId + ":" + version; + } + + public RepositoryLibraryDescriptor(@Nullable String mavenId) { + myMavenId = mavenId; + if (mavenId == null) { + myGroupId = myArtifactId = myVersion = null; + } + else { + String[] parts = mavenId.split(":"); + myGroupId = parts.length > 0 ? parts[0] : null; + myArtifactId = parts.length > 1 ? parts[1] : null; + myVersion = parts.length > 2 ? parts[2] : null; + } + } + + + public String getMavenId() { + return myMavenId; + } + + public String getGroupId() { + return myGroupId; + } + + public String getArtifactId() { + return myArtifactId; + } + + public String getVersion() { + return myVersion; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RepositoryLibraryDescriptor that = (RepositoryLibraryDescriptor)o; + + if (myMavenId != null ? !myMavenId.equals(that.myMavenId) : that.myMavenId != null) return false; + + return true; + } + + @Override + public int hashCode() { + return myMavenId != null ? myMavenId.hashCode() : 0; + } +} diff --git a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenModelSerializationExtension.java b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenModelSerializationExtension.java index ece4d5cecdf4..7f7a3bf5b851 100644 --- a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenModelSerializationExtension.java +++ b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenModelSerializationExtension.java @@ -6,6 +6,10 @@ import org.jetbrains.jps.maven.model.JpsMavenExtensionService; import org.jetbrains.jps.model.module.JpsDependencyElement; import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension; +import org.jetbrains.jps.model.serialization.library.JpsLibraryPropertiesSerializer; + +import java.util.Collections; +import java.util.List; /** * @author nik @@ -41,4 +45,10 @@ public class JpsMavenModelSerializationExtension extends JpsModelSerializerExten orderEntry.setAttribute(PRODUCTION_ON_TEST_ATTRIBUTE, ""); } } + + @NotNull + @Override + public List> getLibraryPropertiesSerializers() { + return Collections.singletonList(JpsMavenRepositoryLibraryType.createPropertiesSerializer()); + } } diff --git a/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenRepositoryLibraryType.java b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenRepositoryLibraryType.java new file mode 100644 index 000000000000..782ca6f084d0 --- /dev/null +++ b/plugins/maven/jps-plugin/src/org/jetbrains/jps/maven/model/impl/JpsMavenRepositoryLibraryType.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2016 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.jps.maven.model.impl; + +import org.jdom.Element; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.maven.model.RepositoryLibraryDescriptor; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsSimpleElement; +import org.jetbrains.jps.model.ex.JpsElementTypeBase; +import org.jetbrains.jps.model.library.JpsLibraryType; +import org.jetbrains.jps.model.serialization.library.JpsLibraryPropertiesSerializer; + +public class JpsMavenRepositoryLibraryType extends JpsElementTypeBase> + implements JpsLibraryType> { + + public static JpsMavenRepositoryLibraryType INSTANCE = new JpsMavenRepositoryLibraryType(); + private static final String MAVEN_ID_ATTRIBUTE = "maven-id"; + + /** @noinspection MethodMayBeStatic*/ + public final String getTypeId() { + return "repository"; + } + + public static JpsLibraryPropertiesSerializer> createPropertiesSerializer() { + return new JpsLibraryPropertiesSerializer>(INSTANCE, INSTANCE.getTypeId()) { + @Override + public JpsSimpleElement loadProperties(@Nullable Element elem) { + return JpsElementFactory.getInstance().createSimpleElement(new RepositoryLibraryDescriptor( + elem != null? elem.getAttributeValue(MAVEN_ID_ATTRIBUTE, (String)null) : null + )); + } + + @Override + public void saveProperties(JpsSimpleElement properties, Element element) { + final String mavenId = properties.getData().getMavenId(); + if (mavenId != null) { + element.setAttribute(MAVEN_ID_ATTRIBUTE, mavenId); + } + } + }; + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryLibraryProperties.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryLibraryProperties.java index 4aa1d4d5d026..f3d3215eeb81 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryLibraryProperties.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/library/RepositoryLibraryProperties.java @@ -19,38 +19,30 @@ import com.intellij.openapi.roots.libraries.LibraryProperties; import com.intellij.openapi.util.Comparing; import com.intellij.util.xmlb.annotations.Attribute; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.maven.model.RepositoryLibraryDescriptor; + +import java.util.function.Function; /** * @author nik */ public class RepositoryLibraryProperties extends LibraryProperties { - private String mavenId; - private String groupId; - private String artifactId; - private String version; + private RepositoryLibraryDescriptor myDescriptor; public RepositoryLibraryProperties() { } public RepositoryLibraryProperties(String mavenId) { - setMavenId(mavenId); + myDescriptor = new RepositoryLibraryDescriptor(mavenId); } public RepositoryLibraryProperties(@NotNull String groupId, @NotNull String artifactId, @NotNull String version) { - this.groupId = groupId; - this.artifactId = artifactId; - this.version = version; - this.mavenId = groupId + ":" + artifactId + ":" + version; + myDescriptor = new RepositoryLibraryDescriptor(groupId, artifactId, version); } @Override public boolean equals(Object obj) { - if (!(obj instanceof RepositoryLibraryProperties)) { - return false; - } - RepositoryLibraryProperties other = (RepositoryLibraryProperties)obj; - return Comparing.equal(mavenId, other.mavenId); - + return obj instanceof RepositoryLibraryProperties && Comparing.equal(myDescriptor, ((RepositoryLibraryProperties)obj).myDescriptor); } @Override @@ -65,41 +57,36 @@ public class RepositoryLibraryProperties extends LibraryProperties 0 ? parts[0] : null; - artifactId = parts.length > 1 ? parts[1] : null; - version = parts.length > 2 ? parts[2] : null; - } + myDescriptor = new RepositoryLibraryDescriptor(mavenId); } public String getGroupId() { - return groupId; + return call(RepositoryLibraryDescriptor::getGroupId); } public String getArtifactId() { - return artifactId; + return call(RepositoryLibraryDescriptor::getArtifactId); } public String getVersion() { - return version; + return call(RepositoryLibraryDescriptor::getVersion); } public void changeVersion(String version) { - this.version = version; - this.mavenId = groupId + ":" + artifactId + ":" + version; + myDescriptor = new RepositoryLibraryDescriptor(getGroupId(), getArtifactId(), version); + } + + private String call(Function method) { + final RepositoryLibraryDescriptor descriptor = myDescriptor; + return descriptor != null ? method.apply(descriptor) : null; } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 937c6d8d22ff..78f8a7133005 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -457,7 +457,7 @@ public class StudyUtils { private static String getTaskTextFrom(@NotNull VirtualFile taskDirectory, @NotNull String taskTextFilename) { VirtualFile taskTextFile = taskDirectory.findChild(taskTextFilename); if (taskTextFile == null) { - VirtualFile srcDir = taskDirectory.findChild("src"); + VirtualFile srcDir = taskDirectory.findChild(EduNames.SRC); if (srcDir != null) { taskTextFile = srcDir.findChild(taskTextFilename); } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java index a37bdfc4f343..c3db44d3cf6b 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java @@ -98,6 +98,11 @@ public class PyRenameElementQuickFix implements LocalQuickFix { return null; } + @Override + public boolean startInWriteAction() { + return false; + } + private static void renameInUnitTestMode(@NotNull Project project, @NotNull PsiNameIdentifierOwner nameOwner, @Nullable Editor editor) { final PsiElement substitution = RenamePsiElementProcessor.forElement(nameOwner).substituteElementToRename(nameOwner, editor); diff --git a/spellchecker/src/com/intellij/spellchecker/actions/SpellingPopupActionGroup.java b/spellchecker/src/com/intellij/spellchecker/actions/SpellingPopupActionGroup.java index c6fa374b47f0..6c2d7c598ef5 100644 --- a/spellchecker/src/com/intellij/spellchecker/actions/SpellingPopupActionGroup.java +++ b/spellchecker/src/com/intellij/spellchecker/actions/SpellingPopupActionGroup.java @@ -128,14 +128,20 @@ public final class SpellingPopupActionGroup extends ActionGroup { final Project project = e.getData(LangDataKeys.PROJECT); final Editor editor = e.getData(LangDataKeys.EDITOR); if (psiFile != null && project != null && editor != null) { - ApplicationManager.getApplication().runWriteAction(() -> CommandProcessor.getInstance().executeCommand(project, () -> { + final Runnable runnable = () -> CommandProcessor.getInstance().executeCommand(project, () -> { try { intention.invoke(project, editor, psiFile); } catch (IncorrectOperationException ex) { LOGGER.error(ex); } - }, e.getPresentation().getText(), e.getActionManager().getId(SpellCheckerIntentionAction.this))); + }, e.getPresentation().getText(), e.getActionManager().getId(this)); + if (intention.startInWriteAction()) { + ApplicationManager.getApplication().runWriteAction(runnable); + } + else { + runnable.run(); + } } } }