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 super V> myApplicableFilter;
+ @NotNull private final Predicate super V> 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 super V> applicableFilter,
+ @NotNull Predicate super V> 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 extends JpsLibraryPropertiesSerializer>> 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();
+ }
}
}
}