/******************************************************************************* * Copyright © 2011, 2013 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.edt.compiler.internal.core.validation.statement; import org.eclipse.edt.compiler.binding.FieldAccessValidationRule; import org.eclipse.edt.compiler.binding.IValidationProxy; import org.eclipse.edt.compiler.core.ast.AbstractASTVisitor; import org.eclipse.edt.compiler.core.ast.Expression; import org.eclipse.edt.compiler.core.ast.Name; import org.eclipse.edt.compiler.core.ast.QualifiedName; import org.eclipse.edt.compiler.core.ast.SimpleName; import org.eclipse.edt.compiler.internal.core.builder.IProblemRequestor; import org.eclipse.edt.compiler.internal.core.lookup.ICompilerOptions; import org.eclipse.edt.compiler.internal.core.validation.annotation.AnnotationValidator; import org.eclipse.edt.mof.egl.Annotation; import org.eclipse.edt.mof.egl.ConstantField; import org.eclipse.edt.mof.egl.FunctionMember; import org.eclipse.edt.mof.egl.FunctionParameter; import org.eclipse.edt.mof.egl.Member; import org.eclipse.edt.mof.egl.utils.TypeUtils; public class LValueValidator { private IProblemRequestor problemRequestor; private ICompilerOptions compilerOptions; private Member member; private Expression lValue; private ILValueValidationRules validationRules; public static interface ILValueValidationRules { boolean canAssignToConstantVariables(); boolean canAssignToReadOnlyVariables(); boolean canAssignToFunctionReferences(); boolean canAssignToFunctionParmConst(); boolean shouldRunAccessRules(); } public static class DefaultLValueValidationRules implements ILValueValidationRules { @Override public boolean canAssignToConstantVariables() { return false; } @Override public boolean canAssignToReadOnlyVariables() { return false; } @Override public boolean canAssignToFunctionReferences() { return false; } @Override public boolean canAssignToFunctionParmConst() { return false; } @Override public boolean shouldRunAccessRules() { return true; } } public LValueValidator(IProblemRequestor problemRequestor, ICompilerOptions compilerOptions, Member member, Expression lValue) { this(problemRequestor, compilerOptions, member, lValue, new DefaultLValueValidationRules()); } public LValueValidator(IProblemRequestor problemRequestor, ICompilerOptions compilerOptions, Member member, Expression lValue, ILValueValidationRules validationRules) { this.problemRequestor = problemRequestor; this.member = member; this.lValue = lValue; this.validationRules = validationRules; this.compilerOptions = compilerOptions; } private boolean invokeFieldAccessValidators() { boolean result = true; if (member == null) { return result; } for (Annotation annot : member.getAnnotations()) { IValidationProxy proxy = AnnotationValidator.getValidationProxy(annot); if (proxy != null) { for (FieldAccessValidationRule rule : proxy.getFieldAccessValidators()) { result = rule.validateLValue(lValue, member, problemRequestor, compilerOptions) && result; } } } return result; } public boolean validate() { boolean result = true; if (validationRules.shouldRunAccessRules()) { //Run field access rules defined by annotations on the field result = invokeFieldAccessValidators(); } Name constName = findConstName(lValue); Member constMember = constName == null ? null : constName.resolveMember(); if (constMember != null) { boolean canAssignToConst = constMember instanceof FunctionParameter ? validationRules.canAssignToFunctionParmConst() : validationRules.canAssignToConstantVariables(); if (!canAssignToConst) { // No part of the field can be modified for value types. For reference types only the declaration itself cannot be modified. if (constName == lValue || (constMember.getType() != null && TypeUtils.isValueType(constMember.getType()))) { problemRequestor.acceptProblem( lValue, IProblemRequestor.CANNOT_MODIFY_CONSTANT, new String[] {member.getCaseSensitiveName()}); result = false; } } } if (member instanceof FunctionMember) { if (!validationRules.canAssignToFunctionReferences()) { problemRequestor.acceptProblem( lValue, IProblemRequestor.FUNCTION_NOT_VALID_AS_LVALUE, new String[] {member.getCaseSensitiveName()}); result = false; } } return result; } public static Name findConstName(Expression e) { if (e == null) { return null; } final Name[] value = new Name[1]; e.accept(new AbstractASTVisitor() { @Override public boolean visit(SimpleName simpleName) { Member m = simpleName.resolveMember(); if (m instanceof ConstantField || (m instanceof FunctionParameter && ((FunctionParameter)m).isConst())) { value[0] = simpleName; } return false; }; @Override public boolean visit(QualifiedName qualifiedName) { Member m = qualifiedName.resolveMember(); if (m instanceof ConstantField || (m instanceof FunctionParameter && ((FunctionParameter)m).isConst())) { value[0] = qualifiedName; return false; } return true; }; }); return value[0]; } }