diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/SuperClassHasFrequentlyUsedInheritorsInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/SuperClassHasFrequentlyUsedInheritorsInspection.java index 03f5c4d24439..b8a838a1854a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/SuperClassHasFrequentlyUsedInheritorsInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/SuperClassHasFrequentlyUsedInheritorsInspection.java @@ -45,6 +45,7 @@ public class SuperClassHasFrequentlyUsedInheritorsInspection extends BaseJavaBat @NotNull final InspectionManager manager, final boolean isOnTheFly) { if (aClass.isInterface() || + aClass.isEnum() || aClass instanceof PsiTypeParameter || aClass.getMethods().length != 0 || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { @@ -86,7 +87,9 @@ public class SuperClassHasFrequentlyUsedInheritorsInspection extends BaseJavaBat @Nullable private static PsiClass getSuperIfUnique(@NotNull final PsiClass aClass) { if (aClass instanceof PsiAnonymousClass) { - return (PsiClass)((PsiAnonymousClass)aClass).getBaseClassReference().resolve(); + final PsiClass returnClass = (PsiClass)((PsiAnonymousClass)aClass).getBaseClassReference().resolve(); + if (returnClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(returnClass.getQualifiedName())) return null; + return returnClass; } final PsiReferenceList extendsList = aClass.getExtendsList(); if (extendsList != null) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java index dba0f1fb5ebb..917a8784b048 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java @@ -19,8 +19,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.ClassFileViewProvider; -import com.intellij.psi.impl.source.JavaFileElementType; import com.intellij.psi.stubs.BinaryFileStubBuilder; import com.intellij.psi.stubs.PsiFileStub; import com.intellij.psi.stubs.StubElement; @@ -36,7 +34,7 @@ import java.util.Comparator; public class ClassFileStubBuilder implements BinaryFileStubBuilder { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClassFileStubBuilder"); - public static final int STUB_VERSION = 7; + public static final int STUB_VERSION = 8; @Override public boolean acceptsFile(final VirtualFile file) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsMethodImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsMethodImpl.java index 83418ec617b6..64ff8788692b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsMethodImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsMethodImpl.java @@ -283,9 +283,9 @@ public class ClsMethodImpl extends ClsMemberImpl implements PsiAn @Nullable @Override public Result compute() { - return Result.create(calcSourceMirrorMethod(), - getContainingFile(), - getContainingFile().getNavigationElement(), + return Result.create(calcSourceMirrorMethod(), + getContainingFile(), + getContainingFile().getNavigationElement(), FileIndexFacade.getInstance(getProject()).getRootModificationTracker()); } }); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParametersListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParametersListImpl.java index ba4802b99f63..b5d96af19adc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParametersListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeParametersListImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -41,7 +41,7 @@ public class ClsTypeParametersListImpl extends ClsRepositoryPsiElement 0) buffer.append(", "); appendText(params[i], indentLevel, buffer); } - buffer.append("> "); + buffer.append(">"); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java index 7c40209ff9cd..6033e54f712c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/SignatureParsing.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -29,12 +29,13 @@ import com.intellij.psi.impl.java.stubs.impl.PsiTypeParameterStubImpl; import com.intellij.psi.stubs.StubElement; import com.intellij.util.ArrayUtil; import com.intellij.util.cls.ClsFormatException; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import java.text.CharacterIterator; -import java.util.ArrayList; +import java.util.List; @SuppressWarnings({"HardCodedStringLiteral"}) public class SignatureParsing { @@ -55,30 +56,33 @@ public class SignatureParsing { return list; } - private static PsiTypeParameterStub parseTypeParameter(CharacterIterator signatureIterator, PsiTypeParameterListStub parent) - throws ClsFormatException { + private static PsiTypeParameterStub parseTypeParameter(CharacterIterator iterator, PsiTypeParameterListStub parent) throws ClsFormatException { StringBuilder name = new StringBuilder(); - while (signatureIterator.current() != ':' && signatureIterator.current() != CharacterIterator.DONE) { - name.append(signatureIterator.current()); - signatureIterator.next(); + while (iterator.current() != ':' && iterator.current() != CharacterIterator.DONE) { + name.append(iterator.current()); + iterator.next(); } - if (signatureIterator.current() == CharacterIterator.DONE) { + if (iterator.current() == CharacterIterator.DONE) { throw new ClsFormatException(); } //todo parse annotations on type param PsiTypeParameterStub parameterStub = new PsiTypeParameterStubImpl(parent, StringRef.fromString(name.toString())); - ArrayList bounds = null; - while (signatureIterator.current() == ':') { - signatureIterator.next(); - String bound = parseTopLevelClassRefSignature(signatureIterator); - if (bound != null && !bound.equals(CommonClassNames.JAVA_LANG_OBJECT)) { - if (bounds == null) bounds = new ArrayList(); + List bounds = ContainerUtil.newSmartList(); + while (iterator.current() == ':') { + iterator.next(); + String bound = parseTopLevelClassRefSignature(iterator); + if (bound != null) { bounds.add(bound); } } + int size = bounds.size(); + if (size > 0 && CommonClassNames.JAVA_LANG_OBJECT.equals(bounds.get(size - 1))) { + bounds.remove(size - 1); + } + StubBuildingVisitor.newReferenceList(JavaStubElementTypes.EXTENDS_BOUND_LIST, parameterStub, ArrayUtil.toStringArray(bounds)); return parameterStub; diff --git a/java/java-tests/testData/psi/cls/mirror/Bounds.txt b/java/java-tests/testData/psi/cls/mirror/Bounds.txt new file mode 100644 index 000000000000..0854f8511168 --- /dev/null +++ b/java/java-tests/testData/psi/cls/mirror/Bounds.txt @@ -0,0 +1,13 @@ + + // IntelliJ API Decompiler stub source generated from a class file + // Implementation of methods is not available + +package pkg; + +class Bounds { + Bounds() { /* compiled code */ } + + public static > T max(java.util.Collection ts) { /* compiled code */ } + + public static T max(java.util.Collection ts, java.util.Comparator comparator) { /* compiled code */ } +} \ No newline at end of file diff --git a/java/java-tests/testData/psi/cls/mirror/KotlinFunList.txt b/java/java-tests/testData/psi/cls/mirror/KotlinFunList.txt index a08328b13468..b6c31e2576ce 100644 --- a/java/java-tests/testData/psi/cls/mirror/KotlinFunList.txt +++ b/java/java-tests/testData/psi/cls/mirror/KotlinFunList.txt @@ -4,7 +4,7 @@ package pkg; -public abstract class KotlinFunList { +public abstract class KotlinFunList { public static pkg.KotlinFunList.ClassObject$ $classobj; public KotlinFunList() { /* compiled code */ } @@ -12,13 +12,13 @@ public abstract class KotlinFunList { public static final class ClassObject$ { public ClassObject$() { /* compiled code */ } - public final class Standard { + public final class Standard { final pkg.KotlinFunList.ClassObject$ this$0; public Standard() { /* compiled code */ } } - public final class Empty { + public final class Empty { final pkg.KotlinFunList.ClassObject$ this$0; public Empty() { /* compiled code */ } diff --git a/java/java-tests/testData/psi/cls/mirror/pkg/Bounds.class b/java/java-tests/testData/psi/cls/mirror/pkg/Bounds.class new file mode 100644 index 000000000000..ce57f184578b Binary files /dev/null and b/java/java-tests/testData/psi/cls/mirror/pkg/Bounds.class differ diff --git a/java/java-tests/testData/psi/cls/mirror/src/pkg/Bounds.java b/java/java-tests/testData/psi/cls/mirror/src/pkg/Bounds.java new file mode 100644 index 000000000000..bacda1c53fed --- /dev/null +++ b/java/java-tests/testData/psi/cls/mirror/src/pkg/Bounds.java @@ -0,0 +1,14 @@ +package pkg; + +import java.util.Collection; +import java.util.Comparator; + +class Bounds { + public static > T max(Collection coll) { + return null; + } + + public static T max(Collection coll, Comparator comp) { + return null; + } +} diff --git a/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt b/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt index d58e2e68de90..82d04fec4659 100644 --- a/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt +++ b/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt @@ -1693,7 +1693,7 @@ PsiJavaFileStub [java.util] PsiModifierListStub[mask=9] PsiTypeParameterListStub PsiTypeParameter[T] - PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Comparable] + PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Object, java.lang.Comparable] PsiParameterListStub PsiParameterStub[p1:java.util.List] PsiModifierListStub[mask=0] @@ -1704,7 +1704,7 @@ PsiJavaFileStub [java.util] PsiModifierListStub[mask=10] PsiTypeParameterListStub PsiTypeParameter[T] - PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Comparable] + PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Object, java.lang.Comparable] PsiParameterListStub PsiParameterStub[p1:java.util.List] PsiModifierListStub[mask=0] @@ -1715,7 +1715,7 @@ PsiJavaFileStub [java.util] PsiModifierListStub[mask=10] PsiTypeParameterListStub PsiTypeParameter[T] - PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Comparable] + PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Object, java.lang.Comparable] PsiParameterListStub PsiParameterStub[p1:java.util.List] PsiModifierListStub[mask=0] @@ -1843,7 +1843,7 @@ PsiJavaFileStub [java.util] PsiModifierListStub[mask=9] PsiTypeParameterListStub PsiTypeParameter[T] - PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Comparable] + PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Object, java.lang.Comparable] PsiParameterListStub PsiParameterStub[p1:java.util.Collection] PsiModifierListStub[mask=0] @@ -1863,7 +1863,7 @@ PsiJavaFileStub [java.util] PsiModifierListStub[mask=9] PsiTypeParameterListStub PsiTypeParameter[T] - PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Comparable] + PsiRefListStub[EXTENDS_BOUNDS_LIST:java.lang.Object, java.lang.Comparable] PsiParameterListStub PsiParameterStub[p1:java.util.Collection] PsiModifierListStub[mask=0] diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsDuplicatesTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsDuplicatesTest.java index 47189fb7d493..81dcb5c3298a 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsDuplicatesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsDuplicatesTest.java @@ -27,6 +27,28 @@ import gnu.trove.TObjectHashingStrategy; import java.util.Set; public class ClsDuplicatesTest extends PsiTestCase { + private Set myUnique = new THashSet(new TObjectHashingStrategy() { + @Override + public int computeHashCode(PsiNamedElement object) { + String name = object.getName(); + return name == null ? 0 : name.hashCode(); + } + + @Override + public boolean equals(PsiNamedElement o1, PsiNamedElement o2) { + return o1.getParent() == o2.getParent() && + o1.getClass() == o2.getClass() && + StringUtil.equals(o1.getName(), o2.getName()) && + StringUtil.equals(o1.getText(), o2.getText()); + } + }); + + @Override + protected void tearDown() throws Exception { + myUnique = null; + super.tearDown(); + } + @Override protected Sdk getTestProjectJdk() { return JavaTestUtil.getTestJdk(); @@ -35,12 +57,11 @@ public class ClsDuplicatesTest extends PsiTestCase { public void testDuplicates() throws Exception { final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage(""); assert rootPackage != null; + final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); JavaRecursiveElementVisitor visitor = new JavaRecursiveElementVisitor() { @Override public void visitPackage(PsiPackage aPackage) { -// System.out.println(aPackage.getQualifiedName()); - visit(aPackage); for (PsiPackage subPackage : aPackage.getSubPackages(scope)) { visitPackage(subPackage); @@ -60,46 +81,21 @@ public class ClsDuplicatesTest extends PsiTestCase { @Override public void visitClass(PsiClass aClass) { - if ("com.sun.xml.internal.bind.v2.runtime.unmarshaller.DomLoader.State".equals(aClass.getQualifiedName())) { - int i =0; - } super.visitClass(aClass); PsiElement parent = aClass.getParent(); - if (parent instanceof PsiFile){ - uniques.clear(); + if (parent instanceof PsiFile) { + myUnique.clear(); } } }; + rootPackage.accept(visitor); } - private final Set uniques = new THashSet(new TObjectHashingStrategy() { - @Override - public int computeHashCode(PsiNamedElement object) { - String name = object.getName(); - return name == null ? 0 : name.hashCode(); - } - - @Override - public boolean equals(PsiNamedElement o1, PsiNamedElement o2) { - boolean eq = o1.getParent() == o2.getParent() && StringUtil.equals(o1.getName(), o2.getName()) && o1.getClass() == o2.getClass() - && StringUtil.equals(o1.getText(), o2.getText()); - - if (eq) { - return true; - } - else { - return false; - } - } - }); - private void visit(PsiNamedElement element) { - if (!uniques.add(element)) { - fail("Duplicate Element: " + - ElementDescriptionUtil.getElementDescription(element, UsageViewLongNameLocation.INSTANCE) + - ": " + - element.getText()); + if (!myUnique.add(element)) { + String description = ElementDescriptionUtil.getElementDescription(element, UsageViewLongNameLocation.INSTANCE); + fail("Duplicate Element: " + description + ": " + element.getText()); } } } diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsMirrorBuildingTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsMirrorBuildingTest.java index 234c624dcaba..9e0c410d7ec5 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsMirrorBuildingTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsMirrorBuildingTest.java @@ -47,6 +47,7 @@ public class ClsMirrorBuildingTest extends LightIdeaTestCase { public void testMiddle$Buck() { doTest(); } public void testDefaultPackage() { doTest(); } public void testLocalClass() { doTest(); } + public void testBounds() { doTest(); } private void doTest() { doTest(getTestName(false)); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GrReassignedLocalVarsChecker.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GrReassignedLocalVarsChecker.java index 5a155c18d640..580dd918bf9e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GrReassignedLocalVarsChecker.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/GrReassignedLocalVarsChecker.java @@ -37,7 +37,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; @@ -57,7 +56,7 @@ public class GrReassignedLocalVarsChecker { private static final Key> REASSIGNED_VAR = Key.create("least upper bound type"); @Nullable - public static Boolean isReassignedVar(final GrReferenceExpression refExpr) { + public static Boolean isReassignedVar(@NotNull final GrReferenceExpression refExpr) { if (!PsiUtil.isCompileStatic(refExpr)) { return false; } @@ -86,7 +85,7 @@ public class GrReassignedLocalVarsChecker { return data.getValue(); } - private static boolean isReassignedVarImpl(final GrVariable resolved) { + private static boolean isReassignedVarImpl(@NotNull final GrVariable resolved) { final GrControlFlowOwner variableScope = PsiTreeUtil.getParentOfType(resolved, GrCodeBlock.class, GroovyFile.class); if (variableScope == null) return false; @@ -97,7 +96,7 @@ public class GrReassignedLocalVarsChecker { ((GroovyPsiElement)scope).accept(new GroovyRecursiveElementVisitor() { @Override public void visitClosure(GrClosableBlock closure) { - if (getAssignedVarsInsideBlock(closure).contains(name)) { + if (getUsedVarsInsideBlock(closure).contains(name)) { isReassigned.set(true); } } @@ -133,7 +132,7 @@ public class GrReassignedLocalVarsChecker { } @Nullable - private static PsiType getLeastUpperBoundByVar(final GrVariable resolved) { + private static PsiType getLeastUpperBoundByVar(@NotNull final GrVariable resolved) { CachedValue data = resolved.getUserData(LEAST_UPPER_BOUND_TYPE); if (data == null) { data = CachedValuesManager.getManager(resolved.getProject()).createCachedValue(new CachedValueProvider() { @@ -148,7 +147,7 @@ public class GrReassignedLocalVarsChecker { } @Nullable - private static PsiType getLeastUpperBoundByVarImpl(final GrVariable resolved) { + private static PsiType getLeastUpperBoundByVarImpl(@NotNull final GrVariable resolved) { return RecursionManager.doPreventingRecursion(resolved, false, new NullableComputable() { @Override public PsiType compute() { @@ -170,7 +169,7 @@ public class GrReassignedLocalVarsChecker { } @NotNull - private static Set getAssignedVarsInsideBlock(@NotNull final GrCodeBlock block) { + private static Set getUsedVarsInsideBlock(@NotNull final GrCodeBlock block) { CachedValue> data = block.getUserData(ASSIGNED_VARS); if (data == null) { @@ -181,27 +180,24 @@ public class GrReassignedLocalVarsChecker { final Set result = ContainerUtil.newHashSet(); block.acceptChildren(new GroovyRecursiveElementVisitor() { - @Override - public void visitAssignmentExpression(GrAssignmentExpression expression) { - super.visitAssignmentExpression(expression); - - GrExpression lValue = expression.getLValue(); - if (lValue instanceof GrReferenceExpression && !((GrReferenceExpression)lValue).isQualified()) { - result.add(((GrReferenceExpression)lValue).getReferenceName()); - } - } @Override public void visitOpenBlock(GrOpenBlock openBlock) { - result.addAll(getAssignedVarsInsideBlock(openBlock)); + result.addAll(getUsedVarsInsideBlock(openBlock)); } @Override public void visitClosure(GrClosableBlock closure) { - result.addAll(getAssignedVarsInsideBlock(closure)); + result.addAll(getUsedVarsInsideBlock(closure)); + } + + @Override + public void visitReferenceExpression(GrReferenceExpression referenceExpression) { + if (referenceExpression.getQualifier() == null && referenceExpression.getReferenceName() != null) { + result.add(referenceExpression.getReferenceName()); + } } }); - return Result.create(result, block); } }, false); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties index 5ccb19b400aa..348e53ffbbb6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/GroovyInspectionBundle.properties @@ -85,7 +85,7 @@ replace.postfix.0.with.prefix.0=Replace postfix {0} with prefix {0} replace.0.with.1=Replace {0} with binary {1} gr.deprecated.api.usage=Deprecated API inspection category.method.0.cannot.be.applied.to.1=Category method ''{0}'' cannot be applied to ''{1}'' -local.var.0.is.reassigned.in.closure=Local variable {0} is reassigned in {1} with other type +local.var.0.is.reassigned=Local variable ''{0}'' is reassigned anonymous.class=anonymous class closure=closure other.scope=Other scope diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java index 6f16535b484a..82a688f9bd89 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/confusing/GrReassignedInClosureLocalVarInspection.java @@ -21,16 +21,12 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.codeInsight.GrReassignedLocalVarsChecker; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; -import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; @@ -70,38 +66,18 @@ public class GrReassignedInClosureLocalVarInspection extends BaseInspection { final PsiElement resolved = referenceExpression.resolve(); if (!GroovyRefactoringUtil.isLocalVariable(resolved)) return; - final PsiType checked = GrReassignedLocalVarsChecker.getReassignedVarType(referenceExpression, false); - if (checked == null) return; - - final GrControlFlowOwner varFlowOwner = ControlFlowUtils.findControlFlowOwner(resolved); - final GrControlFlowOwner refFlorOwner = ControlFlowUtils.findControlFlowOwner(referenceExpression); - if (isOtherScopeAndType(referenceExpression, checked, varFlowOwner, refFlorOwner)) { - String flowDescription = getFlowDescription(refFlorOwner); - final String message = message("local.var.0.is.reassigned.in.closure", ((GrNamedElement)resolved).getName(), flowDescription); + if (isOtherTypeOrDifferent(referenceExpression, (GrVariable)resolved) ) { + final String message = message("local.var.0.is.reassigned", ((GrNamedElement)resolved).getName()); registerError(referenceExpression, message, LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } } }; } - private static boolean isOtherScopeAndType(GrReferenceExpression referenceExpression, - PsiType checked, - GrControlFlowOwner varFlowOwner, - GrControlFlowOwner refFlorOwner) { - return varFlowOwner != refFlorOwner && !TypesUtil.isAssignable(referenceExpression.getType(), checked, referenceExpression); - } + private static boolean isOtherTypeOrDifferent(@NotNull GrReferenceExpression referenceExpression, GrVariable resolved) { + if (ControlFlowUtils.findControlFlowOwner(referenceExpression) != ControlFlowUtils.findControlFlowOwner(resolved)) return true; - private static String getFlowDescription(GrControlFlowOwner refFlorOwner) { - String flowDescription; - if (refFlorOwner instanceof GrClosableBlock) { - flowDescription = message("closure"); - } - else if (refFlorOwner instanceof GrAnonymousClassDefinition) { - flowDescription = message("anonymous.class"); - } - else { - flowDescription = message("other.scope"); - } - return flowDescription; + final PsiType currentType = referenceExpression.getType(); + return currentType != null && currentType != PsiType.NULL && !ControlFlowUtils.findAccess(resolved, referenceExpression, false, true).isEmpty(); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java index b1a497ddc00f..bff12db841ac 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java @@ -709,15 +709,10 @@ public class ControlFlowUtils { * @param ahead if true search for next write. if false searches for previous write * @return all write instructions leading to (or preceding) the place */ - public static ReadWriteVariableInstruction[] findWriteAccess(GrVariable local, final PsiElement place, boolean ahead) { - List res = findAccess(local, place, ahead, true); - return res.toArray(new ReadWriteVariableInstruction[res.size()]); - } - public static List findAccess(GrVariable local, final PsiElement place, boolean ahead, boolean writeAccessOnly) { LOG.assertTrue(!(local instanceof GrField), local.getClass()); - final GrControlFlowOwner owner = findControlFlowOwner(local); + final GrControlFlowOwner owner = findControlFlowOwner(place); assert owner != null; final Instruction cur = findInstruction(place, owner.getControlFlow()); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java index 4da4d1321c87..cf69b239ed8a 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrLiteralImpl.java @@ -54,7 +54,7 @@ public class GrLiteralImpl extends GrAbstractLiteral implements GrLiteral, PsiLa public PsiType getType() { IElementType elemType = getLiteralType(this); - return elemType == kNULL ? PsiType.NULL : TypesUtil.getPsiType(this, elemType); + return TypesUtil.getPsiType(this, elemType); } public void accept(GroovyElementVisitor visitor) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy index efed43e59ec5..9568abf5b7a9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy @@ -149,7 +149,7 @@ boolean bar(def list) { test() { def var = "abc" def cl = { - var = new Date() + var = new Date() } cl() var.toUpperCase() @@ -158,7 +158,7 @@ test() { test2() { def var = "abc" def cl = { - var = 'cde' + var = 'cde' } cl() var.toUpperCase()