| /******************************************************************************* |
| * 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(); |
| } |
| } |