Merge remote-tracking branch 'origin/master'

This commit is contained in:
Roman Shevchenko
2016-03-17 21:01:59 +01:00
59 changed files with 594 additions and 443 deletions
@@ -101,18 +101,8 @@ public class JavaGenericsUtil {
final PsiExpression[] args = argumentList.getExpressions();
if (args.length == parametersCount) {
final PsiExpression lastArg = args[args.length - 1];
if (lastArg instanceof PsiReferenceExpression) {
final PsiElement lastArgsResolve = ((PsiReferenceExpression)lastArg).resolve();
if (lastArgsResolve instanceof PsiParameter) {
if (((PsiParameter)lastArgsResolve).getType() instanceof PsiArrayType) {
return false;
}
}
}
else if (lastArg instanceof PsiMethodCallExpression) {
if (lastArg.getType() instanceof PsiArrayType) {
return false;
}
if (lastArg.getType() instanceof PsiArrayType) {
return false;
}
}
for (int i = parametersCount - 1; i < args.length; i++) {
@@ -37,7 +37,10 @@ import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import static com.intellij.util.ObjectUtils.assertNotNull;
@@ -140,15 +143,7 @@ public class ChangeSignatureProcessor extends ChangeSignatureProcessorBase {
if (!processor.setupDefaultValues(myChangeInfo, refUsages, myProject)) return false;
}
MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
final MultiMap<PsiElement, String> conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages);
for (PsiElement key : conflicts.keySet()) {
Collection<String> collection = conflictDescriptions.get(key);
if (collection.size() == 0) collection = new HashSet<String>();
collection.addAll(conflicts.get(key));
conflictDescriptions.put(key, collection);
}
}
collectConflictsFromExtensions(refUsages, conflictDescriptions, myChangeInfo);
final UsageInfo[] usagesIn = refUsages.get();
RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
@@ -38,6 +38,8 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.MoveDestination;
import com.intellij.refactoring.RefactorJBundle;
import com.intellij.refactoring.changeSignature.ChangeInfo;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase;
import com.intellij.refactoring.introduceparameterobject.usageInfo.*;
import com.intellij.refactoring.util.FixableUsageInfo;
import com.intellij.refactoring.util.FixableUsagesRefactoringProcessor;
@@ -77,6 +79,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
private final Set<PsiParameter> paramsNeedingGetters = new HashSet<PsiParameter>();
private final PsiClass existingClass;
private PsiMethod myExistingClassCompatibleConstructor;
private ChangeInfo myChangeInfo;
public IntroduceParameterObjectProcessor(String className,
String packageName,
@@ -164,6 +167,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
}
}
}
List<UsageInfo> changeSignatureUsages = new ArrayList<>();
for (UsageInfo usageInfo : refUsages.get()) {
if (usageInfo instanceof FixableUsageInfo) {
final String conflictMessage = ((FixableUsageInfo)usageInfo).getConflictMessage();
@@ -171,7 +175,13 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
conflicts.putValue(usageInfo.getElement(), conflictMessage);
}
}
else {
changeSignatureUsages.add(usageInfo);
}
}
ChangeSignatureProcessorBase.collectConflictsFromExtensions(new Ref<>(changeSignatureUsages.toArray(new UsageInfo[changeSignatureUsages.size()])), conflicts, myChangeInfo);
return showConflicts(conflicts, refUsages.get());
}
@@ -179,7 +189,24 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
if (myUseExistingClass && existingClass != null) {
myExistingClassCompatibleConstructor = existingClassIsCompatible(existingClass, parameters);
}
findUsagesForMethod(method, usages, true);
final PsiCodeBlock body = method.getBody();
final String baseParameterName = StringUtil.decapitalize(className);
final String fixedParamName =
body != null
? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true)
: JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER);
myChangeInfo =
new MergeMethodArguments(method, className, packageName, fixedParamName, paramsToMerge, typeParams, keepMethodAsDelegate,
myCreateInnerClass ? method.getContainingClass() : null).createChangeInfo();
for (UsageInfo info : ChangeSignatureProcessorBase.findUsages(myChangeInfo)) {
usages.add(new ChangeSignatureUsageWrapper(info));
}
findUsagesForMethod(method, usages, fixedParamName);
if (myUseExistingClass && existingClass != null && !(paramsNeedingGetters.isEmpty() && paramsNeedingSetters.isEmpty())) {
usages.add(new AppendAccessorsUsageInfo(existingClass, myGenerateAccessors, paramsNeedingGetters, paramsNeedingSetters, parameters));
@@ -187,7 +214,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
final PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY);
for (PsiMethod siblingMethod : overridingMethods) {
findUsagesForMethod(siblingMethod, usages, false);
findUsagesForMethod(siblingMethod, usages, fixedParamName);
}
if (myNewVisibility != null) {
@@ -195,16 +222,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
}
}
private void findUsagesForMethod(PsiMethod overridingMethod, List<FixableUsageInfo> usages, boolean changeSignature) {
final PsiCodeBlock body = overridingMethod.getBody();
final String baseParameterName = StringUtil.decapitalize(className);
final String fixedParamName =
body != null
? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true)
: JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER);
usages.add(new MergeMethodArguments(overridingMethod, className, packageName, fixedParamName, paramsToMerge, typeParams, keepMethodAsDelegate, myCreateInnerClass ? method.getContainingClass() : null, changeSignature));
private void findUsagesForMethod(PsiMethod overridingMethod, List<FixableUsageInfo> usages, String fixedParamName) {
final ParamUsageVisitor visitor = new ParamUsageVisitor(overridingMethod, paramsToMerge);
overridingMethod.accept(visitor);
final Set<PsiReferenceExpression> values = visitor.getParameterUsages();
@@ -261,6 +279,13 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
}
}
}
List<UsageInfo> changeSignatureUsages = new ArrayList<>();
for (UsageInfo info : usageInfos) {
if (info instanceof ChangeSignatureUsageWrapper) {
changeSignatureUsages.add(((ChangeSignatureUsageWrapper)info).getInfo());
}
}
ChangeSignatureProcessorBase.doChangeSignature(myChangeInfo, changeSignatureUsages.toArray(new UsageInfo[changeSignatureUsages.size()]));
}
}
@@ -537,4 +562,20 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP
}
}
private static class ChangeSignatureUsageWrapper extends FixableUsageInfo {
private final UsageInfo myInfo;
public ChangeSignatureUsageWrapper(UsageInfo info) {
super(info.getElement());
myInfo = info;
}
public UsageInfo getInfo() {
return myInfo;
}
@Override
public void fixUsage() throws IncorrectOperationException {}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 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.
@@ -13,32 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.refactoring.introduceparameterobject.usageInfo;
package com.intellij.refactoring.introduceparameterobject;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
import com.intellij.refactoring.changeSignature.ChangeInfo;
import com.intellij.refactoring.changeSignature.JavaChangeInfoImpl;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
import com.intellij.refactoring.util.FixableUsageInfo;
import com.intellij.refactoring.util.CanonicalTypes;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@SuppressWarnings({"MethodWithTooManyParameters"})
public class MergeMethodArguments extends FixableUsageInfo {
public class MergeMethodArguments {
private final PsiMethod method;
private final PsiClass myContainingClass;
private final boolean myChangeSignature;
private final boolean myKeepMethodAsDelegate;
private final List<PsiTypeParameter> typeParams;
private final String className;
@@ -53,50 +50,45 @@ public class MergeMethodArguments extends FixableUsageInfo {
String parameterName,
int[] paramsToMerge,
List<PsiTypeParameter> typeParams,
final boolean keepMethodAsDelegate, final PsiClass containingClass, boolean changeSignature) {
super(method);
final boolean keepMethodAsDelegate,
final PsiClass containingClass) {
this.paramsToMerge = paramsToMerge;
this.packageName = packageName;
this.className = className;
this.parameterName = parameterName;
this.method = method;
myContainingClass = containingClass;
myChangeSignature = changeSignature;
lastParamIsVararg = method.isVarArgs() && isParameterToMerge(method.getParameterList().getParametersCount() - 1);
myKeepMethodAsDelegate = keepMethodAsDelegate;
this.typeParams = new ArrayList<PsiTypeParameter>(typeParams);
}
public void fixUsage() throws IncorrectOperationException {
public ChangeInfo createChangeInfo() {
final Project project = method.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiMethod deepestSuperMethod = method.findDeepestSuperMethod();
final PsiClass psiClass;
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
String packageName;
if (myContainingClass != null) {
psiClass = myContainingClass.findInnerClassByName(className, false);
}
else {
psiClass = psiFacade.findClass(StringUtil.getQualifiedName(packageName, className), GlobalSearchScope.allScope(project));
}
assert psiClass != null;
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
if (deepestSuperMethod != null) {
final PsiClass parentClass = deepestSuperMethod.getContainingClass();
final PsiSubstitutor parentSubstitutor =
TypeConversionUtil.getSuperClassSubstitutor(parentClass, method.getContainingClass(), PsiSubstitutor.EMPTY);
for (int i1 = 0; i1 < psiClass.getTypeParameters().length; i1++) {
final PsiTypeParameter typeParameter = psiClass.getTypeParameters()[i1];
for (PsiTypeParameter parameter : parentClass.getTypeParameters()) {
if (Comparing.strEqual(typeParameter.getName(), parameter.getName())) {
subst = subst.put(typeParameter, parentSubstitutor.substitute(
new PsiImmediateClassType(parameter, PsiSubstitutor.EMPTY)));
break;
}
}
packageName = myContainingClass.getQualifiedName();
if (packageName == null) {
packageName = myContainingClass.getName();
}
}
else {
packageName = this.packageName;
}
String text = StringUtil.getQualifiedName(packageName, className);
if (!typeParams.isEmpty()) {
text += "<" + StringUtil.join(typeParams, new Function<PsiTypeParameter, String>() {
@Override
public String fun(PsiTypeParameter parameter) {
return parameter.getName();
}
}, ", ") + ">";
}
final PsiType classType = factory.createTypeFromText(text, method);
final List<ParameterInfoImpl> parametersInfo = new ArrayList<ParameterInfoImpl>();
final PsiClassType classType = JavaPsiFacade.getElementFactory(project).createType(psiClass, subst);
final ParameterInfoImpl mergedParamInfo = new ParameterInfoImpl(-1, parameterName, classType, null) {
@Override
@@ -117,33 +109,16 @@ public class MergeMethodArguments extends FixableUsageInfo {
}
parametersInfo.add(firstIncludedIdx == -1 ? 0 : firstIncludedIdx, mergedParamInfo);
final SmartPsiElementPointer<PsiMethod> meth = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(method);
final Runnable performChangeSignatureRunnable = new Runnable() {
@Override
public void run() {
final PsiMethod psiMethod = meth.getElement();
if (psiMethod == null) return;
if (myChangeSignature) {
final ChangeSignatureProcessor changeSignatureProcessor =
new ChangeSignatureProcessor(psiMethod.getProject(), psiMethod,
myKeepMethodAsDelegate, null, psiMethod.getName(),
psiMethod.getReturnType(),
parametersInfo.toArray(new ParameterInfoImpl[parametersInfo.size()]));
changeSignatureProcessor.run();
}
}
};
if (ApplicationManager.getApplication().isUnitTestMode()) {
performChangeSignatureRunnable.run();
} else {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
CommandProcessor.getInstance().runUndoTransparentAction(performChangeSignatureRunnable);
}
});
}
PsiType returnType = method.getReturnType();
return new JavaChangeInfoImpl(VisibilityUtil.getVisibilityModifier(method.getModifierList()),
method,
method.getName(),
returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null,
parametersInfo.toArray(new ParameterInfoImpl[parametersInfo.size()]),
null,
myKeepMethodAsDelegate,
Collections.emptySet(),
Collections.emptySet());
}
private boolean isParameterToMerge(int index) {
@@ -307,7 +307,10 @@ public class GenericsUtil {
PsiType componentType = arrayType.getComponentType();
PsiType type = componentType.accept(this);
if (type == componentType) return arrayType;
return type.createArrayType();
if (type instanceof PsiWildcardType) {
type = ((PsiWildcardType)type).getBound();
}
return type != null ? type.createArrayType() : arrayType;
}
@Override
@@ -764,6 +764,9 @@ public final class PsiUtil extends PsiUtilCore {
return null;
}
/**
* Applies capture conversion to the type in context
*/
@NotNull
public static PsiType captureToplevelWildcards(@NotNull final PsiType type, @NotNull final PsiElement context) {
if (type instanceof PsiClassType) {
@@ -811,6 +814,38 @@ public final class PsiUtil extends PsiUtilCore {
return type;
}
/**
* Opens top level captured wildcards and remap them according to the context.
* The only valid purpose: allow to speculate on non-physical expressions about types, e.g. to detect redundant casts with 'wildcards'
*/
public static PsiType recaptureWildcards(PsiType type, PsiElement context) {
if (type instanceof PsiClassType) {
final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
final PsiClass aClass = resolveResult.getElement();
if (aClass != null) {
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
PsiSubstitutor resultSubstitution = null;
for (PsiTypeParameter parameter : substitutor.getSubstitutionMap().keySet()) {
final PsiType substitute = substitutor.substitute(parameter);
if (substitute instanceof PsiCapturedWildcardType) {
if (resultSubstitution == null) resultSubstitution = substitutor;
resultSubstitution = resultSubstitution.put(parameter, ((PsiCapturedWildcardType)substitute).getWildcard());
}
}
if (resultSubstitution != null) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
return captureToplevelWildcards(factory.createType(aClass, resultSubstitution), context);
}
}
}
else if (type instanceof PsiArrayType) {
return recaptureWildcards(((PsiArrayType)type).getComponentType(), context).createArrayType();
}
return type;
}
public static boolean isInsideJavadocComment(PsiElement element) {
return PsiTreeUtil.getParentOfType(element, PsiDocComment.class, true) != null;
}
@@ -385,7 +385,7 @@ public class RedundantCastUtil {
if (oldMethod.equals(newResult.getElement()) &&
(!(newCall instanceof PsiCallExpression) ||
oldAnonymousClass != null && newAnonymousClass != null && Comparing.equal(oldAnonymousClass.getBaseClassType(), newAnonymousClass.getBaseClassType()) ||
Comparing.equal(((PsiCallExpression)newCall).getType(), ((PsiCallExpression)expression).getType())) &&
Comparing.equal(PsiUtil.recaptureWildcards(((PsiCallExpression)newCall).getType(), expression), ((PsiCallExpression)expression).getType())) &&
newResult.isValidResult()) {
if (!(newArgs[i] instanceof PsiFunctionalExpression) || castType != null && castType.equals(((PsiFunctionalExpression)newArgs[i]).getFunctionalInterfaceType())) {
addToResults(cast);
@@ -29,6 +29,14 @@ class Test {
public static void main(String[] args) {
<warning descr="Unchecked generics array creation for varargs parameter">asList</warning>(new ArrayList<String>());
ArrayList<String>[] arrayOfStrings = null;
asList(arrayOfStrings);
asList((ArrayList<String>[])null);
//overload should be chosen before target type is known -> inference failure
<error descr="Incompatible types. Found: 'java.util.List<java.util.ArrayList<java.lang.String>>', required: 'java.util.List<java.util.ArrayList<java.lang.String>[]>'">List<ArrayList<String>[]> arraysList = asList(arrayOfStrings);</error>
System.out.println(arraysList);
asListSuppressed(new ArrayList<String>());
//noinspection unchecked
@@ -0,0 +1,9 @@
import java.util.function.IntFunction;
import java.util.stream.Stream;
class MyTest {
private static void getArguments(final Stream<Class<String>> classStream) {
final Class<?>[] classes = classStream.toArray(((<warning descr="Casting '(value) -> new Class<?>[value]' to 'IntFunction<Class<?>[]>' is redundant">IntFunction<Class<?>[]></warning>) (value) -> new Class<?>[value]) );
}
}
@@ -0,0 +1,9 @@
import java.util.function.IntFunction;
import java.util.stream.Stream;
class MyTest {
private static void getArguments(final Stream<Class<String>> classStream) {
IntFunction<Class<?>[]> m = (value) -> new Class<?>[value];
final Class<?>[] classes = classStream.toArray(m);
}
}
@@ -0,0 +1,7 @@
import java.util.stream.Stream;
class MyTest {
private static void getArguments(final Stream<Class<String>> classStream) {
final Class<?>[] classes = classStream.toArray(<selection>(value) -> new Class<?>[value]</selection>);
}
}
@@ -61,6 +61,10 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testCapturedWildcardInCast() throws Exception {
doTest();
}
private void doTest() {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
}
@@ -512,6 +512,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
doTest(new MockIntroduceVariableHandler("m", false, false, false, "I<? extends I<?>>"));
}
public void testDenotableType3() {
doTest(new MockIntroduceVariableHandler("m", false, false, false, "java.util.function.IntFunction<java.lang.Class<?>[]>"));
}
public void testReturnNonExportedArray() {
doTest(new MockIntroduceVariableHandler("i", false, false, false, "java.io.File[]") {
@Override
@@ -161,11 +161,6 @@ public abstract class TransactionGuard {
@NotNull
public abstract AccessToken startSynchronousTransaction(@NotNull TransactionKind kind);
/**
* @return whether there's a transaction currently running
*/
public abstract boolean isInsideTransaction();
/**
* When on UI thread and there's no other transaction running, executes the given runnable. If there is a transaction running,
* but the given {@code kind} is allowed via {@link #acceptNestedTransactions(TransactionKind...)}, merges two transactions
@@ -190,4 +185,11 @@ public abstract class TransactionGuard {
*/
@NotNull
public abstract AccessToken acceptNestedTransactions(TransactionKind... kinds);
/**
* Asserts that a transaction is currently running, or not. Callable only on Swing thread.
* @param transactionRequired whether the assertion should check that the application is inside transaction or not
* @param errorMessage the message that will be logged if current transaction status differs from the expected one
*/
public abstract void assertInsideTransaction(boolean transactionRequired, @NotNull String errorMessage);
}
@@ -18,16 +18,20 @@ package com.intellij.pom;
import com.intellij.pom.event.PomModelEvent;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
/**
* @author ik
*/
public interface PomTransaction {
@NotNull
PomModelEvent getAccumulatedEvent();
void run() throws IncorrectOperationException;
@NotNull
PsiElement getChangeScope();
@NotNull
PomModelAspect getTransactionAspect();
}
@@ -21,18 +21,20 @@ import com.intellij.pom.PomTransaction;
import com.intellij.pom.event.PomModelEvent;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class PomTransactionBase implements PomTransaction{
private final PsiElement myScope;
private final PomModelAspect myAspect;
private final PomModelEvent myAccumulatedEvent;
public PomTransactionBase(PsiElement scope, final PomModelAspect aspect){
public PomTransactionBase(@NotNull PsiElement scope, @NotNull final PomModelAspect aspect){
myScope = scope;
myAspect = aspect;
myAccumulatedEvent = new PomModelEvent(PomManager.getModel(scope.getProject()));
}
@NotNull
@Override
public PomModelEvent getAccumulatedEvent() {
return myAccumulatedEvent;
@@ -53,11 +55,13 @@ public abstract class PomTransactionBase implements PomTransaction{
@Nullable
public abstract PomModelEvent runInner() throws IncorrectOperationException;
@NotNull
@Override
public PsiElement getChangeScope() {
return myScope;
}
@NotNull
@Override
public PomModelAspect getTransactionAspect() {
return myAspect;
@@ -36,24 +36,40 @@ public class TransactionGuardImpl extends TransactionGuard {
private final Queue<Runnable> myQueue = new LinkedBlockingQueue<Runnable>();
private final Set<TransactionKind> myMergeableKinds = ContainerUtil.newHashSet();
private String myTransactionStartTrace;
private ModalityState myTransactionModality;
@Override
@NotNull
public AccessToken startSynchronousTransaction(@NotNull TransactionKind kind) throws IllegalStateException {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myTransactionStartTrace != null) {
if (!myMergeableKinds.contains(kind) && !ApplicationManager.getApplication().isUnitTestMode()) {
// please assign exceptions that occur here to Peter
LOG.error("Nested transactions are not allowed, see FAQ in TransactionGuard class javadoc. Transaction start trace is in attachment. Kind is " + kind,
new Attachment("trace.txt", myTransactionStartTrace));
ModalityState modality = ModalityState.current();
if (isInsideTransaction()) {
if (myTransactionModality == modality) {
return AccessToken.EMPTY_ACCESS_TOKEN;
}
if (myMergeableKinds.contains(kind)) {
final ModalityState prev = myTransactionModality;
myTransactionModality = modality;
return new AccessToken() {
@Override
public void finish() {
myTransactionModality = prev;
}
};
}
// please assign exceptions that occur here to Peter
LOG.error("Nested transactions are not allowed, see FAQ in TransactionGuard class javadoc. Transaction start trace is in attachment. Kind is " + kind,
new Attachment("trace.txt", myTransactionStartTrace));
return AccessToken.EMPTY_ACCESS_TOKEN;
}
myTransactionModality = modality;
myTransactionStartTrace = DebugUtil.currentStackTrace();
return new AccessToken() {
@Override
public void finish() {
myTransactionStartTrace = null;
myTransactionModality = null;
if (!myQueue.isEmpty()) {
pollQueueLater();
}
@@ -87,8 +103,7 @@ public class TransactionGuardImpl extends TransactionGuard {
}
}
@Override
public boolean isInsideTransaction() {
private boolean isInsideTransaction() {
ApplicationManager.getApplication().assertIsDispatchThread();
return myTransactionStartTrace != null;
}
@@ -144,11 +159,18 @@ public class TransactionGuardImpl extends TransactionGuard {
};
}
@Override
public void assertInsideTransaction(boolean transactionRequired, @NotNull String errorMessage) {
if (transactionRequired != isInsideTransaction()) {
LOG.error(errorMessage);
}
}
@Override
public void submitTransactionAndWait(@NotNull TransactionKind kind, @NotNull final Runnable transaction) throws ProcessCanceledException {
Application app = ApplicationManager.getApplication();
if (app.isDispatchThread()) {
if (!canRunTransactionNow(kind)) {
if (!canRunTransactionNow(kind) && myTransactionModality != ModalityState.current()) {
throw new AssertionError("Cannot run submitTransactionAndWait from another transaction, kind " + kind + " is not allowed");
}
runSyncTransaction(kind, transaction);
@@ -279,7 +279,7 @@ public abstract class AnAction implements PossiblyDumbAware {
protected void setShortcutSet(ShortcutSet shortcutSet) {
if (myIsGlobal && myShortcutSet != shortcutSet) {
LOG.error("Shortcuts of global AnActions should not be changed outside of KeymapManager");
LOG.warn("Shortcuts of global AnActions should not be changed outside of KeymapManager", new Throwable());
}
myShortcutSet = shortcutSet;
}
@@ -94,9 +94,7 @@ public class EndHandler extends EditorActionHandler {
// here just as a boolean value holder due to requirement to declare variable used from inner class as final.
final AtomicBoolean stopProcessing = new AtomicBoolean(true);
TransactionGuard guard = TransactionGuard.getInstance();
// sometimes this handler is invoked from other actions, then we're already inside a transaction
try (AccessToken ignore = guard.isInsideTransaction() ? null : guard.startSynchronousTransaction(TransactionKind.TEXT_EDITING)) {
try (AccessToken ignore = TransactionGuard.getInstance().startSynchronousTransaction(TransactionKind.TEXT_EDITING)) {
PsiDocumentManager.getInstance(project).commitAllDocuments();
ApplicationManager.getApplication().runWriteAction(() -> {
CodeStyleManager styleManager = CodeStyleManager.getInstance(project);
@@ -20,8 +20,6 @@ import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -34,7 +32,7 @@ public class InspectionTreeUpdater {
public InspectionTreeUpdater(InspectionResultsView view) {
myView = view;
myUpdateQueue = new MergingUpdateQueue("InspectionView", 100, true, view);
myUpdateQueue = new MergingUpdateQueue("InspectionView", 100, true, view, view);
}
public void updateWithPreviewPanel() {
@@ -22,6 +22,7 @@ import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.command.undo.UndoableAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.refactoring.BaseRefactoringProcessor;
@@ -36,15 +37,13 @@ import com.intellij.refactoring.util.MoveRenameUsageInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author Maxim.Medvedev
@@ -71,23 +70,41 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces
@Override
@NotNull
protected UsageInfo[] findUsages() {
List<UsageInfo> infos = new ArrayList<UsageInfo>();
return findUsages(myChangeInfo);
}
public static void collectConflictsFromExtensions(@NotNull Ref<UsageInfo[]> refUsages,
MultiMap<PsiElement, String> conflictDescriptions,
ChangeInfo changeInfo) {
for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
final MultiMap<PsiElement, String> conflicts = usageProcessor.findConflicts(changeInfo, refUsages);
for (PsiElement key : conflicts.keySet()) {
Collection<String> collection = conflictDescriptions.get(key);
if (collection.isEmpty()) collection = new com.intellij.util.containers.HashSet<String>();
collection.addAll(conflicts.get(key));
conflictDescriptions.put(key, collection);
}
}
}
@NotNull
public static UsageInfo[] findUsages(ChangeInfo changeInfo) {
List<UsageInfo> infos = new ArrayList<UsageInfo>();
final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions();
for (ChangeSignatureUsageProcessor processor : processors) {
ContainerUtil.addAll(infos, processor.findUsages(myChangeInfo));
ContainerUtil.addAll(infos, processor.findUsages(changeInfo));
}
infos = filterUsages(infos);
return infos.toArray(new UsageInfo[infos.size()]);
}
protected List<UsageInfo> filterUsages(List<UsageInfo> infos) {
protected static List<UsageInfo> filterUsages(List<UsageInfo> infos) {
Map<PsiElement, MoveRenameUsageInfo> moveRenameInfos = new HashMap<PsiElement, MoveRenameUsageInfo>();
Set<PsiElement> usedElements = new HashSet<PsiElement>();
List<UsageInfo> result = new ArrayList<UsageInfo>(infos.size() / 2);
for (UsageInfo info : infos) {
LOG.assertTrue(info != null, getClass());
LOG.assertTrue(info != null);
PsiElement element = info.getElement();
if (info instanceof MoveRenameUsageInfo) {
if (usedElements.contains(element)) continue;
@@ -139,14 +156,15 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces
@Override
protected void performRefactoring(@NotNull UsageInfo[] usages) {
RefactoringTransaction transaction = getTransaction();
final RefactoringElementListener elementListener = transaction == null ? null : transaction.getElementListener(myChangeInfo.getMethod());
final String fqn = CopyReferenceAction.elementToFqn(myChangeInfo.getMethod());
final ChangeInfo changeInfo = myChangeInfo;
final RefactoringElementListener elementListener = transaction == null ? null : transaction.getElementListener(changeInfo.getMethod());
final String fqn = CopyReferenceAction.elementToFqn(changeInfo.getMethod());
if (fqn != null) {
UndoableAction action = new BasicUndoableAction() {
@Override
public void undo() {
if (elementListener instanceof UndoRefactoringElementListener) {
((UndoRefactoringElementListener)elementListener).undoElementMovedOrRenamed(myChangeInfo.getMethod(), fqn);
((UndoRefactoringElementListener)elementListener).undoElementMovedOrRenamed(changeInfo.getMethod(), fqn);
}
}
@@ -157,44 +175,10 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces
UndoManager.getInstance(myProject).undoableActionPerformed(action);
}
try {
final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions();
final ResolveSnapshotProvider resolveSnapshotProvider = myChangeInfo.isParameterNamesChanged() ?
VariableInplaceRenamer.INSTANCE.forLanguage(myChangeInfo.getMethod().getLanguage()) : null;
final List<ResolveSnapshotProvider.ResolveSnapshot> snapshots = new ArrayList<ResolveSnapshotProvider.ResolveSnapshot>();
for (ChangeSignatureUsageProcessor processor : processors) {
if (resolveSnapshotProvider != null) {
processor.registerConflictResolvers(snapshots, resolveSnapshotProvider, usages, myChangeInfo);
}
}
for (UsageInfo usage : usages) {
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor.processUsage(myChangeInfo, usage, true, usages)) break;
}
}
LOG.assertTrue(myChangeInfo.getMethod().isValid());
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor.processPrimaryMethod(myChangeInfo)) break;
}
for (UsageInfo usage : usages) {
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor.processUsage(myChangeInfo, usage, false, usages)) break;
}
}
if (!snapshots.isEmpty()) {
for (ParameterInfo parameterInfo : myChangeInfo.getNewParameters()) {
for (ResolveSnapshotProvider.ResolveSnapshot snapshot : snapshots) {
snapshot.apply(parameterInfo.getName());
}
}
}
final PsiElement method = myChangeInfo.getMethod();
doChangeSignature(changeInfo, usages);
final PsiElement method = changeInfo.getMethod();
LOG.assertTrue(method.isValid());
if (elementListener != null && myChangeInfo.isNameChanged()) {
if (elementListener != null && changeInfo.isNameChanged()) {
elementListener.elementRenamed(method);
}
}
@@ -203,6 +187,44 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces
}
}
public static void doChangeSignature(ChangeInfo changeInfo, @NotNull UsageInfo[] usages) {
final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions();
final ResolveSnapshotProvider resolveSnapshotProvider = changeInfo.isParameterNamesChanged() ?
VariableInplaceRenamer.INSTANCE.forLanguage(changeInfo.getMethod().getLanguage()) : null;
final List<ResolveSnapshotProvider.ResolveSnapshot> snapshots = new ArrayList<ResolveSnapshotProvider.ResolveSnapshot>();
for (ChangeSignatureUsageProcessor processor : processors) {
if (resolveSnapshotProvider != null) {
processor.registerConflictResolvers(snapshots, resolveSnapshotProvider, usages, changeInfo);
}
}
for (UsageInfo usage : usages) {
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor.processUsage(changeInfo, usage, true, usages)) break;
}
}
LOG.assertTrue(changeInfo.getMethod().isValid());
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor.processPrimaryMethod(changeInfo)) break;
}
for (UsageInfo usage : usages) {
for (ChangeSignatureUsageProcessor processor : processors) {
if (processor.processUsage(changeInfo, usage, false, usages)) break;
}
}
if (!snapshots.isEmpty()) {
for (ParameterInfo parameterInfo : changeInfo.getNewParameters()) {
for (ResolveSnapshotProvider.ResolveSnapshot snapshot : snapshots) {
snapshot.apply(parameterInfo.getName());
}
}
}
}
@Override
protected String getCommandName() {
return RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(myChangeInfo.getMethod()));
@@ -1644,9 +1644,8 @@ public abstract class DialogWrapper {
if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
LOG.error("Project-modal dialogs should not be shown under a write action.");
}
if (TransactionGuard.getInstance().isInsideTransaction()) {
LOG.error("Project-modal dialogs should not be shown inside a transaction. See TransactionGuard documentation.");
}
TransactionGuard.getInstance().assertInsideTransaction(
false, "Project-modal dialogs should not be shown inside a transaction. See TransactionGuard documentation.");
}
final AsyncResult<Boolean> result = new AsyncResult<Boolean>();
@@ -17,8 +17,8 @@ package com.intellij.ui;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.CommonShortcuts;
import com.intellij.openapi.actionSystem.EmptyAction;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.JBMenuItem;
@@ -203,10 +203,7 @@ public class SearchTextField extends JPanel {
if (ApplicationManager.getApplication() != null) { //tests
final ActionManager actionManager = ActionManager.getInstance();
if (actionManager != null) {
final AnAction clearTextAction = actionManager.getAction(IdeActions.ACTION_CLEAR_TEXT);
if (clearTextAction.getShortcutSet().getShortcuts().length == 0) {
clearTextAction.registerCustomShortcutSet(CommonShortcuts.ESCAPE, this);
}
EmptyAction.registerWithShortcutSet(IdeActions.ACTION_CLEAR_TEXT, CommonShortcuts.ESCAPE, this);
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.ui;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.EditableModel;
import com.intellij.util.ui.ElementProducer;
import com.intellij.util.ui.ListTableModel;
@@ -27,6 +28,7 @@ import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
/**
* @author Konstantin Bulenkov
@@ -149,46 +151,41 @@ class TableToolbarDecorator extends ToolbarDecorator {
}
};
myUpAction = new AnActionButtonRunnable() {
class MoveRunnable implements AnActionButtonRunnable {
final int delta;
MoveRunnable(int delta) {
this.delta = delta;
}
@Override
public void run(AnActionButton button) {
final int row = table.getEditingRow();
final int col = table.getEditingColumn();
public void run(AnActionButton button) {
int row = table.getEditingRow();
int col = table.getEditingColumn();
TableUtil.stopEditing(table);
final int[] indexes = table.getSelectedRows();
for (int index : indexes) {
if (0 < index && index < table.getModel().getRowCount()) {
tableModel.exchangeRows(index, index - 1);
table.setRowSelectionInterval(index - 1, index - 1);
}
}
int[] idx = table.getSelectedRows();
Arrays.sort(idx);
if (delta > 0) {
idx = ArrayUtil.reverseArray(idx);
}
if (idx.length == 0) return;
if (idx[0] + delta < 0) return;
if (idx[idx.length - 1] + delta > table.getModel().getRowCount()) return;
for (int i = 0; i < idx.length; i++) {
tableModel.exchangeRows(idx[i], idx[i] + delta);
idx[i] += delta;
}
TableUtil.selectRows(table, idx);
table.requestFocus();
if (row > 0 && col != -1) {
table.editCellAt(row - 1, col);
}
}
};
myDownAction = new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
final int row = table.getEditingRow();
final int col = table.getEditingColumn();
TableUtil.stopEditing(table);
final int[] indexes = table.getSelectedRows();
for (int index : indexes) {
if (0 <= index && index < table.getModel().getRowCount() - 1) {
tableModel.exchangeRows(index, index + 1);
table.setRowSelectionInterval(index + 1, index + 1);
}
}
table.requestFocus();
if (row < table.getRowCount() - 1 && col != -1) {
table.editCellAt(row + 1, col);
}
}
};
}
myUpAction = new MoveRunnable(-1);
myDownAction = new MoveRunnable(1);
}
@Override
@@ -1229,9 +1229,9 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private void startWrite(/*@NotNull*/ Class clazz) {
assertIsDispatchThread(getStatus(), "Write access is allowed from event dispatch thread only");
HeavyProcessLatch.INSTANCE.stopThreadPrioritizing(); // let non-cancellable read actions complete faster, if present
if (!TransactionGuard.getInstance().isInsideTransaction() && Registry.is("ide.require.transaction.for.model.changes", false)) {
// please assign exceptions that occur here to Peter
LOG.error("Write access is allowed from model transactions only, see TransactionGuard documentation for details");
if (Registry.is("ide.require.transaction.for.model.changes", false)) {
TransactionGuard.getInstance().assertInsideTransaction(
true, "Write access is allowed from model transactions only, see TransactionGuard documentation for details");
}
boolean writeActionPending = myWriteActionPending;
if (gatherWriteActionStatistics && myWriteActionsStack.isEmpty() && !writeActionPending) {
@@ -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.
@@ -122,7 +122,7 @@ public class ChangeProjectIconForm {
pathToIcon = files[0];
}
}
catch (Exception e1) {
catch (Exception ignore) {
}
}
}
@@ -43,6 +43,7 @@ import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import java.util.List;
import static java.awt.event.KeyEvent.*;
@@ -142,6 +143,14 @@ public abstract class JBListTable {
myEditor = editor;
}
@Override
public boolean isCellEditable(EventObject e) {
if (e instanceof MouseEvent && UIUtil.isSelectionButtonDown((MouseEvent)e)) {
return false;
}
return super.isCellEditable(e);
}
@Override
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) {
final JPanel p = new JPanel(new BorderLayout()) {
@@ -62,7 +62,7 @@
<lang.elementManipulator forClass="com.intellij.json.psi.JsonStringLiteral"
implementationClass="com.intellij.json.psi.JsonStringLiteralManipulator"/>
<projectService serviceImplementation="com.jetbrains.jsonSchema.JsonSchemaMappingsProjectConfiguration"/>
<projectConfigurable groupId="language" id="settings.json.schema" displayName="JSON Schema"
<projectConfigurable groupId="preferences.externalResources" id="settings.json.schema" displayName="JSON Schema"
instance="com.jetbrains.jsonSchema.JsonSchemaMappingsConfigurable" nonDefaultProject="true"/>
<projectService serviceInterface="com.jetbrains.jsonSchema.ide.JsonSchemaService"
serviceImplementation="com.jetbrains.jsonSchema.impl.JsonSchemaServiceImpl"/>
@@ -15,9 +15,6 @@
<action id="FullyExpandTreeNode">
<keyboard-shortcut first-keystroke="MULTIPLY"/>
</action>
<!--<action id="TextComponent.ClearAction">
<keyboard-shortcut first-keystroke="ESCAPE"/>
</action>-->
<action id="ExpandTreeNode">
<keyboard-shortcut first-keystroke="ADD"/>
</action>
@@ -216,6 +216,10 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
popupActions.add(ActionManager.getInstance().getAction(VcsActions.ACTION_COPY_REVISION_NUMBER));
PopupHandler.installPopupHandler(myList, popupActions, ActionPlaces.UPDATE_POPUP, ActionManager.getInstance());
for (AnAction action : popupActions.getChildren(null)) {
action.registerCustomShortcutSet(action.getShortcutSet(), mySplitter);
}
setTitle(title);
setComponent(mySplitter);
setPreferredFocusedComponent(myList);
@@ -241,7 +245,7 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
return myCachedContents.getContentOf(revision);
}
private void loadContentsFor(final VcsFileRevision[] revisions) throws VcsException {
private void loadContentsFor(final VcsFileRevision... revisions) throws VcsException {
myCachedContents.loadContentsFor(revisions);
}
@@ -426,6 +430,8 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
}
private void ensureBlocksCreated(int requiredIndex) throws VcsException {
loadContentsFor(myRevisions.get(requiredIndex));
for (int i = 0; i <= requiredIndex; i++) {
if (myBlocks.get(i) == null) {
myBlocks.set(i, createBlock(i));
@@ -460,6 +466,7 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
private class MyDiffAction extends DumbAwareAction {
public MyDiffAction() {
super(VcsBundle.message("action.name.compare"), VcsBundle.message("action.description.compare"), AllIcons.Actions.Diff);
setShortcutSet(CommonShortcuts.getDiff());
}
public void update(final AnActionEvent e) {
@@ -489,6 +496,7 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
super(VcsBundle.message("show.diff.with.local.action.text"),
VcsBundle.message("show.diff.with.local.action.description"),
AllIcons.Actions.DiffWithCurrent);
setShortcutSet(ActionManager.getInstance().getAction("Vcs.ShowDiffWithLocal").getShortcutSet());
}
public void update(final AnActionEvent e) {
@@ -1835,7 +1835,6 @@ overloaded.methods.with.same.number.parameters.option=<html>Ignore overloaded me
string.concatenation.in.format.call.display.name=String concatenation as argument to 'format()' call
string.concatenation.in.format.call.problem.descriptor=<code>#ref()</code> call has a String concatenation argument #loc
string.concatenation.in.format.call.quickfix=Replace concatenation with separate argument
string.concatenation.in.format.call.plural.quickfix=Replace concatenation with separate arguments
string.concatenation.in.message.format.call.display.name=String concatenation as argument to 'MessageFormat.format()' call
string.concatenation.in.message.format.call.problem.descriptor=String concatenation as argument to 'MessageFormat.format()' call #loc
shift.out.of.range.quickfix=Replace ''{0}'' with ''{1}''
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2012 Bas Leijdekkers
* Copyright 2010-2016 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,10 @@
*/
package com.siyeh.ig.bugs;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.FormatUtils;
import org.jetbrains.annotations.Nls;
@@ -44,67 +39,6 @@ public class StringConcatenationInFormatCallInspection extends BaseInspection {
return InspectionGadgetsBundle.message("string.concatenation.in.format.call.problem.descriptor");
}
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
return new StringConcatenationInFormatCallFix(((Boolean)infos[0]).booleanValue());
}
private static class StringConcatenationInFormatCallFix extends InspectionGadgetsFix {
private final boolean myPlural;
public StringConcatenationInFormatCallFix(boolean plural) {
myPlural = plural;
}
@Override
@NotNull
public String getName() {
if (myPlural) {
return InspectionGadgetsBundle.message("string.concatenation.in.format.call.plural.quickfix");
}
else {
return InspectionGadgetsBundle.message("string.concatenation.in.format.call.quickfix");
}
}
@NotNull
@Override
public String getFamilyName() {
return InspectionGadgetsBundle.message("string.concatenation.in.format.call.plural.quickfix");
}
@Override
protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
final PsiElement element = descriptor.getPsiElement().getParent().getParent();
if (!(element instanceof PsiMethodCallExpression)) {
return;
}
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
final PsiExpression formatArgument = FormatUtils.getFormatArgument(argumentList);
if (!(formatArgument instanceof PsiPolyadicExpression)) {
return;
}
final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)formatArgument;
final StringBuilder newExpression = new StringBuilder();
final PsiExpression[] operands = polyadicExpression.getOperands();
for (PsiExpression operand : operands) {
if (operand instanceof PsiReferenceExpression) {
argumentList.add(operand);
continue;
}
final PsiJavaToken token = polyadicExpression.getTokenBeforeOperand(operand);
if (token != null) {
newExpression.append(token.getText());
}
newExpression.append(operand.getText());
}
PsiReplacementUtil.replaceExpression(polyadicExpression, newExpression.toString());
}
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new StringConcatenationInFormatCallVisitor();
@@ -141,7 +75,7 @@ public class StringConcatenationInFormatCallInspection extends BaseInspection {
if (count == 0) {
return;
}
registerMethodCallError(expression, Boolean.valueOf(count > 1));
registerMethodCallError(expression);
}
}
}
@@ -72,6 +72,9 @@ public class UtilityClassCanBeEnumInspection extends BaseInspection {
@Override
protected void doFix(Project project, ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (!PsiUtil.isLanguageLevel5OrHigher(element)) {
return;
}
final PsiElement parent = element.getParent();
if (!(parent instanceof PsiClass)) {
return;
@@ -1,5 +1,5 @@
/*
* Copyright 2011 Bas Leijdekkers
* Copyright 2011-2016 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,7 +74,11 @@ public class AddThisQualifierFix extends InspectionGadgetsFix {
return;
}
}
newExpression = containingClass.getQualifiedName() + ".this." + expression.getText();
final String qualifiedName = containingClass.getQualifiedName();
if (qualifiedName == null) {
return;
}
newExpression = qualifiedName + ".this." + expression.getText();
}
PsiReplacementUtil.replaceExpressionAndShorten(expression, newExpression);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2015 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.
@@ -156,27 +156,35 @@ public class ImplicitNumericConversionInspection extends BaseInspection {
if (expressionType == null) {
return null;
}
final String text = expression.getText();
if (expressionType.equals(PsiType.INT) && expectedType.equals(PsiType.LONG)) {
return expression.getText() + 'L';
return text + 'L';
}
if (expressionType.equals(PsiType.INT) && expectedType.equals(PsiType.FLOAT)) {
return expression.getText() + ".0F";
if (!isDecimalLiteral(text)) {
return null;
}
return text + ".0F";
}
if (expressionType.equals(PsiType.INT) && expectedType.equals(PsiType.DOUBLE)) {
return expression.getText() + ".0";
if (!isDecimalLiteral(text)) {
return null;
}
return text + ".0";
}
if (expressionType.equals(PsiType.LONG) && expectedType.equals(PsiType.FLOAT)) {
final String text = expression.getText();
final int length = text.length();
return text.substring(0, length - 1) + ".0F";
if (!isDecimalLiteral(text)) {
return null;
}
return text.substring(0, text.length() - 1) + ".0F";
}
if (expressionType.equals(PsiType.LONG) && expectedType.equals(PsiType.DOUBLE)) {
final String text = expression.getText();
final int length = text.length();
return text.substring(0, length - 1) + ".0";
if (!isDecimalLiteral(text)) {
return null;
}
return text.substring(0, text.length() - 1) + ".0";
}
if (expressionType.equals(PsiType.DOUBLE) && expectedType.equals(PsiType.FLOAT)) {
final String text = expression.getText();
final int length = text.length();
if (text.charAt(length - 1) == 'd' || text.charAt(length - 1) == 'D') {
return text.substring(0, length - 1) + 'F';
@@ -186,13 +194,17 @@ public class ImplicitNumericConversionInspection extends BaseInspection {
}
}
if (expressionType.equals(PsiType.FLOAT) && expectedType.equals(PsiType.DOUBLE)) {
final String text = expression.getText();
final int length = text.length();
return text.substring(0, length - 1);
}
return null;
}
private static boolean isDecimalLiteral(String text) {
// should not be binary, octal or hexadecimal: 0b101, 077, 0xFF
return text.length() > 0 && text.charAt(0) != '0';
}
private static boolean isNegatedLiteral(PsiExpression expression) {
if (!(expression instanceof PsiPrefixExpression)) {
return false;
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 Bas Leijdekkers
* Copyright 2006-2016 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package com.siyeh.ig.style;
import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -71,10 +72,13 @@ public class UnqualifiedFieldAccessInspection extends BaseInspection implements
return;
}
final PsiClass fieldClass = field.getContainingClass();
if (fieldClass instanceof PsiAnonymousClass) {
if (fieldClass == null) {
return;
}
if (PsiUtil.isLocalOrAnonymousClass(fieldClass)) {
final PsiClass expressionClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
if (expressionClass != null && !expressionClass.equals(fieldClass)) {
// qualified this expression not possible for anonymous class
// qualified this expression not possible for anonymous or local class
return;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2012 Bas Leijdekkers
* Copyright 2006-2016 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@ package com.siyeh.ig.style;
import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -70,9 +72,16 @@ public class UnqualifiedMethodAccessInspection extends BaseInspection implements
return;
}
final PsiClass containingClass = method.getContainingClass();
if (containingClass instanceof PsiAnonymousClass) {
if (containingClass == null) {
return;
}
if (PsiUtil.isLocalOrAnonymousClass(containingClass)) {
final PsiClass expressionClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
if (expressionClass == null || !expressionClass.equals(containingClass)) {
// qualified this expression not possible for anonymous or local class
return;
}
}
registerError(expression);
}
}
@@ -0,0 +1,6 @@
class HexadecimalLiteral {
void a() {
double value = (double) 0xFF;
}
}
@@ -0,0 +1,6 @@
class HexadecimalLiteral {
void a() {
double value = <caret>0xFF;
}
}
@@ -0,0 +1,11 @@
package com.siyeh.igtest.bugs.string_concatenation_in_format_call;
public class StringConcatenationInFormatCall {
void foo(int i) {
String.<warning descr="'format()' call has a String concatenation argument">format</warning>("a" + "b" + i);
String.<warning descr="'format()' call has a String concatenation argument">format</warning>("c: " + i);
}
}
@@ -1,11 +0,0 @@
package com.siyeh.igtest.bugs.string_concatenation_in_format_call;
public class StringContenationInFormatCall {
void foo(int i) {
String.format("a" + "b" + i);
String.format("c: " + i);
}
}
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>StringContenationInFormatCall.java</file>
<line>8</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">String concatenation as argument to 'format()' call</problem_class>
<description>&lt;code&gt;format()&lt;/code&gt; call has a String concatenation argument #loc</description>
</problem>
<problem>
<file>StringContenationInFormatCall.java</file>
<line>9</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">String concatenation as argument to 'format()' call</problem_class>
<description>&lt;code&gt;format()&lt;/code&gt; call has a String concatenation argument #loc</description>
</problem>
</problems>
@@ -5,8 +5,8 @@ public class UnqualifiedFieldAccess {
private String field;
public void x () {
field = "foofoo";
final String s = String.valueOf(field.hashCode());
<warning descr="Instance field access 'field' is not qualified with 'this'">field</warning> = "foofoo";
final String s = String.valueOf(<warning descr="Instance field access 'field' is not qualified with 'this'">field</warning>.hashCode());
System.out.println(s);
}
@@ -21,6 +21,16 @@ public class UnqualifiedFieldAccess {
};
}
};
class A {
int i;
void a() {
new Object() {
void b() {
System.out.println(i);
}
};
}
}
}
void simpleAnonymous() {
@@ -28,7 +38,7 @@ public class UnqualifiedFieldAccess {
String s;
void foo() {
System.out.println(s);
System.out.println(<warning descr="Instance field access 's' is not qualified with 'this'">s</warning>);
}
};
}
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>UnqualifiedFieldAccess.java</file>
<line>8</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Instance field access not qualified with 'this'</problem_class>
<description>Instance field access &lt;code&gt;field&lt;/code&gt; is not qualified with 'this' #loc</description>
</problem>
<problem>
<file>UnqualifiedFieldAccess.java</file>
<line>9</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Instance field access not qualified with 'this'</problem_class>
<description>Instance field access &lt;code&gt;field&lt;/code&gt; is not qualified with 'this' #loc</description>
</problem>
<problem>
<file>UnqualifiedFieldAccess.java</file>
<line>31</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Instance field access not qualified with 'this'</problem_class>
<description>Instance field access &lt;code&gt;s&lt;/code&gt; is not qualified with 'this' #loc</description>
</problem>
</problems>
@@ -9,11 +9,21 @@ public class UnqualifiedMethodAccess extends JPanel {
void foo() {}
void bar() {
foo();
<warning descr="Instance method call 'foo' is not qualified with 'this'">foo</warning>();
}
void foo(String s) {
this.foo();
class A {
void a() {
<warning descr="Instance method call 'a' is not qualified with 'this'">a</warning>();
new Object() {
void b() {
a();
}
};
}
}
}
void anonymous() {
@@ -22,6 +32,7 @@ public class UnqualifiedMethodAccess extends JPanel {
new Object() {
void foo() {
bar();
<warning descr="Instance method call 'foo' is not qualified with 'this'">foo</warning>();
}
};
}
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>UnqualifiedMethodAccess.java</file>
<line>12</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Instance method call not qualified with 'this'</problem_class>
<description>Instance method call &lt;code&gt;foo&lt;/code&gt; is not qualified with 'this' #loc</description>
</problem>
</problems>
@@ -1,10 +1,33 @@
/*
* 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 com.siyeh.ig.bugs;
import com.siyeh.ig.IGInspectionTestCase;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
public class StringConcatenationInFormatCallInspectionTest extends IGInspectionTestCase {
public class StringConcatenationInFormatCallInspectionTest extends LightInspectionTestCase {
public void test() throws Exception {
doTest("com/siyeh/igtest/bugs/string_concatenation_in_format_call", new StringConcatenationInFormatCallInspection());
public void testStringConcatenationInFormatCall() {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
return new StringConcatenationInFormatCallInspection();
}
}
@@ -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.
@@ -24,9 +24,8 @@ import com.siyeh.ig.numeric.ImplicitNumericConversionInspection;
*/
public class ImplicitNumericConversionFixTest extends IGQuickFixesTestCase {
public void testOperatorAssignment() {
doTest();
}
public void testOperatorAssignment() { doTest(); }
public void testHexadecimalLiteral() { doTest(); }
@Override
protected void setUp() throws Exception {
@@ -1,10 +1,33 @@
/*
* 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 com.siyeh.ig.style;
import com.siyeh.ig.IGInspectionTestCase;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
public class UnqualifiedFieldAccessInspectionTest extends IGInspectionTestCase {
public class UnqualifiedFieldAccessInspectionTest extends LightInspectionTestCase {
public void test() throws Exception {
doTest("com/siyeh/igtest/style/unqualified_field_access", new UnqualifiedFieldAccessInspection());
public void testUnqualifiedFieldAccess() throws Exception {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
return new UnqualifiedFieldAccessInspection();
}
}
@@ -1,11 +1,33 @@
/*
* 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 com.siyeh.ig.style;
import com.siyeh.ig.IGInspectionTestCase;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
public class UnqualifiedMethodAccessInspectionTest
extends IGInspectionTestCase {
public class UnqualifiedMethodAccessInspectionTest extends LightInspectionTestCase {
public void test() throws Exception {
doTest("com/siyeh/igtest/style/unqualified_method_access", new UnqualifiedMethodAccessInspection());
public void testUnqualifiedMethodAccess() {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
return new UnqualifiedMethodAccessInspection();
}
}
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase;
import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor;
import com.intellij.refactoring.changeSignature.ChangeSignatureViewDescriptor;
import com.intellij.refactoring.rename.RenameUtil;
import com.intellij.refactoring.ui.ConflictsDialog;
@@ -33,7 +32,6 @@ import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
/**
@@ -68,15 +66,7 @@ public class GrChangeSignatureProcessor extends ChangeSignatureProcessorBase {
@Override
protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) {
MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
final MultiMap<PsiElement, String> conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages);
for (PsiElement key : conflicts.keySet()) {
Collection<String> collection = conflictDescriptions.get(key);
if (collection.isEmpty()) collection = new HashSet<String>();
collection.addAll(conflicts.get(key));
conflictDescriptions.put(key, collection);
}
}
collectConflictsFromExtensions(refUsages, conflictDescriptions, myChangeInfo);
final UsageInfo[] usagesIn = refUsages.get();
RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
@@ -34,6 +34,7 @@ public class AddConstructorMatchingSuperTest extends GrIntentionTestCase {
void testGroovyToGroovy() {
doTextTest('''\
@interface Anno {}
class Base {
Base(int p, @Anno int x) throws Exception {}
}
@@ -41,6 +42,7 @@ class Base {
class Derived exten<caret>ds Base {
}
''', '''\
@interface Anno {}
class Base {
Base(int p, @Anno int x) throws Exception {}
}
@@ -55,6 +57,7 @@ class Derived extends Base {
void testJavaToGroovy() {
myFixture.addClass('''\
@interface Anno {}
class Base {
Base(int p, @Anno int x) throws Exception {}
}
@@ -566,12 +566,10 @@ _UseNewThreadStartup = _NewThreadStartupWithTrace
def _get_threading_modules_to_patch():
threading_modules_to_patch = []
try:
import thread as _thread
threading_modules_to_patch.append(_thread)
except:
import _thread # @UnresolvedImport @Reimport
threading_modules_to_patch.append(_thread)
from _pydev_imps._pydev_saved_modules import thread as _thread
threading_modules_to_patch.append(_thread)
return threading_modules_to_patch
threading_modules_to_patch = _get_threading_modules_to_patch()
@@ -1,15 +1,8 @@
import sys
IS_PY2 = True
if sys.version_info[0] >= 3:
IS_PY2 = False
IS_PY2 = sys.version_info < (3,)
import threading
if IS_PY2:
import thread
else:
import _thread as thread
import time
import socket
@@ -17,21 +10,14 @@ import socket
import select
if IS_PY2:
import thread
import Queue as _queue
else:
import queue as _queue
if IS_PY2:
import xmlrpclib
else:
import xmlrpc.client as xmlrpclib
if IS_PY2:
import SimpleXMLRPCServer as _pydev_SimpleXMLRPCServer
else:
import xmlrpc.server as _pydev_SimpleXMLRPCServer
if IS_PY2:
import BaseHTTPServer
else:
import _thread as thread
import queue as _queue
import xmlrpc.client as xmlrpclib
import xmlrpc.server as _pydev_SimpleXMLRPCServer
import http.server as BaseHTTPServer
@@ -61,6 +61,7 @@ each command has a format:
from _pydev_bundle.pydev_imports import _queue
from _pydev_imps._pydev_saved_modules import time
from _pydev_imps._pydev_saved_modules import thread
from _pydev_imps._pydev_saved_modules import threading
from _pydev_imps._pydev_saved_modules import socket
from socket import socket, AF_INET, SOCK_STREAM, SHUT_RD, SHUT_WR
from _pydevd_bundle.pydevd_constants import * #@UnusedWildImport
@@ -91,6 +91,10 @@ except AttributeError:
try:
SUPPORT_GEVENT = os.getenv('GEVENT_SUPPORT', 'False') == 'True'
try:
import gevent
except:
SUPPORT_GEVENT = False
except:
# Jython 2.1 doesn't accept that construct
SUPPORT_GEVENT = False
@@ -102,6 +106,11 @@ USE_LIB_COPY = SUPPORT_GEVENT and \
def protect_libraries_from_patching():
"""
In this function we delete some modules from `sys.modules` dictionary and import them again inside
`_pydev_saved_modules` in order to save their original copies there. After that we can use these
saved modules within the debugger to protect them from patching by external libraries (e.g. gevent).
"""
patched = ['threading', 'thread', '_thread', 'time', 'socket', 'Queue', 'queue', 'select',
'xmlrpclib', 'SimpleXMLRPCServer', 'BaseHTTPServer', 'SocketServer',
'xmlrpc.client', 'xmlrpc.server', 'http.server', 'socketserver']
@@ -117,13 +117,18 @@ public class PySignature {
public String getTypeQualifiedName() {
if (myTypes.size() == 1) {
return myTypes.get(0);
return noneTypeToNone(myTypes.get(0));
}
else {
return StringUtil.join(myTypes, " or ");
return "Union[" + StringUtil.join(myTypes, NamedParameter::noneTypeToNone, ", ") + "]";
}
}
@Nullable
private static String noneTypeToNone(@Nullable String type) {
return "NoneType".equals(type) ? "None" : type;
}
public void addType(String type) {
if (!myTypes.contains(type)) {
myTypes.add(type);
@@ -203,7 +203,7 @@ public class PyAnnotateTypesIntention implements IntentionAction {
PyParameter[] params = function.getParameterList().getParameters();
for (int i = params.length - 1; i >= 0; i--) {
if (params[i] instanceof PyNamedParameter) {
if (params[i] instanceof PyNamedParameter && !params[i].isSelf()) {
params[i] = annotateParameter(project, editor, (PyNamedParameter)params[i], false);
}
}
@@ -137,8 +137,7 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention {
static String returnType(@NotNull PyFunction function) {
String returnType = PyNames.OBJECT;
final PySignature signature = PySignatureCacheManager.getInstance(function.getProject()).findSignature(
function);
final PySignature signature = PySignatureCacheManager.getInstance(function.getProject()).findSignature(function);
if (signature != null) {
returnType = ObjectUtils.chooseNotNull(signature.getReturnTypeQualifiedName(), returnType);
}
@@ -148,22 +147,28 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention {
public static PyExpression annotateReturnType(Project project, PyFunction function, boolean createTemplate) {
String returnType = returnType(function);
final String annotationText = " -> " + returnType;
final PsiElement prevElem = PyPsiUtils.getPrevNonCommentSibling(function.getStatementList(), true);
assert prevElem != null;
final String annotationText = "-> " + returnType;
final PsiDocumentManager manager = PsiDocumentManager.getInstance(project);
Document documentWithCallable = manager.getDocument(function.getContainingFile());
if (documentWithCallable != null) {
try {
final TextRange range = prevElem.getTextRange();
manager.doPostponedOperationsAndUnblockDocument(documentWithCallable);
if (prevElem.getNode().getElementType() == PyTokenTypes.COLON) {
documentWithCallable.insertString(range.getStartOffset(), annotationText);
final PyAnnotation oldAnnotation = function.getAnnotation();
if (oldAnnotation != null) {
final TextRange oldRange = oldAnnotation.getTextRange();
documentWithCallable.replaceString(oldRange.getStartOffset(), oldRange.getEndOffset(), annotationText);
}
else {
documentWithCallable.insertString(range.getEndOffset(), annotationText + ":");
final PsiElement prevElem = PyPsiUtils.getPrevNonCommentSibling(function.getStatementList(), true);
assert prevElem != null;
final TextRange range = prevElem.getTextRange();
if (prevElem.getNode().getElementType() == PyTokenTypes.COLON) {
documentWithCallable.insertString(range.getStartOffset(), " " + annotationText);
}
else {
documentWithCallable.insertString(range.getEndOffset(), " " + annotationText + ":");
}
}
}
finally {