Merge branch origin/master

This commit is contained in:
Elizaveta Shashkova
2014-12-03 20:43:01 +03:00
67 changed files with 504 additions and 230 deletions
@@ -136,7 +136,7 @@ public class JavaParametersUtil {
}
final boolean isJdk = JavaSdk.checkForJdk(new File(jreHome));
if (isJdk) {
throw new CantRunException("Jre expected but jdk found");
throw new CantRunException("Alternative JRE path needs to point to a JRE, not to a complete JDK installation");
}
final Sdk jdk = JavaSdk.getInstance().createJdk("", jreHome);
if (jdk == null) throw CantRunException.noJdkConfigured();
@@ -48,22 +48,22 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
}
}
if (!ignoreInference(listOwner, annotationFQN)) {
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN);
if (fromBytecode != null) {
return fromBytecode;
}
if (ignoreInference(listOwner, annotationFQN)) {
return null;
}
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN);
if (fromBytecode != null) {
return fromBytecode;
}
if (canInferFromSource(listOwner)) {
//noinspection ConstantConditions
PsiMethod method = (PsiMethod)listOwner;
if (listOwner instanceof PsiMethod) {
if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN)) {
return getInferredContractAnnotation(method);
return getInferredContractAnnotation((PsiMethod)listOwner);
}
if ((AnnotationUtil.NOT_NULL.equals(annotationFQN) || AnnotationUtil.NULLABLE.equals(annotationFQN))) {
PsiAnnotation anno = getInferredNullityAnnotation(method);
PsiAnnotation anno = getInferredNullityAnnotation((PsiMethod)listOwner);
return anno == null ? null : annotationFQN.equals(anno.getQualifiedName()) ? anno : null;
}
}
@@ -79,6 +79,9 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
@Override
public boolean ignoreInference(@NotNull PsiModifierListOwner owner, @Nullable String annotationFQN) {
if (owner instanceof PsiMethod && PsiUtil.canBeOverriden((PsiMethod)owner)) {
return true;
}
if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN) && hasHardcodedContracts(owner)) {
return true;
}
@@ -138,10 +141,6 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
return ProjectBytecodeAnalysis.getInstance(myProject).createContractAnnotation(attrs);
}
private static boolean canInferFromSource(PsiModifierListOwner listOwner) {
return listOwner instanceof PsiMethod && !PsiUtil.canBeOverriden((PsiMethod)listOwner);
}
@NotNull
@Override
public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) {
@@ -150,17 +149,24 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
PsiAnnotation[] fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotations(listOwner);
for (PsiAnnotation annotation : fromBytecode) {
if (!ignoreInference(listOwner, annotation.getQualifiedName())) {
if (!ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotation.getQualifiedName()) || canInferFromSource(listOwner)) {
result.add(annotation);
}
result.add(annotation);
}
}
if (canInferFromSource(listOwner)) {
if (listOwner instanceof PsiMethod) {
PsiAnnotation hardcoded = getHardcodedContractAnnotation((PsiMethod)listOwner);
ContainerUtil.addIfNotNull(result, hardcoded != null ? hardcoded : getInferredContractAnnotation((PsiMethod)listOwner));
ContainerUtil.addIfNotNull(result, getInferredNullityAnnotation((PsiMethod)listOwner));
if (hardcoded != null) {
result.add(hardcoded);
} else if (!ignoreInference(listOwner, ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) {
ContainerUtil.addIfNotNull(result, getInferredContractAnnotation((PsiMethod)listOwner));
}
if (!ignoreInference(listOwner, AnnotationUtil.NOT_NULL) || !ignoreInference(listOwner, AnnotationUtil.NULLABLE)) {
PsiAnnotation annotation = getInferredNullityAnnotation((PsiMethod)listOwner);
if (annotation != null && !ignoreInference(listOwner, annotation.getQualifiedName())) {
result.add(annotation);
}
}
}
return result.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : result.toArray(new PsiAnnotation[result.size()]);
@@ -89,8 +89,12 @@ class ContractInferenceInterpreter {
PsiTypeElement typeElement = myMethod.getReturnTypeElement();
final PsiType returnType = typeElement == null ? null : typeElement.getType();
final boolean notNull = !(returnType instanceof PsiPrimitiveType) &&
boolean referenceTypeReturned = !(returnType instanceof PsiPrimitiveType);
final boolean notNull = referenceTypeReturned &&
NullableNotNullManager.getInstance(myMethod.getProject()).isNotNull(myMethod, false);
if (referenceTypeReturned) {
contracts = boxReturnValues(contracts);
}
return ContainerUtil.filter(contracts, new Condition<MethodContract>() {
@Override
public boolean value(MethodContract contract) {
@@ -101,7 +105,20 @@ class ContractInferenceInterpreter {
}
});
}
@NotNull
private static List<MethodContract> boxReturnValues(List<MethodContract> contracts) {
return ContainerUtil.mapNotNull(contracts, new Function<MethodContract, MethodContract>() {
@Override
public MethodContract fun(MethodContract contract) {
if (contract.returnValue == FALSE_VALUE || contract.returnValue == TRUE_VALUE) {
return new MethodContract(contract.arguments, NOT_NULL_VALUE);
}
return contract;
}
});
}
private List<MethodContract> doInferContracts() {
PsiCodeBlock body = myMethod.getBody();
PsiStatement[] statements = body == null ? PsiStatement.EMPTY_ARRAY : body.getStatements();
@@ -294,7 +311,7 @@ class ContractInferenceInterpreter {
parameter = resolveParameter(op2);
constraint = getLiteralConstraint(op1);
}
if (parameter >= 0 && constraint != null) {
if (parameter >= 0 && constraint != null && constraint != NOT_NULL_VALUE) {
List<MethodContract> result = ContainerUtil.newArrayList();
for (ValueConstraint[] state : states) {
ContainerUtil.addIfNotNull(result, contractWithConstraint(state, parameter, constraint, equality ? TRUE_VALUE : FALSE_VALUE));
@@ -410,7 +427,7 @@ class ContractInferenceInterpreter {
if (expr.textMatches(PsiKeyword.TRUE)) return TRUE_VALUE;
if (expr.textMatches(PsiKeyword.FALSE)) return FALSE_VALUE;
if (expr.textMatches(PsiKeyword.NULL)) return NULL_VALUE;
if (((PsiLiteralExpression)expr).getValue() instanceof String) return NOT_NULL_VALUE;
return NOT_NULL_VALUE;
}
return null;
}
@@ -1490,10 +1490,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
final PsiAnnotation contractAnno = findContractAnnotation(method);
final int paramCount = method.getParameterList().getParametersCount();
if (contractAnno != null) {
if (AnnotationUtil.isInferredAnnotation(contractAnno) && PsiUtil.canBeOverriden(method)) {
return Collections.emptyList();
}
return CachedValuesManager.getCachedValue(contractAnno, new CachedValueProvider<List<MethodContract>>() {
@Nullable
@Override
@@ -536,6 +536,10 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
}
private static boolean isCompileConstantInIfCondition(PsiElement element) {
if (element instanceof PsiPrefixExpression && ((PsiPrefixExpression)element).getOperationTokenType() == JavaTokenType.EXCL) {
return isCompileConstantInIfCondition(((PsiPrefixExpression)element).getOperand());
}
if (!(element instanceof PsiReferenceExpression)) return false;
PsiElement resolved = ((PsiReferenceExpression)element).resolve();
if (!(resolved instanceof PsiField)) return false;
@@ -253,10 +253,6 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (value instanceof DfaVariableValue) {
setVariableState(var, getVariableState((DfaVariableValue)value));
}
else if (value instanceof DfaBoxedValue) {
setVariableState(var, getVariableState(var).withNullable(false));
applyCondition(compareToNull(var, true));
}
}
if (getVariableState(var).isNotNull()) {
@@ -477,6 +473,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
public boolean isNotNull(DfaValue dfaVar) {
if (dfaVar instanceof DfaConstValue) return ((DfaConstValue)dfaVar).getValue() != null;
if (dfaVar instanceof DfaBoxedValue) return true;
if (dfaVar instanceof DfaTypeValue) return ((DfaTypeValue)dfaVar).isNotNull();
if (dfaVar instanceof DfaVariableValue) {
if (getVariableState((DfaVariableValue)dfaVar).isNotNull()) return true;
@@ -26,7 +26,7 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -68,25 +68,34 @@ public class NullityInference {
final AtomicBoolean hasNotNulls = new AtomicBoolean();
final AtomicBoolean hasNulls = new AtomicBoolean();
final AtomicBoolean hasUnknowns = new AtomicBoolean();
final List<PsiMethodCallExpression> calls = ContainerUtil.newArrayList();
final Set<PsiMethod> delegates = ContainerUtil.newLinkedHashSet();
body.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReturnStatement(PsiReturnStatement statement) {
PsiExpression value = statement.getReturnValue();
if (value == null) {
hasErrors.set(true);
} else {
if (value instanceof PsiLiteralExpression) {
if (value.textMatches(PsiKeyword.NULL)) {
hasNulls.set(true);
} else {
hasNotNulls.set(true);
}
} else if (value instanceof PsiMethodCallExpression) {
calls.add((PsiMethodCallExpression)value);
} else {
hasUnknowns.set(true);
} else if (value instanceof PsiLiteralExpression) {
if (value.textMatches(PsiKeyword.NULL)) {
hasNulls.set(true);
}
else {
hasNotNulls.set(true);
}
}
else if (value.getType() instanceof PsiPrimitiveType) {
hasNotNulls.set(true);
}
else if (value instanceof PsiMethodCallExpression) {
PsiMethod target = ((PsiMethodCallExpression)value).resolveMethod();
if (target == null) {
hasUnknowns.set(true);
} else {
delegates.add(target);
}
}
else {
hasUnknowns.set(true);
}
super.visitReturnStatement(statement);
}
@@ -102,13 +111,12 @@ public class NullityInference {
return Nullness.NULLABLE;
}
if (calls.size() > 1) {
if (hasErrors.get() || delegates.size() > 1) {
return Nullness.UNKNOWN;
}
if (calls.size() == 1) {
PsiMethod target = calls.get(0).resolveMethod();
if (target != null && NullableNotNullManager.isNotNull(target)) {
if (delegates.size() == 1) {
if (NullableNotNullManager.isNotNull(delegates.iterator().next())) {
return Nullness.NOT_NULL;
}
return Nullness.UNKNOWN;
@@ -880,11 +880,17 @@ public class ExpectedTypesProvider {
if (statement.getException() == myExpr) {
PsiManager manager = statement.getManager();
PsiType throwableType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Throwable", myExpr.getResolveScope());
PsiMember container = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiClass.class);
PsiElement container = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiLambdaExpression.class, PsiClass.class);
PsiType[] throwsTypes = PsiType.EMPTY_ARRAY;
if (container instanceof PsiMethod) {
throwsTypes = ((PsiMethod)container).getThrowsList().getReferencedTypes();
}
else if (container instanceof PsiLambdaExpression) {
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(container);
if (method != null) {
throwsTypes = method.getThrowsList().getReferencedTypes();
}
}
if (throwsTypes.length == 0) {
final PsiClassType exceptionType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName("java.lang.Exception", myExpr.getResolveScope());
@@ -106,8 +106,8 @@ public class ControlFlowWrapper {
}
if (myExitPoints.size() != 1) {
areExitStatementsTheSame();
myGenerateConditionalExit = true;
areExitStatementsTheSame();
}
return myExitStatements;
}
@@ -31,6 +31,7 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.ui.*;
import com.intellij.refactoring.util.ConflictsUtil;
@@ -241,6 +242,9 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
@Nullable
private JPanel createReturnTypePanel() {
if (TypeConversionUtil.isPrimitiveWrapper(myReturnType) && myNullness == Nullness.NULLABLE) {
return null;
}
mySelector = new TypeSelectorManagerImpl(myProject, myReturnType, findOccurrences(), areTypesDirected()).getTypeSelector();
final JComponent component = mySelector.getComponent();
if (component instanceof JComboBox) {
@@ -532,7 +536,7 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
buffer.append(myTargetClass.getName());
}
else {
buffer.append(PsiFormatUtil.formatType(mySelector.getSelectedType(), 0, PsiSubstitutor.EMPTY));
buffer.append(PsiFormatUtil.formatType(mySelector != null ? mySelector.getSelectedType() : myReturnType, 0, PsiSubstitutor.EMPTY));
buffer.append(" ");
buffer.append(myNameField.getText());
}
@@ -602,6 +606,6 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac
}
public PsiType getReturnType() {
return mySelector.getSelectedType();
return mySelector != null ? mySelector.getSelectedType() : myReturnType;
}
}
@@ -68,10 +68,8 @@ import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
import com.intellij.refactoring.util.*;
import com.intellij.refactoring.util.classMembers.ElementNeedsThis;
import com.intellij.refactoring.util.duplicates.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -241,8 +239,11 @@ public class ExtractMethodProcessor implements MatchProvider {
}
catch (ControlFlowWrapper.ExitStatementsNotSameException e) {
myExitStatements = myControlFlowWrapper.getExitStatements();
showMultipleExitPointsMessage();
return false;
myNotNullConditionalCheck = areAllExitPointsAreNotNull(getExpectedReturnType());
if (!myNotNullConditionalCheck) {
showMultipleExitPointsMessage();
return false;
}
}
myOutputVariables = myControlFlowWrapper.getOutputVariables();
@@ -265,11 +266,7 @@ public class ExtractMethodProcessor implements MatchProvider {
}
myHasExpressionOutput = expressionType != PsiType.VOID;
final PsiType returnStatementType = myCodeFragmentMember instanceof PsiMethod
? ((PsiMethod)myCodeFragmentMember).getReturnType()
: myCodeFragmentMember instanceof PsiLambdaExpression
? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
: null;
final PsiType returnStatementType = getExpectedReturnType();
myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && returnStatementType != PsiType.VOID;
if (myGenerateConditionalExit && myOutputVariables.length == 1) {
@@ -284,15 +281,7 @@ public class ExtractMethodProcessor implements MatchProvider {
myNullConditionalCheck &= isNullInferred(myOutputVariables[0].getName(), false);
}
if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
myNotNullConditionalCheck = returnStatementType != null && returnStatementType != PsiType.VOID;
for (PsiStatement statement : myExitStatements) {
if (statement instanceof PsiReturnStatement) {
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
myNotNullConditionalCheck &= returnValue != null && !isNullInferred(returnValue.getText(), true);
}
}
}
myNotNullConditionalCheck = areAllExitPointsAreNotNull(returnStatementType);
}
if (!myHasReturnStatementOutput && checkOutputVariablesCount() && !myNullConditionalCheck && !myNotNullConditionalCheck) {
@@ -342,6 +331,28 @@ public class ExtractMethodProcessor implements MatchProvider {
return true;
}
private PsiType getExpectedReturnType() {
return myCodeFragmentMember instanceof PsiMethod
? ((PsiMethod)myCodeFragmentMember).getReturnType()
: myCodeFragmentMember instanceof PsiLambdaExpression
? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
: null;
}
private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) {
if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
boolean isNotNull = returnStatementType != null && returnStatementType != PsiType.VOID;
for (PsiStatement statement : myExitStatements) {
if (statement instanceof PsiReturnStatement) {
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
isNotNull &= returnValue != null && !isNullInferred(returnValue.getText(), true);
}
}
return isNotNull;
}
return false;
}
protected boolean insertNotNullCheckIfPossible() {
return true;
}
@@ -553,7 +564,19 @@ public class ExtractMethodProcessor implements MatchProvider {
: PsiTreeUtil.findCommonParent(myElements);
return CodeInsightUtil.findReferenceExpressions(scope, myOutputVariable);
}
return PsiExpression.EMPTY_ARRAY;
final List<PsiStatement> filter = ContainerUtil.filter(myExitStatements, new Condition<PsiStatement>() {
@Override
public boolean value(PsiStatement statement) {
return statement instanceof PsiReturnStatement;
}
});
final List<PsiExpression> map = ContainerUtil.map(filter, new Function<PsiStatement, PsiExpression>() {
@Override
public PsiExpression fun(PsiStatement statement) {
return ((PsiReturnStatement) statement).getReturnValue();
}
});
return map.toArray(new PsiExpression[map.size()]);
}
private Nullness initNullness() {
@@ -796,7 +819,7 @@ public class ExtractMethodProcessor implements MatchProvider {
CodeStyleManager.getInstance(myProject).reformat(ifStatement);
}
else if (myNotNullConditionalCheck) {
String varName = myOutputVariable.getName();
String varName = myOutputVariable != null ? myOutputVariable.getName() : "x";
varName = declareVariableAtMethodCallLocation(varName, myReturnType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)myReturnType).getBoxedType(myCodeFragmentMember) : myReturnType);
addToMethodCallLocation(myElementFactory.createStatementFromText("if (" + varName + " != null) return " + varName + ";", null));
}
@@ -1021,7 +1044,9 @@ public class ExtractMethodProcessor implements MatchProvider {
statement = (PsiDeclarationStatement)addToMethodCallLocation(statement);
PsiVariable var = (PsiVariable)statement.getDeclaredElements()[0];
myMethodCall = (PsiMethodCallExpression)var.getInitializer();
var.getModifierList().replace(myOutputVariable.getModifierList());
if (myOutputVariable != null) {
var.getModifierList().replace(myOutputVariable.getModifierList());
}
return name;
}
@@ -24,7 +24,6 @@ import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jdom.Element;
@@ -168,30 +167,16 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
myDefaultNotNull = defaultNotNull;
}
private static boolean skipAnnotation(@NotNull PsiAnnotation annotation, @NotNull PsiModifierListOwner owner) {
return owner instanceof PsiMethod &&
PsiUtil.canBeOverriden((PsiMethod)owner) &&
AnnotationUtil.isInferredAnnotation(annotation) &&
AnnotationUtil.NOT_NULL.equals(annotation.getQualifiedName());
}
@Nullable
private PsiAnnotation findNullabilityAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases, boolean nullable) {
Set<String> qNames = ContainerUtil.newHashSet(nullable ? getNullables() : getNotNulls());
PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, qNames);
if (annotation != null && !skipAnnotation(annotation, owner)) {
PsiAnnotation annotation = checkBases && (owner instanceof PsiClass || owner instanceof PsiMethod)
? AnnotationUtil.findAnnotationInHierarchy(owner, qNames)
: AnnotationUtil.findAnnotation(owner, qNames);
if (annotation != null) {
return annotation;
}
if (checkBases && owner instanceof PsiMethod) {
for (PsiModifierListOwner superOwner : AnnotationUtil.getSuperAnnotationOwners(owner)) {
annotation = AnnotationUtil.findAnnotation(superOwner, qNames);
if (annotation != null && !skipAnnotation(annotation, superOwner)) {
return annotation;
}
}
}
PsiType type = getOwnerType(owner);
if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null;
@@ -317,7 +302,6 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
}
try {
//noinspection deprecation
DefaultJDOMExternalizer.writeExternal(this, component);
}
catch (WriteExternalException e) {
@@ -329,7 +313,6 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
@Override
public void loadState(Element state) {
try {
//noinspection deprecation
DefaultJDOMExternalizer.readExternal(this, state);
if (myNullables.isEmpty()) {
Collections.addAll(myNullables, DEFAULT_NULLABLES);
@@ -0,0 +1,14 @@
// "Create Local Variable 'v'" "true"
public class A {
void foo() {
L l = () -> {
MyException v;
throw v
}
}
interface L {
void g() throws MyException;
}
class MyException extends Exception {}
}
@@ -0,0 +1,13 @@
// "Create Local Variable 'v'" "true"
public class A {
void foo() {
L l = () -> {
throw v<caret>
}
}
interface L {
void g() throws MyException;
}
class MyException extends Exception {}
}
@@ -2346,11 +2346,6 @@
<item name="java.lang.System void checkKey(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.System void exit(int)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_ -&gt; fail&quot;"/>
</annotation>
</item>
<item name="java.lang.System void setProperties(java.util.Properties) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -3834,18 +3834,12 @@
<item name="org.apache.commons.lang.Validate void notEmpty(java.util.Map, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<!-- hardcoded start -->
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="value = &quot;null -&gt; fail&quot;, pure = true"/>
</annotation>
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object, java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="value = &quot;null, _ -&gt; fail&quot;, pure = true"/>
</annotation>
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<!-- hardcoded end -->
<item name="org.apache.commons.lang.WordUtils WordUtils()">
<annotation name="org.jetbrains.annotations.Contract">
<val val="pure=true"/>
@@ -0,0 +1,14 @@
class Fun {
public static final boolean isDebug = true;
void foo() {
if (isDebug) {
System.out.println();
}
}
void fooNegated() {
if (!isDebug) {
System.out.println();
}
}
}
@@ -0,0 +1,12 @@
class Test {
Integer method() {
<selection>try {
if(cond1) return 0;
else if(cond2) return null;
System.out.println("Text");
} finally {
doSomething();
}</selection>
return 12;
}
}
@@ -0,0 +1,21 @@
import org.jetbrains.annotations.Nullable;
class Test {
int method() {
Integer x = newMethod();
if (x != null) return x;
return 12;
}
@Nullable
private Integer newMethod() {
try {
if(cond1) return 0;
else if(cond2) return 1;
System.out.println("Text");
} finally {
doSomething();
}
return null;
}
}
@@ -0,0 +1,13 @@
class Test {
String foo(boolean b) {
<selection>
if (b) {
return "a";
}
if (!b) {
return "b";
}
</selection>
return "42";
}
}
@@ -126,7 +126,7 @@ public class TemplatesCompletionTest extends CompletionAutoPopupTestCase {
doAutoPopupTest("instanceof", null);
}
public void testDoNotAutoCompleteCompletionElementIfTemplateUnique() {
public void testDoNotAutoCompleteCompletionElementIfTemplateUnique() {
LiveTemplateCompletionContributor.ourShowTemplatesInTests = true;
configureByFile();
myFixture.completeBasic();
@@ -239,6 +239,28 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
assert c == []
}
public void "test return boxed integer"() {
def c = inferContracts("""
static Object test1(Object o1) {
return o1 == null ? 1 : smth();
}
static native Object smth()
""")
assert c == ['null -> !null']
}
public void "test return boxed boolean"() {
def c = inferContracts("""
static Object test1(Object o1) {
return o1 == null ? false : smth();
}
static native Object smth()
""")
assert c == ['null -> !null']
}
public void "test boolean autoboxing in delegation"() {
def c = inferContracts("""
static Boolean test04(String s) {
@@ -391,6 +413,15 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
assert c == ['null -> null']
}
public void "test compare with string literal"() {
def c = inferContracts("""
String cast(String s) {
return s == "a" ? "b" : null;
}
""")
assert c == []
}
public void "test return after if without else"() {
def c = inferContracts("""
public static boolean isBlank(String s) {
@@ -184,6 +184,8 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
public void testUnknownFloatMayBeNaN() { doTest(); }
public void testFloatEquality() { doTest(); }
public void testLastConstantConditionInAnd() { doTest(); }
public void testCompileTimeConstant() { doTest(); }
public void testTransientFinalField() { doTest(); }
public void testRememberLocalTransientFieldState() { doTest(); }
@@ -42,6 +42,17 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur
assert inferNullity(parse('String foo() { return bar(); }; String bar() { return "z"; }; ')) == NOT_NULL
}
void "test same delegate method invoked twice"() {
assert inferNullity(parse('''
String foo() {
if (equals(2)) return bar();
if (equals(3)) return bar();
return "abc";
}
String bar() { return "z"; }
''')) == NOT_NULL
}
void "test if branch returns null"() {
assert inferNullity(parse('String bar() { if (equals(2)) return null; return "a"; }; ')) == NULLABLE
}
@@ -50,9 +61,21 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur
assert inferNullity(parse('String foo() { return bar(); }; String bar() { if (equals(2)) return null; return "a"; }; ')) == UNKNOWN
}
void "test return boxed boolean constant"() {
assert inferNullity(parse('Object foo() { return true; }')) == NOT_NULL
}
void "test return boxed boolean value"() {
assert inferNullity(parse('Object foo(Object o) { return o == null; }')) == NOT_NULL
}
void "test return boxed integer"() {
assert inferNullity(parse('Object foo() { return 1; }')) == NOT_NULL
}
protected abstract Nullness inferNullity(PsiMethod method)
private PsiMethod parse(String method) {
protected PsiMethod parse(String method) {
return myFixture.addClass("final class Foo { $method }").methods[0]
}
@@ -60,6 +83,10 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur
Nullness inferNullity(PsiMethod method) {
return NullableNotNullManager.isNotNull(method) ? NOT_NULL : NullableNotNullManager.isNullable(method) ? NULLABLE : UNKNOWN
}
void "test skip when errors"() {
assert inferNullity(parse('String foo() { if(); return 2; } ')) == UNKNOWN
}
}
static class DfaInferenceTest extends NullityInferenceFromSourceTestCase {
@@ -17,7 +17,6 @@ package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInsight.daemon.GutterMark;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.projectRoots.Sdk;
@@ -257,7 +256,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
@Nullable
private PsiAnnotation findInferredAnnotation(PsiModifierListOwner owner, String fqn) {
return InferredAnnotationsManager.getInstance(myModule.getProject()).findInferredAnnotation(owner, fqn);
return ProjectBytecodeAnalysis.getInstance(getProject()).findInferredAnnotation(owner, fqn);
}
@Nullable
@@ -16,7 +16,6 @@
package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInspection.bytecodeAnalysis.asm.LeakingParameters;
import com.intellij.codeInspection.bytecodeAnalysis.data.*;
import com.intellij.openapi.util.io.FileUtil;
@@ -48,7 +47,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private final String myClassesProjectRelativePath = "/classes/" + Test01.class.getPackage().getName().replace('.', '/');
private JavaPsiFacade myJavaPsiFacade;
private InferredAnnotationsManager myInferredAnnotationsManager;
private ProjectBytecodeAnalysis myBytecodeAnalysisService;
private MessageDigest myMessageDigest;
@@ -56,7 +55,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
protected void setUp() throws Exception {
super.setUp();
myJavaPsiFacade = JavaPsiFacade.getInstance(myModule.getProject());
myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
myBytecodeAnalysisService = ProjectBytecodeAnalysis.getInstance(myModule.getProject());
myMessageDigest = MessageDigest.getInstance("MD5");
setUpDataClasses();
}
@@ -131,7 +130,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
params: for (int i = 0; i < annotations.length; i++) {
Annotation[] parameterAnnotations = annotations[i];
PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i];
PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
PsiAnnotation inferredAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
for (Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation.annotationType() == ExpectNotNull.class) {
assertNotNull(javaMethod.toString() + " " + i, inferredAnnotation);
@@ -143,13 +142,13 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
// not-null result
ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class);
PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
PsiAnnotation actualAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
assertEquals(javaMethod.toString(), expectedAnnotation == null, actualAnnotation == null);
// contracts
ExpectContract expectedContract = javaMethod.getAnnotation(ExpectContract.class);
PsiAnnotation actualContract = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
PsiAnnotation actualContract = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
String expectedText = expectedContract == null ? "null" : expectedContract.toString();
String inferredText = actualContract == null ? "null" : actualContract.getText();
@@ -58,6 +58,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
}
public void testExitPoints4() throws Exception {
doTest();
}
public void testExitPoints4Nullable() throws Exception {
doExitPointsTest(false);
}
@@ -20,6 +20,7 @@ public class ReplaceMethodDuplicatesTestSuite {
testSuite.addTestSuite(FindMethodDuplicatesMiscTest.class);
testSuite.addTestSuite(FindMethodDuplicatesTest.class);
testSuite.addTestSuite(SuggestedParamTypesTest.class);
testSuite.addTestSuite(SuggestedReturnTypesTest.class);
return testSuite;
}
}
@@ -61,6 +61,10 @@ public class SuggestedReturnTypesTest extends LightCodeInsightTestCase {
doTest("Integer", "int");
}
public void testOutputUsedInReturn() throws Exception {
doTest("String");
}
private void doTest(String... types) throws Exception {
configureByFile(BASE_PATH + getTestName(false) + ".java");
@@ -432,6 +432,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
Color color = myEditor.getColorsScheme().getColor(EditorColors.LINE_NUMBERS_COLOR);
g.setColor(color != null ? color : JBColor.blue);
g.setFont(myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
Graphics2D g2 = (Graphics2D)g;
@@ -453,8 +454,10 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
if (logLine >= 0) {
String s = String.valueOf(logLine + 1);
int startY = (i + 1) * lineHeight;
Color fgColor = myTextFgColors.get(i);
g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue);
if (myEditor.isInDistractionFreeMode()) {
Color fgColor = myTextFgColors.get(i);
g.setColor(fgColor != null ? fgColor : color != null ? color : JBColor.blue);
}
g.drawString(s,
getLineNumberAreaOffset() + getLineNumberAreaWidth() -
myEditor.getFontMetrics(Font.PLAIN).stringWidth(s) -
@@ -207,7 +207,7 @@ failed.to.generate.wrapper.error.message=Failed to generate temporary html wrapp
application.configuration.use.classpath.and.jdk.of.module.label=Use classpath of m&odule:
application.configuration.main.class.label=Main &class:
jre.path.is.not.valid.jre.home.error.mesage=''{0}'' is not valid JRE home
jre.path.is.not.valid.jre.home.error.mesage=''{0}'' is not a valid JRE home
main.method.not.found.in.class.error.message=Main method not found in class {0}
no.user.process.input.error.message=No process input
fix.run.configuration.problem.button=Fix
@@ -555,9 +555,11 @@ public class SMTestProxy extends AbstractTestProxy {
return (AssertEqualsDiffViewerProvider)myState;
}
for (SMTestProxy child : myChildren) {
if (child.myState instanceof AssertEqualsDiffViewerProvider) {
return (AssertEqualsDiffViewerProvider)child.myState;
if (myChildren != null) {
for (SMTestProxy child : myChildren) {
if (child.myState instanceof AssertEqualsDiffViewerProvider) {
return (AssertEqualsDiffViewerProvider)child.myState;
}
}
}
return null;
@@ -25,6 +25,8 @@ import javax.swing.*;
*/
@SuppressWarnings("JUnitTestClassNamingConvention")
public class _FirstInSuiteTest extends TestCase {
public static long suiteStarted = 0L;
public void testNothing() throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
@@ -46,6 +48,7 @@ public class _FirstInSuiteTest extends TestCase {
// performance tests
public void testNothingPerformance() throws Exception {
suiteStarted = System.nanoTime();
testNothing();
}
}
@@ -63,6 +63,11 @@ public class _LastInSuiteTest extends TestCase {
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public void testStatistics() throws Exception {
if (_FirstInSuiteTest.suiteStarted != 0) {
long testSuiteDuration = System.nanoTime() - _FirstInSuiteTest.suiteStarted;
System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTimeMs' value='%d']",
testSuiteDuration / 1000000));
}
LightPlatformTestCase.reportTestExecutionStatistics();
}
@@ -281,7 +281,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
/**
* Runs highlighting test for the given files.
* The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with all options set.
* The same as {@link #testHighlighting(boolean, boolean, boolean, String...)} with {@code checkInfos=false}.
*
* @param filePaths the first file is tested only; the others are just copied along with the first.
* @return highlighting duration in milliseconds
@@ -24,16 +24,19 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
class ConcurrentHashSet<K> implements Set<K> {
/**
* @deprecated use {@link ContainerUtil#newConcurrentSet()} instead
*/
public class ConcurrentHashSet<K> implements Set<K> {
private final ConcurrentMap<K, Boolean> map;
ConcurrentHashSet(int initialCapacity) {
public ConcurrentHashSet(int initialCapacity) {
map = ContainerUtil.newConcurrentMap(initialCapacity);
}
ConcurrentHashSet() {
public ConcurrentHashSet() {
map = ContainerUtil.newConcurrentMap();
}
ConcurrentHashSet(@NotNull TObjectHashingStrategy<K> hashingStrategy) {
public ConcurrentHashSet(@NotNull TObjectHashingStrategy<K> hashingStrategy) {
map = ContainerUtil.newConcurrentMap(hashingStrategy);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2007-2012 Bas Leijdekkers
* Copyright 2007-2014 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,6 +15,7 @@
*/
package com.siyeh.ipp.exceptions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -36,8 +37,18 @@ public class ConvertCatchToThrowsIntention extends Intention {
@Override
protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException {
final PsiCatchSection catchSection = (PsiCatchSection)element.getParent();
final PsiMethod method = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class);
if (method == null) {
final NavigatablePsiElement owner = PsiTreeUtil.getParentOfType(catchSection, PsiMethod.class, PsiLambdaExpression.class);
final PsiMethod method;
if (owner instanceof PsiMethod) {
method = (PsiMethod)owner;
}
else if (owner instanceof PsiLambdaExpression) {
method = LambdaUtil.getFunctionalInterfaceMethod(owner);
if (method == null || !FileModificationService.getInstance().preparePsiElementsForWrite(method)) {
return;
}
}
else {
return;
}
// todo warn if method implements or overrides some base method
@@ -1,5 +1,5 @@
/*
* Copyright 2007-2013 Bas Leijdekkers
* Copyright 2007-2014 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ class ConvertCatchToThrowsPredicate implements PsiElementPredicate {
if (element instanceof PsiCodeBlock) {
return false;
}
final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, true, PsiClass.class);
return method != null;
final PsiElement owner = PsiTreeUtil.getParentOfType(parent, PsiMethod.class, PsiClass.class, PsiLambdaExpression.class);
return owner instanceof PsiMethod || owner instanceof PsiLambdaExpression;
}
}
@@ -0,0 +1,19 @@
class Lambda {
void bar() throws E {}
void foo() {
U u = () -> {
try {
} <caret>catch (E e) {
e.printStackTrace();
}
};
}
interface U {
void f();
}
class E extends Exception {}
}
@@ -0,0 +1,16 @@
class Lambda {
void bar() throws E {}
void foo() {
U u = () -> {
};
}
interface U {
void f() throws E;
}
class E extends Exception {}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2014 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.
@@ -25,6 +25,7 @@ public class ConvertCatchToThrowsTest extends IPPTestCase {
public void testArmWithPluralCatches() { doTest(); }
public void testArmWithSingleCatch() { doTest(); }
public void testExistingThrows() { doTest(); }
public void testLambda() { doTest(); }
@Override
protected String getIntentionName() {
+17 -46
View File
@@ -50,10 +50,7 @@ import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlatformIcons;
import com.intellij.util.SmartList;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.NotNullPredicate;
import com.jetbrains.python.PyBundle;
@@ -847,13 +844,7 @@ public class PyUtil {
@Nullable
@SuppressWarnings("unchecked")
public static <T> T as(@Nullable final Object expression, @NotNull final Class<T> clazz) {
if (expression == null) {
return null;
}
if (clazz.isAssignableFrom(expression.getClass())) {
return (T)expression;
}
return null;
return ObjectUtils.tryCast(expression, clazz);
}
// TODO: Move to PsiElement?
@@ -968,24 +959,25 @@ public class PyUtil {
}
/**
* If target is a PsiDirectory, that is also a valid Python package, return PsiFile that points to __init__.py,
* If directory is a PsiDirectory, that is also a valid Python package, return PsiFile that points to __init__.py,
* if such file exists, or directory itself (i.e. namespace package). Otherwise, return {@code null}.
* Unlike {@link #turnDirIntoInit(com.intellij.psi.PsiElement)} this function handles namespace packages and
* accepts only PsiDirectories as target.
*
* @param target directory to check
* @param directory directory to check
* @param anchor optional PSI element to determine language level as for {@link #isPackage(com.intellij.psi.PsiDirectory, com.intellij.psi.PsiElement)}
* @return PsiFile or PsiDirectory, if target is a Python package and {@code null} null otherwise
*/
@Nullable
public static PsiElement turnDirIntoPackageElement(@NotNull PsiDirectory target, @Nullable PsiElement anchor) {
if (isPackage(target, anchor)) {
final PsiFile file = target.findFile(PyNames.INIT_DOT_PY);
return file != null ? file : target;
}
else {
return null;
public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) {
if (isPackage(directory, anchor)) {
final PsiElement init = turnDirIntoInit(directory);
if (init != null) {
return init;
}
return directory;
}
return null;
}
/**
@@ -1019,18 +1011,6 @@ public class PyUtil {
return PyNames.INIT_DOT_PY.equals(file.getName());
}
@Nullable
public static PsiElement getPackageElement(@NotNull PsiDirectory directory, @Nullable PsiElement anchor) {
if (isPackage(directory, anchor)) {
final PsiElement init = turnDirIntoInit(directory);
if (init != null) {
return init;
}
return directory;
}
return null;
}
private static boolean isSetuptoolsNamespacePackage(@NotNull PsiDirectory directory) {
final String packagePath = getPackagePath(directory);
return packagePath != null && !PySetuptoolsNamespaceIndex.find(packagePath, directory.getProject()).isEmpty();
@@ -1165,8 +1145,8 @@ public class PyUtil {
public static Collection<VirtualFile> getSourceRoots(@NotNull Module module) {
final Set<VirtualFile> result = new LinkedHashSet<VirtualFile>();
final ModuleRootManager manager = ModuleRootManager.getInstance(module);
result.addAll(Arrays.asList(manager.getSourceRoots()));
result.addAll(Arrays.asList(manager.getContentRoots()));
Collections.addAll(result, manager.getSourceRoots());
Collections.addAll(result, manager.getContentRoots());
return result;
}
@@ -1708,10 +1688,7 @@ public class PyUtil {
private static boolean isObject(@NotNull final PyMemberInfo<PyElement> classMemberInfo) {
final PyElement element = classMemberInfo.getMember();
if ((element instanceof PyClass) && PyNames.OBJECT.equals(element.getName())) {
return true;
}
return false;
return (element instanceof PyClass) && PyNames.OBJECT.equals(element.getName());
}
}
@@ -1751,10 +1728,7 @@ public class PyUtil {
*/
public static boolean isObjectClass(@NotNull PyClass cls) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(cls);
if (cls == builtinCache.getClass(PyNames.OBJECT) || cls == builtinCache.getClass(PyNames.FAKE_OLD_BASE)) {
return true;
}
return false;
return cls == builtinCache.getClass(PyNames.OBJECT) || cls == builtinCache.getClass(PyNames.FAKE_OLD_BASE);
}
/**
@@ -1768,9 +1742,6 @@ public class PyUtil {
*/
public static boolean isObjectType(@NotNull PyType type, @NotNull PsiElement anchor) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor);
if (type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType()) {
return true;
}
return false;
return type == builtinCache.getObjectType() || type == builtinCache.getOldstyleClassobjType();
}
}
@@ -23,7 +23,6 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
@@ -175,7 +174,7 @@ public class ResolveImportUtil {
if (qualifiedName == null || sourceFile == null) {
return Collections.emptyList();
}
final String marker = StringUtil.join(qualifiedName.getComponents(), ".") + "#" + Integer.toString(relativeLevel);
final String marker = qualifiedName + "#" + Integer.toString(relativeLevel);
final Set<String> beingImported = ourBeingImported.get();
if (beingImported.contains(marker)) {
return Collections.emptyList(); // break endless loop in import
@@ -297,8 +297,8 @@ public class PyRefactoringUtil {
final FindUsagesHandler handler = new PyFindUsagesHandlerFactory().createFindUsagesHandler(element, forHighlightUsages);
assert handler != null;
final List<PsiElement> elementsToProcess = new ArrayList<PsiElement>();
elementsToProcess.addAll(Arrays.asList(handler.getPrimaryElements()));
elementsToProcess.addAll(Arrays.asList(handler.getSecondaryElements()));
Collections.addAll(elementsToProcess, handler.getPrimaryElements());
Collections.addAll(elementsToProcess, handler.getSecondaryElements());
for (PsiElement e : elementsToProcess) {
handler.processElementUsages(e, new Processor<UsageInfo>() {
@Override
@@ -245,7 +245,7 @@ public final class PyClassRefactoringUtil {
final String asName = node.getCopyableUserData(ENCODED_IMPORT_AS);
final Boolean useFromImport = node.getCopyableUserData(ENCODED_USE_FROM_IMPORT);
if (target instanceof PsiDirectory) {
target = (PsiNamedElement)PyUtil.turnDirIntoPackageElement((PsiDirectory)target, node);
target = (PsiNamedElement)PyUtil.getPackageElement((PsiDirectory)target, node);
}
if (target instanceof PyFunction) {
final PyFunction f = (PyFunction)target;
@@ -16,8 +16,10 @@
package com.jetbrains.python.refactoring.move;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.QualifiedName;
@@ -40,8 +42,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.openapi.vfs.VirtualFileManager.*;
/**
* @author vlan
*/
@@ -91,32 +91,29 @@ public class PyMoveFileHandler extends MoveFileHandler {
continue;
}
final QualifiedName newName = QualifiedNameFinder.findShortestImportableQName(sourceElement);
final PsiElement fromKeyword = statement.getFirstChild();
final PsiElement firstDot = fromKeyword.getNextSibling().getNextSibling();
assert firstDot.getNode().getElementType() == PyTokenTypes.DOT;
final PsiWhiteSpace nextWhitespace = PsiTreeUtil.getNextSiblingOfType(firstDot, PsiWhiteSpace.class);
final PsiElement replacementEnd = nextWhitespace == null ? statement.getLastChild() : nextWhitespace.getPrevSibling();
if (replacementEnd != firstDot) {
statement.deleteChildRange(firstDot.getNextSibling(), replacementEnd);
}
replaceWithQualifiedExpression(firstDot, newName);
replaceRelativeImportSourceWithQualifiedExpression(statement, newName);
}
}
@Nullable
private static PsiFileSystemItem resolveRelativeImportSourceFromModuleLocation(@NotNull String moduleLocation,
@NotNull PyFromImportStatement statement) {
String relativeImportBasePath = extractPath(moduleLocation);
String relativeImportBasePath = VirtualFileManager.extractPath(moduleLocation);
for (int level = 0; level < statement.getRelativeLevel(); level++) {
relativeImportBasePath = PathUtil.getParentPath(relativeImportBasePath);
}
if (!relativeImportBasePath.isEmpty()) {
//noinspection ConstantConditions
final String relativeImportBaseUrl = constructUrl(extractProtocol(moduleLocation), relativeImportBasePath);
final VirtualFile relativeImportBaseDir = getInstance().findFileByUrl(relativeImportBaseUrl);
final String protocol = VirtualFileManager.extractProtocol(moduleLocation);
assert protocol != null : "Original location: " + moduleLocation;
final String relativeImportBaseUrl = VirtualFileManager.constructUrl(protocol, relativeImportBasePath);
final VirtualFile relativeImportBaseDir = VirtualFileManager.getInstance().findFileByUrl(relativeImportBaseUrl);
VirtualFile sourceFile = relativeImportBaseDir;
if (relativeImportBaseDir != null && relativeImportBaseDir.exists() && statement.getImportSource() != null) {
final String relativePath = statement.getImportSource().getText().replace('.', '/');
final QualifiedName qualifiedName = statement.getImportSource().asQualifiedName();
if (qualifiedName == null) {
return null;
}
final String relativePath = qualifiedName.join("/");
sourceFile = relativeImportBaseDir.findFileByRelativePath(relativePath);
if (sourceFile == null) {
sourceFile = relativeImportBaseDir.findFileByRelativePath(relativePath + PyNames.DOT_PY);
@@ -186,8 +183,12 @@ public class PyMoveFileHandler extends MoveFileHandler {
continue;
}
final QualifiedName newElementName = QualifiedNameFinder.findCanonicalImportPath(newElement, element);
removeLeadingDots(element);
replaceWithQualifiedExpression(element, newElementName);
if (importStmt instanceof PyFromImportStatement) {
replaceRelativeImportSourceWithQualifiedExpression((PyFromImportStatement)importStmt, newElementName);
}
else {
replaceWithQualifiedExpression(element, newElementName);
}
}
else if (element instanceof PyReferenceExpression) {
updatedFiles.add(file);
@@ -227,21 +228,58 @@ public class PyMoveFileHandler extends MoveFileHandler {
return oldElement;
}
private static void removeLeadingDots(@NotNull PsiElement element) {
PsiElement lastDot = null;
PsiElement firstDot = null;
for (PsiElement prev = element.getPrevSibling(); prev != null; prev = prev.getPrevSibling()) {
if (prev.getNode().getElementType() != PyTokenTypes.DOT) {
break;
/**
* Replace import source with leading dots (if any) with reference expression created from given qualified name.
* Basically it does the same thing as {@link #replaceWithQualifiedExpression}, but also removes leading dots.
*
* @param importStatement import statement to update
* @param qualifiedName qualified name of new import source
* @return updated import statement
* @see #replaceWithQualifiedExpression(com.intellij.psi.PsiElement, com.intellij.psi.util.QualifiedName)
*/
@NotNull
private static PsiElement replaceRelativeImportSourceWithQualifiedExpression(@NotNull PyFromImportStatement importStatement,
@Nullable QualifiedName qualifiedName) {
final Couple<PsiElement> range = getRelativeImportSourceRange(importStatement);
if (range != null && qualifiedName != null) {
if (range.getFirst() == range.getSecond()) {
replaceWithQualifiedExpression(range.getFirst(), qualifiedName);
}
if (lastDot == null) {
lastDot = prev;
else {
importStatement.deleteChildRange(range.getFirst().getNextSibling(), range.getSecond());
replaceWithQualifiedExpression(range.getFirst(), qualifiedName);
}
firstDot = prev;
}
if (lastDot != null && firstDot != null) {
element.getParent().deleteChildRange(firstDot, lastDot);
return importStatement;
}
@Nullable
private static Couple<PsiElement> getRelativeImportSourceRange(@NotNull PyFromImportStatement statement) {
final PsiElement fromKeyword = statement.getFirstChild();
assert fromKeyword.getNode().getElementType() == PyTokenTypes.FROM_KEYWORD;
final PsiElement elementAfterFrom = PsiTreeUtil.skipSiblingsForward(fromKeyword, PsiWhiteSpace.class);
if (elementAfterFrom == null) {
return null;
}
else if (elementAfterFrom instanceof PyReferenceExpression) {
return Couple.of(elementAfterFrom, elementAfterFrom);
}
else if (elementAfterFrom.getNode().getElementType() == PyTokenTypes.DOT) {
PsiElement lastDot;
PsiElement next = elementAfterFrom;
do {
lastDot = next;
next = PsiTreeUtil.skipSiblingsForward(next, PsiWhiteSpace.class);
}
while (next != null && next.getNode().getElementType() == PyTokenTypes.DOT);
if (next instanceof PyReferenceExpression) {
return Couple.of(elementAfterFrom, next);
}
else {
return Couple.of(elementAfterFrom, lastDot);
}
}
return null;
}
@Override
@@ -1 +0,0 @@
from .case import TestCase
@@ -1,2 +0,0 @@
class TestCase(object):
pass
@@ -1 +0,0 @@
from .case import TestCase
@@ -1,2 +0,0 @@
class TestCase(object):
pass
@@ -0,0 +1,3 @@
from pkg.subpkg2.subsubpkg import b
print(b)
@@ -0,0 +1,3 @@
from .. subpkg2 . subsubpkg import b
print(b)
@@ -75,7 +75,7 @@ public class PyPep8NamingInspectionTest extends PyTestCase {
}
public void testTest() {
doTest();
doMultiFileTest();
}
public void testOverrideFromModule() {
@@ -90,4 +90,12 @@ public class PyPep8NamingInspectionTest extends PyTestCase {
myFixture.enableInspections(PyPep8NamingInspection.class);
myFixture.checkHighlighting(false, false, true);
}
private void doMultiFileTest() {
myFixture.copyDirectoryToProject("inspections/PyPep8NamingInspection/" + getTestName(true), "");
myFixture.configureByFile("a.py");
myFixture.enableInspections(PyPep8NamingInspection.class);
myFixture.checkHighlighting(false, false, true);
}
}
@@ -200,6 +200,12 @@ public class PyMoveTest extends PyTestCase {
doMoveFileTest("pkg1/subpkg1", "");
}
// PY-14432
public void testRelativeImportSourceWithSpacesInsideMovedModule() {
doMoveFileTest("pkg/subpkg1/a.py", "");
}
// PY-14595
public void testNamespacePackageUsedInMovedFunction() {
runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() {