public void CheckReadonlyNotPassedAsModifiable(MethodDescriptor methodDesc, ActualBuilder builder, ASTInvoke n) { //check for readonly params being passed as modifiable parameters. int index = 0; foreach (var actual in builder.Actuals) { if (actual.IsFromFormal && actual.IsFormalReadonly) { if (String.IsNullOrEmpty(methodDesc.Formals[index].Modifier) || !methodDesc.Formals[index].Modifier.Equals(READONLY_MODIFIER, StringComparison.OrdinalIgnoreCase)) { ReportError(n.Location, "Cannot pass readonly identifier '{0}' as a modifiable parameter to method '{1}'", actual.Name, methodDesc.Name); } } index++; } }
public void CheckActualsHaveReadonly(MethodDescriptor desc, ActualBuilder builder, ASTInvoke n) { //check that for all readonly formals the actual is being passes with a readonly modifier int index = 0; foreach (var formal in desc.Formals) { if (!String.IsNullOrEmpty(formal.Modifier) && formal.Modifier.Equals(READONLY_MODIFIER, StringComparison.OrdinalIgnoreCase)) { if (string.IsNullOrEmpty(builder.Actuals[index].Modifier) || !builder.Actuals[index].Modifier.Equals(READONLY_MODIFIER, StringComparison.OrdinalIgnoreCase)) { ReportError(n.Location, "Missing readonly declaration on method invocation - Parameter '{0}' on function '{1}' must be marked as readonly.", formal.Name, desc.Name); } } index++; } }
public override void VisitInstantiateClass(ASTInstantiateClass n) { ClassDescriptor desc = _scopeMgr.GetType(n.ClassName) as ClassDescriptor; if (desc != null) { var cls = (ClassDescriptor)_scopeMgr.Find(n.ClassName, p => p is ClassDescriptor); var func = cls.Methods.Where(prop => prop.Name.Equals(n.ClassName, StringComparison.OrdinalIgnoreCase)).SingleOrDefault().Type as TypeFunction; //Check if the class we're working with has a constructor of the same name if (func != null) { CheckSubTree(n.Actuals); //check the method signature of the constructor to make sure the correct arguments are passed in ActualBuilder builder = new ActualBuilder(); n.Actuals.Visit(builder); if (func.AcceptCall(builder.Actuals)) { //hooray, the code is valid MethodDescriptor ctorDescriptor = (MethodDescriptor)_scopeMgr.Find(n.ClassName, p => p is MethodDescriptor, func.Scope); _lastSeenType = desc.Type; n.ClassDescriptor = desc; n.Descriptor = ctorDescriptor; } else { ReportError(n.Location, "Invalid parameters for constructor '{0}'", n.ClassName); } } else { ReportError(n.Location, "No constructor found for class '{0}'.", n.ClassName); } } else { ReportError(n.Location, "The name '{0}' is not a class.", n.ClassName); } }
/// <summary> /// VisitInvoke and VisitDereferenceField are very similiar, so this should probably be refactored out /// into a common method. /// </summary> /// <param name="n"></param> public override void VisitInvoke(ASTInvoke n) { //Make sure the lvalue is a type and the method name exists CFlatType lhs = CheckSubTree(n.Object); if (lhs.IsClass) { TypeClass lvalue = (TypeClass)lhs; var descriptor = (ClassDescriptor)_scopeMgr.Find(lvalue.ClassName, p => p is ClassDescriptor); //check if a method with the given name exists in the scope. //This needs to check not only the class's shallow scope, but all the parents as well. MethodDescriptor methodDesc = _scopeMgr.Find(n.Method, d => d is MethodDescriptor, descriptor.Scope) as MethodDescriptor; //if (methodDesc != null && (descriptor.Methods.Contains(methodDesc) || methodDesc.IsCFlatMethod)) if (methodDesc != null) { if (methodDesc.Modifiers.Contains(PRIVATE_MODIFIER, StringComparer.InvariantCultureIgnoreCase)) { if (!_scopeMgr.HasSymbol(n.Method, _currentClass.Scope)) { ReportError(n.Location, "Cannot access the private method {0} in class {1} from class {2}", methodDesc.Name, methodDesc.ContainingClass.Name, _currentClass.ClassName); } } //check if the arguments match TypeFunction method = (TypeFunction)methodDesc.Type; //visit any actuals that need processing CheckSubTree(n.Actuals); //collect the actuals var curMethDesc = _scopeMgr.Find(_currentMethod.Name, d => d is MethodDescriptor) as MethodDescriptor; ActualBuilder builder = new ActualBuilder(curMethDesc); n.Actuals.Visit(builder); if (method.AcceptCall(builder.Actuals)) //if the types check { CheckActualsHaveReadonly(methodDesc, builder, n); CheckReadonlyNotPassedAsModifiable(methodDesc, builder, n); n.Descriptor = methodDesc; n.CFlatType = method.ReturnType; _lastSeenType = method.ReturnType; //check if we're processing an exit instruction, and if so, this counts as a return for the current block. if (IsExitMethod(n)) { _currentMethod.RegisterReturnStatement(); } } else { ReportError(n.Location, "Invalid parameters for method '{0}.{1}'", TypeToFriendlyName(lvalue), n.Method); } } else { ReportError(n.Location, "Method '{0}' does not exist for type '{1}'", n.Method, TypeToFriendlyName(lvalue)); } } else { ReportError(n.Location, "Type '{0}' does not support methods.", TypeToFriendlyName(lhs)); } }