mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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/");
|
||||
}
|
||||
|
||||
@@ -919,6 +919,21 @@
|
||||
</test>
|
||||
</regressions>
|
||||
|
||||
<options>
|
||||
<test host="com.intellij.psi.impl.JavaRegExpHost">
|
||||
<pattern><![CDATA[(?i<error descr="Unknown inline option flag">Z</error>m)abc]]></pattern>
|
||||
<expected>OK</expected>
|
||||
</test>
|
||||
<test host="com.intellij.psi.impl.JavaRegExpHost">
|
||||
<pattern>(?idmsuxU)nice</pattern>
|
||||
<expected>OK</expected>
|
||||
</test>
|
||||
<test host="com.intellij.psi.impl.JavaRegExpHost">
|
||||
<pattern verify="false">(?idm-suxU)one(?suxU-idm)two</pattern>
|
||||
<expected>OK</expected>
|
||||
</test>
|
||||
</options>
|
||||
|
||||
<test>
|
||||
<pattern>abc)</pattern>
|
||||
<expected>ERR</expected>
|
||||
|
||||
+22
-13
@@ -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<PsiElement> array = new ArrayList<PsiElement>();
|
||||
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);
|
||||
}
|
||||
|
||||
+6
-12
@@ -83,7 +83,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
|
||||
return processLocalScope(project, parameters, (LocalSearchScope)searchScope, baseClass, consumer);
|
||||
}
|
||||
|
||||
Iterable<PsiClass> cached = getOrComputeSubClasses(project, baseClass);
|
||||
Iterable<PsiClass> cached = getOrComputeSubClasses(project, baseClass, searchScope);
|
||||
|
||||
for (final PsiClass subClass : cached) {
|
||||
ProgressManager.checkCanceled();
|
||||
@@ -99,7 +99,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Iterable<PsiClass> getOrComputeSubClasses(@NotNull Project project, @NotNull PsiClass baseClass) {
|
||||
private static Iterable<PsiClass> getOrComputeSubClasses(@NotNull Project project, @NotNull PsiClass baseClass, @NotNull SearchScope searchScopeForNonPhysical) {
|
||||
ConcurrentMap<PsiClass, Iterable<PsiClass>> map = HighlightingCaches.getInstance(project).ALL_SUB_CLASSES;
|
||||
Iterable<PsiClass> cached = map.get(baseClass);
|
||||
if (cached == null) {
|
||||
@@ -108,8 +108,11 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
|
||||
anchor -> ApplicationManager.getApplication().runReadAction((Computable<PsiClass>)() -> (PsiClass)anchor.retrieve());
|
||||
Predicate<PsiClass> 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<Boolean>)baseClass::isPhysical);
|
||||
SearchScope scopeToUse = isPhysical ? GlobalSearchScope.allScope(project) : searchScopeForNonPhysical;
|
||||
LazyConcurrentCollection.MoreElementsGenerator<PsiAnchor, PsiClass> 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>)() -> 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<PsiClass, Cla
|
||||
PsiAnchor seed = ApplicationManager.getApplication().runReadAction((Computable<PsiAnchor>)() -> PsiAnchor.create(baseClass));
|
||||
// lazy collection: store underlying queue as PsiAnchors, generate new elements by running direct inheritors
|
||||
Iterable<PsiClass> 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<Boolean>)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<PsiClass, Cla
|
||||
}
|
||||
super.visitClass(candidate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCodeBlock(PsiCodeBlock block) {
|
||||
ProgressManager.checkCanceled();
|
||||
if (!parameters.isIncludeAnonymous()) return;
|
||||
super.visitCodeBlock(block);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+89
-57
@@ -30,6 +30,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Collection of elements of type V which is
|
||||
@@ -53,9 +54,9 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
|
||||
// If more elements requested for this iterator, the processMoreSubclasses() is called which tries to populate 'subClasses' with more inheritors.
|
||||
private final HashSetQueue<T> subClasses; // guarded by lock
|
||||
private final Object lock = new Object(); // MUST NOT acquire read action inside this lock
|
||||
@NotNull private final Function<T, V> myConvertor;
|
||||
@NotNull private final Function<T, V> myAnchorToValueConvertor;
|
||||
@NotNull private final MoreElementsGenerator<T,V> 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<T> candidatesToFindSubclassesIterator; // guarded by lock
|
||||
@@ -67,13 +68,13 @@ class LazyConcurrentCollection<T,V> implements Iterable<V> {
|
||||
|
||||
LazyConcurrentCollection(@NotNull T seedElement,
|
||||
@NotNull Function<T, V> convertor,
|
||||
@NotNull Predicate<? super V> applicableFilter,
|
||||
@NotNull Predicate<? super V> applicableForGenerationFilter,
|
||||
@NotNull MoreElementsGenerator<T, V> 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<T,V> implements Iterable<V> {
|
||||
synchronized (lock) {
|
||||
next = subClassIterator.next();
|
||||
}
|
||||
return myConvertor.fun(next);
|
||||
return myAnchorToValueConvertor.fun(next);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Pair.NonNull<T,V> findNextClassInQueue(@NotNull HashSetQueue.PositionalIterator.IteratorPosition<T> 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<T> subClassIterator) {
|
||||
// returns true if some classes were found
|
||||
private boolean processMoreSubclasses(@NotNull Iterator<T> subClassIterator) {
|
||||
while (true) {
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
Pair.NonNull<T,V> pair =
|
||||
ApplicationManager.getApplication().runReadAction(new Computable<Pair.NonNull<T,V>>() {
|
||||
@Override
|
||||
public Pair.NonNull<T,V> 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<T> startPosition = candidatesToFindSubclassesIterator.position().next();
|
||||
Pair.NonNull<T,V> pair = startPosition == null ? null : findNextClassInQueue(startPosition);
|
||||
if (pair != null) {
|
||||
currentlyProcessingClasses.down();
|
||||
}
|
||||
return pair;
|
||||
ApplicationManager.getApplication().runReadAction((Computable<Pair.NonNull<T,V>>)() -> {
|
||||
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<T> startPosition = candidatesToFindSubclassesIterator.position().next();
|
||||
Pair.NonNull<T,V> 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<T,V> implements Iterable<V> {
|
||||
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<T> 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<T,V> implements Iterable<V> {
|
||||
@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<T,V> implements Iterable<V> {
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return hasNext.get();
|
||||
}
|
||||
|
||||
private void advanceIteratorOnSuccess() {
|
||||
HashSetQueue.PositionalIterator.IteratorPosition<T> position = candidatesToFindSubclassesIterator.position().next();
|
||||
// under lock
|
||||
private Pair.NonNull<T,V> findNextClassInQueue(@NotNull HashSetQueue.PositionalIterator.IteratorPosition<T> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PsiClassType.ClassResolveResult> 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<List<PsiClassType.ClassResolveResult>>() {
|
||||
@Override
|
||||
public List<PsiClassType.ClassResolveResult> 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<PsiClassType.ClassResolveResult> calcImmediateSupersWithCapturing() {
|
||||
List<PsiClassType.ClassResolveResult> 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<PsiClass, PsiSubstitutor> calcAllMemberSupers(final LanguageLevel level) {
|
||||
final Map<PsiClass, PsiSubstitutor> map = ContainerUtil.newTroveMap();
|
||||
|
||||
+7
-2
@@ -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)) {
|
||||
|
||||
+11
-6
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import p.AccountCalculator;
|
||||
import p.ObjectParameterDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class Test {
|
||||
public static void calc(AccountCalculator calculator,
|
||||
ObjectParameterDescriptor<String>.Holder holder) throws IOException{
|
||||
calculator.getMetrics(holder);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
+19
@@ -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 <Om> List<Om> sort(Comparator comp, Stream<Om> stream) {
|
||||
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.util.List<Om>'">return stream.sorted(comp).collect(Collectors.toList());</error>
|
||||
}
|
||||
|
||||
//accept unbounded wildcards
|
||||
List<String> get(List<?> lists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void foo(List l) {
|
||||
String p = get(l).get(0);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
class Test {
|
||||
|
||||
public void method1()
|
||||
{
|
||||
System.out.println(((1)));
|
||||
;;
|
||||
System.out.println(2);
|
||||
}
|
||||
|
||||
public void method2()
|
||||
{
|
||||
<selection>System.out.println(1);
|
||||
System.out.println(2);</selection>
|
||||
}
|
||||
}
|
||||
+17
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,10 @@ public class ClsGenerics18HighlightingTest extends ClsGenericsHighlightingTest {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIDEA157254() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testOuterClassTypeArgs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
+4
@@ -994,4 +994,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
|
||||
public void testNestedCaptures() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testErasureOfReturnTypeOfNonGenericMethod() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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<String> 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<N ;i++) {
|
||||
int extI = i - 1 - (i - 1) % 10; // 10 inheritors
|
||||
createFile(myModule, dir, "C" + i + ".java", "class C" + i + " extends C" + extI + " { }");
|
||||
}
|
||||
PsiClass class0 = file0.getClasses()[0];
|
||||
|
||||
int delayToCancel = 100;
|
||||
for (int i=0;i<1000;i++) {
|
||||
//System.out.println("i = " + i+ "; delayToCancel="+delayToCancel);
|
||||
StandardProgressIndicatorBase progress = new StandardProgressIndicatorBase();
|
||||
JobScheduler.getScheduler().schedule(progress::cancel, delayToCancel, TimeUnit.MILLISECONDS);
|
||||
try {
|
||||
Collections.nCopies(Runtime.getRuntime().availableProcessors(), "").stream().parallel().forEach(__ -> {
|
||||
Collection<PsiClass> 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +273,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
doDuplicatesTest();
|
||||
}
|
||||
|
||||
public void testCodeDuplicatesWithEmptyStatementsBlocksParentheses() throws Exception {
|
||||
doDuplicatesTest();
|
||||
}
|
||||
|
||||
public void testCodeDuplicatesWithMultExitPoints() throws Exception {
|
||||
doDuplicatesTest();
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+6
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -266,7 +266,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
}
|
||||
|
||||
public void reinitSettings() {
|
||||
revalidateMarkup();
|
||||
updateSize(false, true);
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+24
-15
@@ -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.<PsiVariable>emptyList(),
|
||||
project, new LocalSearchScope(thenBranch), false);
|
||||
final DuplicatesFinder finder =
|
||||
new DuplicatesFinder(new PsiElement[]{thenBranch},
|
||||
inputVariables, null,
|
||||
Collections.<PsiVariable>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);
|
||||
}
|
||||
}
|
||||
|
||||
+41
@@ -173,4 +173,45 @@ class NotADup {
|
||||
}
|
||||
System.out.println("j = " + j);
|
||||
}
|
||||
|
||||
void n(int i) {
|
||||
<warning descr="'if' statement with identical branches">if</warning> (i == 0) {
|
||||
System.out.println(((i)));
|
||||
;
|
||||
;
|
||||
{
|
||||
}
|
||||
}
|
||||
else System.out.println(i);
|
||||
}
|
||||
|
||||
public static String o(List<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ public abstract class GroovyNamedArgumentProvider {
|
||||
@Nullable String argumentName,
|
||||
boolean forCompletion,
|
||||
Map<String, NamedArgumentDescriptor> result) {
|
||||
throw new UnsupportedOperationException();
|
||||
// no op
|
||||
}
|
||||
|
||||
public void getNamedArguments(@NotNull GrCall call,
|
||||
|
||||
+84
@@ -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;
|
||||
}
|
||||
}
|
||||
+10
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+56
@@ -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<JpsSimpleElement<RepositoryLibraryDescriptor>>
|
||||
implements JpsLibraryType<JpsSimpleElement<RepositoryLibraryDescriptor>> {
|
||||
|
||||
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<JpsSimpleElement<RepositoryLibraryDescriptor>> createPropertiesSerializer() {
|
||||
return new JpsLibraryPropertiesSerializer<JpsSimpleElement<RepositoryLibraryDescriptor>>(INSTANCE, INSTANCE.getTypeId()) {
|
||||
@Override
|
||||
public JpsSimpleElement<RepositoryLibraryDescriptor> 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<RepositoryLibraryDescriptor> properties, Element element) {
|
||||
final String mavenId = properties.getData().getMavenId();
|
||||
if (mavenId != null) {
|
||||
element.setAttribute(MAVEN_ID_ATTRIBUTE, mavenId);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+19
-32
@@ -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<RepositoryLibraryProperties> {
|
||||
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<RepositoryLib
|
||||
|
||||
@Override
|
||||
public void loadState(RepositoryLibraryProperties state) {
|
||||
setMavenId(state.mavenId);
|
||||
myDescriptor = state.myDescriptor;
|
||||
}
|
||||
|
||||
@Attribute("maven-id")
|
||||
public String getMavenId() {
|
||||
return mavenId;
|
||||
return call(RepositoryLibraryDescriptor::getMavenId);
|
||||
}
|
||||
|
||||
public void setMavenId(String mavenId) {
|
||||
this.mavenId = mavenId;
|
||||
if (mavenId == null) {
|
||||
groupId = artifactId = version = null;
|
||||
}
|
||||
else {
|
||||
String[] parts = mavenId.split(":");
|
||||
groupId = parts.length > 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<RepositoryLibraryDescriptor, String> method) {
|
||||
final RepositoryLibraryDescriptor descriptor = myDescriptor;
|
||||
return descriptor != null ? method.apply(descriptor) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user