Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2016-06-14 15:16:40 +03:00
39 changed files with 595 additions and 182 deletions
@@ -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/");
}
+15
View File
@@ -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>
@@ -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);
}
@@ -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);
}
});
}
}
@@ -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();
@@ -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)) {
@@ -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);
}
}
@@ -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);
}
}
@@ -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>
}
}
@@ -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();
}
@@ -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();
}
@@ -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) {
@@ -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);
@@ -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();
}
}
@@ -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);
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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,
@@ -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;
}
}
@@ -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());
}
}
@@ -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,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();
}
}
}
}