Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2013-11-04 17:25:24 +01:00
9 changed files with 110 additions and 17 deletions
@@ -464,13 +464,38 @@ public class GenericsHighlightUtil {
final PsiIdentifier classIdentifier = aClass.getNameIdentifier();
if (PsiUtil.isLanguageLevel8OrHigher(aClass) && classIdentifier != null) {
final HighlightInfo info = checkUnrelatedDefaultMethods(aClass, signaturesWithSupers, classIdentifier);
HighlightInfo info = checkUnrelatedDefaultMethods(aClass, signaturesWithSupers, classIdentifier);
if (info != null) return info;
info = checkDefaultMethodOverrideEquivalentToObjectNonPrivate(aClass, signaturesWithSupers);
if (info != null) return info;
}
return null;
}
private static HighlightInfo checkDefaultMethodOverrideEquivalentToObjectNonPrivate(PsiClass aClass,
Collection<HierarchicalMethodSignature> withSupers) {
if (aClass.isInterface()) {
for (HierarchicalMethodSignature sig : withSupers) {
final PsiMethod method = sig.getMethod();
if (method.hasModifierProperty(PsiModifier.DEFAULT)) {
for (HierarchicalMethodSignature methodSignature : sig.getSuperSignatures()) {
final PsiClass containingClass = methodSignature.getMethod().getContainingClass();
if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) {
final PsiIdentifier identifier = method.getNameIdentifier();
LOG.assertTrue(identifier != null);
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.descriptionAndTooltip("Default method " + sig.getName() + " overrides a member of java.lang.Object")
.range(identifier)
.create();
}
}
}
}
}
return null;
}
private static HighlightInfo checkUnrelatedDefaultMethods(PsiClass aClass,
Collection<HierarchicalMethodSignature> signaturesWithSupers,
PsiIdentifier classIdentifier) {
@@ -485,20 +510,32 @@ public class GenericsHighlightUtil {
final PsiClass superContainingClass = superMethod.getContainingClass();
if (containingClass != null && superContainingClass != null && !InheritanceUtil
.isInheritorOrSelf(containingClass, superContainingClass, true)) {
if (superMethod.hasModifierProperty(PsiModifier.DEFAULT)) {
final String inheritUnrelatedDefaultsMessage = HighlightUtil.formatClass(aClass) + " inherits unrelated defaults for " +
JavaHighlightUtil.formatMethod(method) + " from types " + HighlightUtil.formatClass(containingClass) +
" and " + HighlightUtil.formatClass(superContainingClass);
return HighlightInfo
.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(inheritUnrelatedDefaultsMessage).create();
}
if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
final boolean isDefault = superMethod.hasModifierProperty(PsiModifier.DEFAULT);
if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT) && !isDefault) {
final String message = JavaErrorMessages.message(
aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract",
HighlightUtil.formatClass(superContainingClass),
JavaHighlightUtil.formatMethod(superMethod),
HighlightUtil.formatClass(superContainingClass, false));
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(message).create();
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(classIdentifier).descriptionAndTooltip(message)
.create();
}
if (isDefault || superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
final String message = isDefault
? " inherits unrelated defaults for "
: " inherits abstract and default for ";
final String inheritUnrelatedDefaultsMessage = HighlightUtil.formatClass(aClass) +
message +
JavaHighlightUtil.formatMethod(method) +
" from types " +
HighlightUtil.formatClass(containingClass) +
" and " +
HighlightUtil.formatClass(superContainingClass);
return HighlightInfo
.newHighlightInfo(HighlightInfoType.ERROR).range(classIdentifier).descriptionAndTooltip(inheritUnrelatedDefaultsMessage)
.create();
}
}
}
@@ -30,6 +30,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ConcurrentWeakHashMap;
import gnu.trove.THashMap;
@@ -204,9 +205,13 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
PsiUtil.setModifierProperty(newVariable, PsiModifier.FINAL, true);
PsiElement statement = getStatementToInsertBefore();
if (statement == null) return;
statement.getParent().addBefore(copyDecl, statement);
PsiExpression newExpression = factory.createExpressionFromText(newName, myVariable);
replaceReferences(myClass, myVariable, newExpression);
if (RefactoringUtil.isLoopOrIf(statement.getParent())) {
RefactoringUtil.putStatementInLoopBody(copyDecl, statement.getParent(), statement);
} else {
statement.getParent().addBefore(copyDecl, statement);
}
}
private PsiElement getStatementToInsertBefore() {
@@ -217,7 +222,7 @@ public class VariableAccessFromInnerClassFix implements IntentionAction {
PsiElement statement = myClass;
nextInnerClass:
do {
statement = PsiUtil.getEnclosingStatement(statement);
statement = RefactoringUtil.getParentStatement(statement, false);
if (statement == null || statement.getParent() == null) {
return null;
@@ -25,7 +25,7 @@ class ReturnTypeIncompatibility {
}
public static void main(String[] args) {
call<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<Integer>)' and 'ReturnTypeIncompatibility.call(I2<String>)' match">(i-> {return i;})</error>;
call<error descr="Ambiguous method call: both 'ReturnTypeIncompatibility.call(I1<Integer>)' and 'ReturnTypeIncompatibility.call(I2<String & Integer>)' match">(i-> {return i;})</error>;
}
}
@@ -0,0 +1,5 @@
interface A {
default String <error descr="Default method toString overrides a member of java.lang.Object">toString</error>() {
return "";
}
}
@@ -12,4 +12,17 @@ interface SecondParent {
class <error descr="Class 'SecondParent' must either be declared abstract or implement abstract method 'doSomething()' in 'SecondParent'">FirstSon</error> implements FirstParent, SecondParent {}
<error descr="Class 'SecondSon' must either be declared abstract or implement abstract method 'doSomething()' in 'SecondParent'">class SecondSon implements SecondParent, FirstParent</error> {}
<error descr="Class 'SecondSon' must either be declared abstract or implement abstract method 'doSomething()' in 'SecondParent'">class SecondSon implements SecondParent, FirstParent</error> {}
interface A {
default int foo() {
return 1;
}
}
interface B {
abstract int foo();
}
interface <error descr="C inherits abstract and default for foo() from types A and B">C</error> extends A, B {
}
@@ -0,0 +1,17 @@
// "Copy 'i' to temp final variable" "true"
class ParamTypeBug {
private static String strings[] = new String[]{ "a", "b", "c" };
public static void main(final String ... args){
if (args.length == 1){
for(int i = 0; i < strings.length; i++) {
final int finalI = i;
new Thread(){
public void run(){
new String(strings[finalI]);
}
}.start();
}
}
}
}
@@ -0,0 +1,15 @@
// "Copy 'i' to temp final variable" "true"
class ParamTypeBug {
private static String strings[] = new String[]{ "a", "b", "c" };
public static void main(final String ... args){
if (args.length == 1){
for(int i = 0; i < strings.length; i++)
new Thread(){
public void run(){
new String(strings[<caret>i]);
}
}.start();
}
}
}
@@ -31,6 +31,7 @@ public class Interface8MethodsHighlightingTest extends LightDaemonAnalyzerTestCa
public void testCyclicSubstitutor() { doTest(false, false); }
public void testThisAccessibility() { doTest(false, false); }
public void testStaticMethodCalls() { doTest(false, false); }
public void testDefaultMethodOverrideEquivalentObject() { doTest(false, false); }
private void doTest() {
doTest(false, false);
@@ -51,12 +51,12 @@ class DomStubBuilderVisitor {
StringRef.fromString(tag.getName()),
StringRef.fromNullableString(nsKey),
description instanceof CustomDomChildrenDescription);
for (final XmlTag subTag : tag.getSubTags()) {
visitXmlElement(subTag, stub);
}
for (XmlAttribute attribute : tag.getAttributes()) {
visitXmlElement(attribute, stub);
}
for (final XmlTag subTag : tag.getSubTags()) {
visitXmlElement(subTag, stub);
}
} else if (element instanceof XmlAttribute) {
new AttributeStub(parent, StringRef.fromString(((XmlAttribute)element).getLocalName()),
StringRef.fromNullableString(nsKey),