blob: c8335fd0a2d6c6f3ad99ccda6fe6f38952ac3aa2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.code;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
class ConstantChecks {
private static abstract class ExpressionChecker extends ASTVisitor {
private final IExpressionFragment fExpression;
protected boolean fResult= true;
public ExpressionChecker(IExpressionFragment ex) {
fExpression= ex;
}
public boolean check() {
fResult= true;
fExpression.getAssociatedNode().accept(this);
return fResult;
}
}
private static class LoadTimeConstantChecker extends ExpressionChecker {
public LoadTimeConstantChecker(IExpressionFragment ex) {
super(ex);
}
@Override
public boolean visit(SuperFieldAccess node) {
fResult= false;
return false;
}
@Override
public boolean visit(SuperMethodInvocation node) {
fResult= false;
return false;
}
@Override
public boolean visit(ThisExpression node) {
fResult= false;
return false;
}
@Override
public boolean visit(FieldAccess node) {
fResult&= new LoadTimeConstantChecker((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(node.getExpression())).check();
return false;
}
@Override
public boolean visit(MethodInvocation node) {
if(node.getExpression() == null) {
visitName(node.getName());
} else {
fResult&= new LoadTimeConstantChecker((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(node.getExpression())).check();
}
return false;
}
@Override
public boolean visit(QualifiedName node) {
return visitName(node);
}
@Override
public boolean visit(SimpleName node) {
return visitName(node);
}
private boolean visitName(Name name) {
fResult&= checkName(name);
return false; //Do not descend further
}
private boolean checkName(Name name) {
IBinding binding= name.resolveBinding();
if (binding == null)
return true; /* If the binding is null because of compile errors etc.,
scenarios which may have been deemed unacceptable in
the presence of semantic information will be admitted. */
// If name represents a member:
if (binding instanceof IVariableBinding || binding instanceof IMethodBinding)
return isMemberReferenceValidInClassInitialization(name);
else if (binding instanceof ITypeBinding)
return ! ((ITypeBinding) binding).isTypeVariable();
else {
/* IPackageBinding is not expected, as a package name not
used as a type name prefix is not expected in such an
expression. Other types are not expected either.
*/
Assert.isTrue(false);
return true;
}
}
private boolean isMemberReferenceValidInClassInitialization(Name name) {
IBinding binding= name.resolveBinding();
Assert.isTrue(binding instanceof IVariableBinding || binding instanceof IMethodBinding);
if(name instanceof SimpleName)
return Modifier.isStatic(binding.getModifiers());
else {
Assert.isTrue(name instanceof QualifiedName);
return checkName(((QualifiedName) name).getQualifier());
}
}
}
private static class StaticFinalConstantChecker extends ExpressionChecker {
public StaticFinalConstantChecker(IExpressionFragment ex) {
super(ex);
}
@Override
public boolean visit(SuperFieldAccess node) {
fResult= false;
return false;
}
@Override
public boolean visit(SuperMethodInvocation node) {
fResult= false;
return false;
}
@Override
public boolean visit(ThisExpression node) {
fResult= false;
return false;
}
@Override
public boolean visit(QualifiedName node) {
return visitName(node);
}
@Override
public boolean visit(SimpleName node) {
return visitName(node);
}
private boolean visitName(Name name) {
IBinding binding= name.resolveBinding();
if(binding == null) {
/* If the binding is null because of compile errors etc.,
scenarios which may have been deemed unacceptable in
the presence of semantic information will be admitted.
Descend deeper.
*/
return true;
}
int modifiers= binding.getModifiers();
if(binding instanceof IVariableBinding) {
if (!(Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers))) {
fResult= false;
return false;
}
} else if(binding instanceof IMethodBinding) {
if (!Modifier.isStatic(modifiers)) {
fResult= false;
return false;
}
} else if(binding instanceof ITypeBinding) {
return false; // It's o.k. Don't descend deeper.
} else {
/* IPackageBinding is not expected, as a package name not
used as a type name prefix is not expected in such an
expression. Other types are not expected either.
*/
Assert.isTrue(false);
return false;
}
//Descend deeper:
return true;
}
}
public static boolean isStaticFinalConstant(IExpressionFragment ex) {
return new StaticFinalConstantChecker(ex).check();
}
public static boolean isLoadTimeConstant(IExpressionFragment ex) {
return new LoadTimeConstantChecker(ex).check();
}
}