Resource declaration and assignment conflicts highlighting

This commit is contained in:
Roman Shevchenko
2011-02-23 21:04:42 +01:00
parent fdbaba14e1
commit 0a17b195bb
7 changed files with 60 additions and 77 deletions
@@ -674,25 +674,28 @@ public class HighlightControlFlowUtil {
@Nullable
public static PsiClass getInnerClassVariableReferencedFrom(PsiVariable variable, PsiElement context) {
PsiElement scope;
PsiElement[] scope;
if (variable instanceof PsiScopedLocalVariable) {
scope = ((PsiScopedLocalVariable)variable).getDeclarationScope();
}
else if (variable instanceof PsiLocalVariable) {
scope = variable.getParent().getParent(); // code block or for statement
scope = new PsiElement[]{variable.getParent().getParent()}; // code block or for statement
}
else if (variable instanceof PsiParameter) {
scope = ((PsiParameter)variable).getDeclarationScope();
scope = new PsiElement[]{((PsiParameter)variable).getDeclarationScope()};
}
else {
scope = variable.getParent();
scope = new PsiElement[]{variable.getParent()};
}
if (scope.getContainingFile() != context.getContainingFile()) return null;
if (scope.length < 1 || scope[0].getContainingFile() != context.getContainingFile()) return null;
PsiElement parent = context.getParent();
PsiElement prevParent = context;
outer:
while (parent != null) {
if (parent.equals(scope)) break;
for (PsiElement scopeElement : scope) {
if (parent.equals(scopeElement)) break outer;
}
if (parent instanceof PsiClass && !(prevParent instanceof PsiExpressionList && parent instanceof PsiAnonymousClass)) {
return (PsiClass)parent;
}
@@ -82,7 +82,7 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
super(node);
}
public boolean hasModifierProperty(@NotNull String name){
public boolean hasModifierProperty(@NotNull String name) {
final PsiModifierListStub stub = getStub();
if (stub != null) {
int flag = NAME_TO_MODIFIER_FLAG_MAP.get(name);
@@ -93,34 +93,34 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
IElementType type = NAME_TO_KEYWORD_TYPE_MAP.get(name);
PsiElement parent = getParent();
if (parent instanceof PsiClass){
PsiElement pparent = parent.getParent();
if (pparent instanceof PsiClass && ((PsiClass)pparent).isInterface()){
if (type == JavaTokenType.PUBLIC_KEYWORD){
if (parent instanceof PsiClass) {
PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiClass && ((PsiClass)grandParent).isInterface()) {
if (type == JavaTokenType.PUBLIC_KEYWORD) {
return true;
}
if (type == null){ // package local
if (type == null) { // package local
return false;
}
if (type == JavaTokenType.STATIC_KEYWORD){
if (type == JavaTokenType.STATIC_KEYWORD) {
return true;
}
}
if (((PsiClass)parent).isInterface()){
if (type == JavaTokenType.ABSTRACT_KEYWORD){
if (((PsiClass)parent).isInterface()) {
if (type == JavaTokenType.ABSTRACT_KEYWORD) {
return true;
}
// nested interface is implicitly static
if (pparent instanceof PsiClass) {
if (type == JavaTokenType.STATIC_KEYWORD){
if (grandParent instanceof PsiClass) {
if (type == JavaTokenType.STATIC_KEYWORD) {
return true;
}
}
}
if (((PsiClass)parent).isEnum()){
if (((PsiClass)parent).isEnum()) {
if (type == JavaTokenType.STATIC_KEYWORD) {
if (!(pparent instanceof PsiFile)) return true;
if (!(grandParent instanceof PsiFile)) return true;
}
else if (type == JavaTokenType.FINAL_KEYWORD) {
final PsiField[] fields = ((PsiClass)parent).getFields();
@@ -138,37 +138,37 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
}
}
}
else if (parent instanceof PsiMethod){
else if (parent instanceof PsiMethod) {
PsiClass aClass = ((PsiMethod)parent).getContainingClass();
if (aClass != null && aClass.isInterface()){
if (type == JavaTokenType.PUBLIC_KEYWORD){
if (aClass != null && aClass.isInterface()) {
if (type == JavaTokenType.PUBLIC_KEYWORD) {
return true;
}
if (type == null){ // package local
if (type == null) { // package local
return false;
}
if (type == JavaTokenType.ABSTRACT_KEYWORD){
if (type == JavaTokenType.ABSTRACT_KEYWORD) {
return true;
}
}
}
else if (parent instanceof PsiField){
else if (parent instanceof PsiField) {
if (parent instanceof PsiEnumConstant) {
return type == JavaTokenType.PUBLIC_KEYWORD || type == JavaTokenType.STATIC_KEYWORD || type == JavaTokenType.FINAL_KEYWORD;
}
else {
PsiClass aClass = ((PsiField)parent).getContainingClass();
if (aClass != null && aClass.isInterface()){
if (type == JavaTokenType.PUBLIC_KEYWORD){
if (aClass != null && aClass.isInterface()) {
if (type == JavaTokenType.PUBLIC_KEYWORD) {
return true;
}
if (type == null){ // package local
if (type == null) { // package local
return false;
}
if (type == JavaTokenType.STATIC_KEYWORD){
if (type == JavaTokenType.STATIC_KEYWORD) {
return true;
}
if (type == JavaTokenType.FINAL_KEYWORD){
if (type == JavaTokenType.FINAL_KEYWORD) {
return true;
}
}
@@ -177,9 +177,15 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
else if (parent instanceof PsiParameter) {
if (type == JavaTokenType.FINAL_KEYWORD && ((PsiParameter)parent).getType() instanceof PsiDisjunctionType) return true;
}
else if (parent instanceof PsiLocalVariable) {
PsiElement grandParent = parent.getParent();
if (type == JavaTokenType.FINAL_KEYWORD && grandParent instanceof PsiResource) return true;
}
if (type == null){ // package local
return !hasModifierProperty(PsiModifier.PUBLIC) && !hasModifierProperty(PsiModifier.PRIVATE) && !hasModifierProperty(PsiModifier.PROTECTED);
if (type == null) { // package local
return !hasModifierProperty(PsiModifier.PUBLIC) &&
!hasModifierProperty(PsiModifier.PRIVATE) &&
!hasModifierProperty(PsiModifier.PROTECTED);
}
return getNode().findChildByType(type) != null;
@@ -280,18 +280,18 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScop
}
@NotNull
public PsiElement getDeclarationScope() {
public PsiElement[] getDeclarationScope() {
final PsiElement parentElement = getParent();
if (parentElement instanceof PsiDeclarationStatement) {
return parentElement.getParent();
return new PsiElement[]{parentElement.getParent()};
}
else if (parentElement instanceof PsiResource) {
final PsiResourceList resourceList = (PsiResourceList)parentElement.getParent();
final PsiTryStatement tryStatement = (PsiTryStatement)resourceList.getParent();
final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
return tryBlock != null ? tryBlock : resourceList;
return tryBlock != null ? new PsiElement[]{resourceList, tryBlock} : new PsiElement[]{resourceList};
}
return parentElement.getParent();
return new PsiElement[]{parentElement.getParent()};
}
@NotNull
@@ -37,7 +37,8 @@ class C {
void m3(int p) throws Exception {
try (MyResource r = new MyResource()) {
r.doSomething();
/* todo: < error descr="Cannot assign a value to final variable 'r'">r = null</error >;*/
<error descr="Cannot assign a value to final variable 'r'">r = null</error>;
int <error descr="Variable 'r' is already defined in the scope">r</error> = 0;
}
catch (E e) {
<error descr="Cannot resolve symbol 'r'">r</error> = null;
@@ -49,6 +50,10 @@ class C {
try (MyResource <error descr="Variable 'r' is already defined in the scope">r</error> = new MyResource(); MyResource <error descr="Variable 'r' is already defined in the scope">r</error> = new MyResource()) { }
try (MyResource r1 = new MyResource(); MyResource r2 = r1) { }
/* todo: try (MyResource r1 = < error descr="Cannot resolve symbol 'r'">r2</error >; MyResource r2 = r1) { }*/
MyResource r = null;
try (MyResource <error descr="Variable 'r' is already defined in the scope">r</error> = new MyResource()) { }
try (r = new MyResource()) { }
@@ -27,24 +27,14 @@ class C {
System.out.println(r1);
}
try (MyResource r2 = <warning descr="Variable 'r2' initializer 'new MyResource()' is redundant">new MyResource()</warning>) {
r2 = null; // todo: check for NPE
System.out.println(r2);
}
MyResource r2 = null;
System.out.println(r2);
try (r2 = <warning descr="The value 'new MyResource()' assigned to r2 is never used">new MyResource()</warning>) { }
MyResource r3 = null;
System.out.println(r3);
try (r3 = <warning descr="The value 'new MyResource()' assigned to r3 is never used">new MyResource()</warning>) { }
try (MyResource <warning descr="Variable 'r3' is never used">r3</warning> = new MyResource()) { }
try (MyResource <warning descr="Variable 'r4' is never used">r4</warning> = new MyResource()) { }
try (MyResource r5 = new MyResource()) {
System.out.println(r5);
r5 = <warning descr="The value 'new MyResource()' assigned to r5 is never used">new MyResource()</warning>;
}
MyResource <warning descr="Variable 'r6' is never assigned">r6</warning>;
try (MyResource r = <error descr="Variable 'r6' might not have been initialized">r6</error>) {
MyResource <warning descr="Variable 'r4' is never assigned">r4</warning>;
try (MyResource r = <error descr="Variable 'r4' might not have been initialized">r4</error>) {
System.out.println(r);
}
}
@@ -254,6 +254,7 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
" void m() {\n" +
" int local = 0;\n" +
" for (int loop = 0; loop < 10; loop++) ;\n" +
" try (Resource r = new Resource()) { }\n" +
" }\n" +
"}",
@@ -296,28 +297,6 @@ public class JavaStubBuilderTest extends LightIdeaTestCase {
});
}
public void testNonMethodParameterLists() {
withLevel(LanguageLevel.JDK_1_7, new Runnable() {
@Override public void run() {
doTest("class C {\n" +
" {\n" +
" try (Resource r = new Resource()) { }\n" +
" }\n" +
"}",
"PsiJavaFileStub []\n" +
" IMPORT_LIST:PsiImportListStub\n" +
" CLASS:PsiClassStub[name=C fqn=C]\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n" +
" TYPE_PARAMETER_LIST:PsiTypeParameterListStub\n" +
" EXTENDS_LIST:PsiRefListStub[EXTENDS_LIST:]\n" +
" IMPLEMENTS_LIST:PsiRefListStub[IMPLEMENTS_LIST:]\n" +
" CLASS_INITIALIZER:PsiClassInitializerStub\n" +
" MODIFIER_LIST:PsiModifierListStub[mask=4096]\n");
}
});
}
public void testSOEProof() {
final StringBuilder sb = new StringBuilder();
final SecureRandom random = new SecureRandom();
@@ -19,10 +19,10 @@ import org.jetbrains.annotations.NotNull;
public interface PsiScopedLocalVariable extends PsiLocalVariable {
/**
* Returns the element (method, "for" statement or try block) in which the variable is declared.
* Returns the element or elements (method, "for" statement or try block) in which the variable is declared.
*
* @return the declaration scope for the variable.
*/
@NotNull
PsiElement getDeclarationScope();
PsiElement[] getDeclarationScope();
}