Skip to content

Commit

Permalink
Fix for issue #366: check static compatibility when inferring expression
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Nov 4, 2017
1 parent c6e27d1 commit dce1711
Showing 6 changed files with 112 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -472,6 +472,22 @@ public void testClosure10() {
assertDeclaration(contents, start, end, "java.lang.Object", "equals", DeclarationKind.METHOD);
}

@Test
public void testClosure11() {
String contents =
"class A {\n" +
" String b\n" +
" static void main(args) {\n" +
" def c = {\n" +
" b\n" + // unknown because enclosing declaration is static
" }\n" +
" }\n" +
"}";

int offset = contents.lastIndexOf('b');
assertUnknownConfidence(contents, offset, offset + 1, "A", false);
}

@Test
public void testSpread1() {
String contents = "def z = [1,2]*.value";
Original file line number Diff line number Diff line change
@@ -476,7 +476,7 @@ protected ASTNode findDeclarationForDynamicVariable(VariableExpression var, Clas
}
}
if (candidate == null && resolveStrategy < Closure.DELEGATE_ONLY) {
candidate = findDeclaration(var.getName(), owner, isLhsExpr, isOwnerStatic(scope), callArgs);
candidate = findDeclaration(var.getName(), owner, isLhsExpr, scope.isOwnerStatic(), callArgs);
if (candidate == null && resolveStrategy < Closure.OWNER_FIRST) {
candidate = findDeclaration(var.getName(), scope.getDelegate(), isLhsExpr, false, callArgs);
}
@@ -524,14 +524,14 @@ protected ASTNode findDeclaration(String name, ClassNode declaringType, boolean
// look for property
for (ClassNode type : typeHierarchy) {
PropertyNode property = type.getProperty(name);
if (property != null) {
if (isCompatible(property, isStaticExpression)) {
return property;
}
}

// look for field
FieldNode field = declaringType.getField(name);
if (field != null) {
if (isCompatible(field, isStaticExpression)) {
return field;
}

@@ -550,7 +550,7 @@ protected ASTNode findDeclaration(String name, ClassNode declaringType, boolean
}

// look for static or synthetic accessor
if (accessor != null) {
if (isCompatible(accessor, isStaticExpression)) {
return accessor;
}

@@ -736,15 +736,21 @@ protected static ClassNode getDeclaringTypeFromDeclaration(ASTNode declaration,
}
}

protected static boolean isOwnerStatic(VariableScope scope) {
AnnotatedNode enclosing;
boolean isOwnerStatic = false;
if ((enclosing = scope.getEnclosingMethodDeclaration()) != null) {
isOwnerStatic = ((MethodNode) enclosing).isStatic();
} else if ((enclosing = scope.getEnclosingFieldDeclaration()) != null) {
isOwnerStatic = ( (FieldNode) enclosing).isStatic();
protected static boolean isCompatible(AnnotatedNode declaration, boolean isStaticExpression) {
if (declaration != null) {
boolean isStatic = false;
if (declaration instanceof FieldNode) {
isStatic = ((FieldNode) declaration).isStatic();
} else if (declaration instanceof MethodNode) {
isStatic = ((MethodNode) declaration).isStatic();
} else if (declaration instanceof PropertyNode) {
isStatic = ((PropertyNode) declaration).isStatic();
}
if (!isStaticExpression || isStatic || declaration.getDeclaringClass().equals(VariableScope.CLASS_CLASS_NODE)) {
return true;
}
}
return isOwnerStatic;
return false;
}

/**
Original file line number Diff line number Diff line change
@@ -367,17 +367,17 @@ public void visitCompilationUnit(ITypeRequestor requestor) {
}

public void visitJDT(IType type, ITypeRequestor requestor) {
IJavaElement oldEnclosing = enclosingElement;
ASTNode oldEnclosingNode = enclosingDeclarationNode;
enclosingElement = type;
ClassNode node = findClassNode(createName(type));
if (node == null) {
// probably some sort of AST transformation is making this node invisible
return;
}
scopes.add(new VariableScope(scopes.getLast(), node, false));
ASTNode enclosingDeclaration0 = enclosingDeclarationNode;
IJavaElement enclosingElement0 = enclosingElement;
enclosingDeclarationNode = node;
enclosingElement = type;
try {
scopes.add(new VariableScope(scopes.getLast(), node, false));
enclosingDeclarationNode = node;
visitClassInternal(node);

try {
@@ -400,7 +400,7 @@ public void visitJDT(IType type, ITypeRequestor requestor) {
// visit fields created by @Field
for (FieldNode field : node.getFields()) {
if (field.getEnd() > 0) {
visitField(field);
visitFieldInternal(field);
}
}
} else {
@@ -409,14 +409,14 @@ public void visitJDT(IType type, ITypeRequestor requestor) {
List<FieldNode> traitFields = (List<FieldNode>) node.getNodeMetaData("trait.fields");
if (traitFields != null) {
for (FieldNode field : traitFields) {
visitField(field);
visitFieldInternal(field);
}
}
@SuppressWarnings("unchecked")
List<MethodNode> traitMethods = (List<MethodNode>) node.getNodeMetaData("trait.methods");
if (traitMethods != null) {
for (MethodNode method : traitMethods) {
visitConstructorOrMethod(method, false);
visitConstructorOrMethodInternal(method, false);
}
}
}
@@ -426,15 +426,22 @@ public void visitJDT(IType type, ITypeRequestor requestor) {
if (!type.getMethod(type.getElementName(), NO_PARAMS).exists()) {
ConstructorNode defConstructor = findDefaultConstructor(node);
if (defConstructor != null) {
visitConstructorOrMethod(defConstructor, true);
visitConstructorOrMethodInternal(defConstructor, true);
}
}
}

// visit relocated @Memoized method bodies
for (MethodNode method : node.getMethods()) {
if (method.getName().startsWith("memoizedMethodPriv$")) {
visitClassCodeContainer(method.getCode());
scopes.add(new VariableScope(scopes.getLast(), method, method.isStatic()));
enclosingDeclarationNode = method;
try {
visitClassCodeContainer(method.getCode());
} finally {
scopes.removeLast();
enclosingDeclarationNode = node;
}
}
}

@@ -446,9 +453,9 @@ public void visitJDT(IType type, ITypeRequestor requestor) {
throw vc;
}
} finally {
enclosingElement = oldEnclosing;
enclosingDeclarationNode = oldEnclosingNode;
scopes.removeLast();
enclosingElement = enclosingElement0;
enclosingDeclarationNode = enclosingDeclaration0;
}
}

@@ -747,6 +754,30 @@ private void visitClassReference(ClassNode node) {
}
}

private void visitFieldInternal(FieldNode field) {
scopes.add(new VariableScope(scopes.getLast(), field, field.isStatic()));
ASTNode enclosingDeclarationNode0 = enclosingDeclarationNode;
enclosingDeclarationNode = field;
try {
visitField(field);
} finally {
scopes.removeLast();
enclosingDeclarationNode = enclosingDeclarationNode0;
}
}

private void visitConstructorOrMethodInternal(MethodNode method, boolean isCtor) {
scopes.add(new VariableScope(scopes.getLast(), method, method.isStatic()));
ASTNode enclosingDeclarationNode0 = enclosingDeclarationNode;
enclosingDeclarationNode = method;
try {
visitConstructorOrMethod(method, isCtor);
} finally {
scopes.removeLast();
enclosingDeclarationNode = enclosingDeclarationNode0;
}
}

//

@Override
Original file line number Diff line number Diff line change
@@ -515,6 +515,11 @@ public ClassNode getDelegate() {
return delegate != null ? delegate.type : null;
}

public ClassNode getDelegateOrThis() {
VariableInfo info = getDelegateOrThisInfo();
return info != null ? info.type : null;
}

/**
* @return the current delegate type if exists, or this type if exists, or
* Object. Returns null if in top level scope (i.e. in import statement).
@@ -530,9 +535,14 @@ public VariableInfo getDelegateOrThisInfo() {
return info;
}

public ClassNode getDelegateOrThis() {
VariableInfo info = getDelegateOrThisInfo();
return info != null ? info.type : null;
public boolean isOwnerStatic() {
FieldNode field; MethodNode method;
if (isStatic() ||
((field = getEnclosingFieldDeclaration()) != null && field.isStatic()) ||
((method = getEnclosingMethodDeclaration()) != null && method.isStatic())) {
return true;
}
return false;
}

public void addVariable(String name, ClassNode type, ClassNode declaringType) {
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package p

class A {
public static def f
static def s() {
f = A.f
}
}

class B extends A {
def f
void s() {
public def f
void m() {
f = A.f
f = super.f
}
static s2() {
static def s2() {
f = A.f
}
}

class A {
static f = 7
static s() {
f = A.f
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package p

class A {
public static def g
static def s() {
g = A.g
}
}

class B extends A {
def f
void s() {
public def f
void m() {
f = A.g
f = super.g
}
static s2() {
static def s2() {
f = A.g
}
}

class A {
static g = 7
static s() {
g = A.g
}
}

0 comments on commit dce1711

Please sign in to comment.