/// <summary> /// A user defined function parameter was never referenced. /// </summary> /// <param name="location">The location in the source code of the parameter that was never referenced.</param> /// <param name="parameter">The variable declaration node of the un-referenced function parameter.</param> /// <param name="inFunction">The signature of the function in which the parameter exists.</param> public virtual void FunctionParameterNeverUsed(LSLSourceCodeRange location, ILSLVariableDeclarationNode parameter, ILSLFunctionSignature inFunction) { OnWarning(location, string.Format("Parameter \"{0}\" was never used in function \"{1}\".", parameter.Name, inFunction.Name)); }
/// <summary> /// Determines if two function signatures match exactly (including return type), parameter names do not matter but /// parameter types and variadic parameter status do. /// </summary> /// <param name="left">The first function signature in the comparison.</param> /// <param name="right">The other function signature in the comparison.</param> /// <returns>True if the two signatures are identical</returns> /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is <c>null</c>.</exception> public static bool SignaturesEquivalent(ILSLFunctionSignature left, ILSLFunctionSignature right) { if (left == null) { throw new ArgumentNullException("left"); } if (right == null) { throw new ArgumentNullException("right"); } if (left.ReturnType != right.ReturnType) { return(false); } if (left.Name != right.Name) { return(false); } if (left.ParameterCount != right.ParameterCount) { return(false); } for (var i = 0; i < left.ParameterCount; i++) { var l = left.Parameters[i]; var r = right.Parameters[i]; if (l.Type != r.Type || l.Variadic != r.Variadic) { return(false); } } return(true); }
/// <summary> /// A local variable name inside of a user defined function hides the definition of one of the functions parameters. /// </summary> /// <param name="location">The location in source code of the local variable that hides the function parameter.</param> /// <param name="functionSignature">The signature of the function in which the local variable is defined.</param> /// <param name="localVariable">The variable declaration node of the local variable that hides the parameter.</param> /// <param name="parameter">The parameter node of the parameter that was hidden.</param> public virtual void LocalVariableHidesParameter(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature, ILSLVariableDeclarationNode localVariable, ILSLParameterNode parameter) { OnWarning(location, string.Format("Local variable \"{0}\" in function \"{1}\" hides parameter \"{2}\".", localVariable.Name, functionSignature.Name, parameter.Name)); }
void ILSLSyntaxWarningListener.FunctionParameterNeverUsed(LSLSourceCodeRange location, ILSLVariableDeclarationNode parameter, ILSLFunctionSignature inFunction) { _warningActionQueue.Enqueue(location.StartIndex, () => SyntaxWarningListener.FunctionParameterNeverUsed(location, parameter, inFunction)); }
void ILSLSyntaxWarningListener.UseOfDeprecatedLibraryFunction(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature) { _warningActionQueue.Enqueue(location.StartIndex, () => SyntaxWarningListener.UseOfDeprecatedLibraryFunction(location, functionSignature)); }
/// <summary> /// A library function that was marked as being deprecated was used. /// </summary> /// <param name="location">The location in source code where the deprecated function was called.</param> /// <param name="functionSignature">The function signature of the deprecated library function that was called.</param> public virtual void UseOfDeprecatedLibraryFunction(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature) { OnWarning(location, string.Format( "The library function \"{0}\" is deprecated, it is recommended you use an alternative or remove it.", functionSignature.Name)); }
/// <summary> /// A user defined local variable was never referenced. /// </summary> /// <param name="location">The location in the source code of the local variable that was never referenced.</param> /// <param name="variable">The variable declaration node of the un-referenced local variable.</param> /// <param name="inFunction">The signature of the function in which the local variable exists.</param> public virtual void LocalVariableNeverUsed(LSLSourceCodeRange location, ILSLVariableDeclarationNode variable, ILSLFunctionSignature inFunction) { const string msg = "Local variable \"{0}\" was never used in function \"{1}\"."; OnWarning(location, string.Format(msg, variable.Name, inFunction.Name)); }
void ILSLSyntaxWarningListener.LocalVariableHidesParameter(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature, ILSLVariableDeclarationNode localVariable, ILSLParameterNode parameter) { _warningActionQueue.Enqueue(location.StartIndex, () => SyntaxWarningListener.LocalVariableHidesParameter(location, functionSignature, localVariable, parameter)); }
void ILSLSyntaxErrorListener.TypeMismatchInReturnValue(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature, ILSLReadOnlyExprNode attemptedReturnExpression) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.TypeMismatchInReturnValue(location, functionSignature, attemptedReturnExpression)); }
void ILSLSyntaxErrorListener.ParameterTypeMismatchInFunctionCall(LSLSourceCodeRange location, int parameterIndexWithError, ILSLFunctionSignature calledFunction, ILSLReadOnlyExprNode[] parameterExpressionsGiven) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.ParameterTypeMismatchInFunctionCall(location, parameterIndexWithError, calledFunction, parameterExpressionsGiven)); }
void ILSLSyntaxWarningListener.LocalVariableHidesGlobalVariable(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature, ILSLVariableDeclarationNode localVariable, ILSLVariableDeclarationNode globalVariable) { _warningActionQueue.Enqueue(location.StartIndex, () => SyntaxWarningListener.LocalVariableHidesGlobalVariable(location, functionSignature, localVariable, globalVariable)); }
/// <summary> /// Determines if two function signatures match exactly (including return type), parameter names do not matter but /// parameter types do. /// </summary> /// <param name="otherSignature">The other function signature to compare to</param> /// <returns>True if the two signatures are identical</returns> /// <exception cref="ArgumentNullException"><paramref name="otherSignature"/> is <c>null</c>.</exception> public bool SignatureEquivalent(ILSLFunctionSignature otherSignature) { if (otherSignature == null) { throw new ArgumentNullException("otherSignature"); } return(LSLFunctionSignatureMatcher.SignaturesEquivalent(this, otherSignature)); }
void ILSLSyntaxWarningListener.VariableRedeclaredInInnerScope(LSLSourceCodeRange location, ILSLFunctionSignature currentFunctionBodySignature, ILSLVariableDeclarationNode newDeclarationNode, ILSLVariableDeclarationNode previousDeclarationNode) { _warningActionQueue.Enqueue(location.StartIndex, () => SyntaxWarningListener.VariableRedeclaredInInnerScope(location, currentFunctionBodySignature, newDeclarationNode, previousDeclarationNode)); }
void ILSLSyntaxErrorListener.ImproperParameterCountInFunctionCall(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature, ILSLReadOnlyExprNode[] parameterExpressionsGiven) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.ImproperParameterCountInFunctionCall(location, functionSignature, parameterExpressionsGiven)); }
/// <summary> /// A local variable was re-declared inside of a nested scope, such as an if statement or for loop, ect... <para/> /// This is not an error, but bad practice. This function handles the warning case inside function declarations. /// </summary> /// <param name="location">The source code range of the new variable declaration.</param> /// <param name="currentFunctionBodySignature">The signature of the function the new variable was declared in.</param> /// <param name="newDeclarationNode">The tree node of the new declaration that has not been added to the tree yet.</param> /// <param name="previousDeclarationNode"> /// The previous variable declaration node which already exist in the syntax tree, in /// an outer scope. /// </param> public virtual void VariableRedeclaredInInnerScope(LSLSourceCodeRange location, ILSLFunctionSignature currentFunctionBodySignature, ILSLVariableDeclarationNode newDeclarationNode, ILSLVariableDeclarationNode previousDeclarationNode) { OnWarning(location, string.Format( "Local variable \"{0}\" in function \"{1}\" hides a previous declaration in an outer scope (on line {2}).", newDeclarationNode.Name, currentFunctionBodySignature.Name, MapLineNumber(previousDeclarationNode.SourceRange.LineStart))); }
/// <summary> /// A local variable inside of a user defined function hides the definition of a user defined global variable. /// </summary> /// <param name="location">The location in source code of the local variable that hides the global variable.</param> /// <param name="functionSignature">The signature of the function in which the local variable is defined.</param> /// <param name="localVariable">The variable declaration node of the local variable that hides the global variable.</param> /// <param name="globalVariable">The variable declaration node of the user defined global variable that was hidden.</param> public virtual void LocalVariableHidesGlobalVariable(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature, ILSLVariableDeclarationNode localVariable, ILSLVariableDeclarationNode globalVariable) { OnWarning(location, string.Format( "Local variable \"{0}\" in function \"{1}\" hides global variable \"{2}\" defined on line {3}.", localVariable.Name, functionSignature.Name, globalVariable.Name, MapLineNumber(globalVariable.SourceRange.LineStart))); }
/// <summary> /// Construct an <see cref="LSLFunctionSignature" /> by cloning another <see cref="LSLFunctionSignature" /> object. /// </summary> /// <param name="other">The <see cref="LSLFunctionSignature" /> object to copy construct from.</param> /// <exception cref="ArgumentNullException"><paramref name="other" /> is <c>null</c>.</exception> public LSLFunctionSignature(ILSLFunctionSignature other) { if (other == null) { throw new ArgumentNullException("other"); } Name = other.Name; _parameters = new GenericArray <LSLParameterSignature>(other.Parameters); ReturnType = other.ReturnType; HasVariadicParameter = other.HasVariadicParameter; VariadicParameterIndex = other.VariadicParameterIndex; }
/// <summary> /// Dead code was detected, but it was not an error because it was inside a function with a void return type. /// </summary> /// <param name="location">The location in the source code.</param> /// <param name="currentFunction">The signature of the function that dead code was detected in.</param> /// <param name="deadSegment">An object describing the range of code that is considered to be dead.</param> public virtual void DeadCodeDetected(LSLSourceCodeRange location, ILSLFunctionSignature currentFunction, ILSLDeadCodeSegment deadSegment) { if (deadSegment.SourceRange.IsSingleLine) { OnWarning(location, "Unreachable code detected in function \"" + currentFunction.Name + "\"."); } else { OnWarning(location, string.Format( "Unreachable code detected in function \"" + currentFunction.Name + "\" between lines {0} and {1}.", MapLineNumber(deadSegment.SourceRange.LineStart), MapLineNumber(deadSegment.SourceRange.LineEnd))); } }
/// <summary> /// Determines if a two LSLFunctionSignatures are duplicate definitions of each other. /// <para> /// The logic behind this is a bit different than <see cref="SignaturesEquivalent" />. /// If the given function signatures have the same name, differing return types and no parameters; than this /// function will return true /// and <see cref="SignaturesEquivalent" /> will not. /// If the given function signatures have differing return types, and the exact same parameter types/count; than /// this function will return true /// and <see cref="SignaturesEquivalent" /> will not. /// </para> /// </summary> /// <param name="left">The first function signature in the comparison.</param> /// <param name="right">The other function signature in the comparison.</param> /// <returns> /// True if the two signatures are duplicate definitions of each other, taking static overloading ambiguities into /// account. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is <c>null</c>.</exception> public static bool DefinitionIsDuplicate(ILSLFunctionSignature left, ILSLFunctionSignature right) { if (left == null) { throw new ArgumentNullException("left"); } if (right == null) { throw new ArgumentNullException("right"); } //Cannot be duplicates of each other if the name is different if (left.Name != right.Name) { return(false); } //Both functions have no parameters and the same name, they are duplicate definitions of each other. if (left.ParameterCount == right.ParameterCount && left.ParameterCount == 0) { return(true); } //we don't care about the return type, it does not make a function definition unique, it does not participate in overload resolution. //simple case, these functions cannot be a duplicate definition if they have a different parameter count. if (left.ParameterCount != right.ParameterCount) { return(false); } for (var i = 0; i < left.ParameterCount; i++) { //check all the parameters have identical specifications. //IE, type and variadic status. var l = left.Parameters[i]; var r = right.Parameters[i]; if (l.Type != r.Type || l.Variadic != r.Variadic) { //nope, there was a mismatch. return(false); } } //everything matched up, the return type was ignored, it does not matter. return(true); }
/// <summary> /// Construct an <see cref="LSLFunctionCallNode" /> with an arguments list. /// This represents a call to a library function, since it has no definition node. /// </summary> /// <param name="functionSignature">The signature of the library function.</param> /// <param name="argumentList">The argument list node.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="functionSignature" /> or <paramref name="argumentList" /> is /// <c>null</c>. /// </exception> public LSLFunctionCallNode(ILSLFunctionSignature functionSignature, LSLExpressionListNode argumentList) { if (functionSignature == null) { throw new ArgumentNullException("functionSignature"); } if (argumentList == null) { throw new ArgumentNullException("argumentList"); } Signature = new LSLFunctionSignature(functionSignature); Name = functionSignature.Name; ArgumentExpressionList = argumentList; ArgumentExpressionList.Parent = this; _libraryFunction = true; }
/// <exception cref="ArgumentNullException"> /// <paramref name="context" /> or <paramref name="signature" /> or /// <paramref name="argumentExpressionList" /> is <c>null</c>. /// </exception> internal LSLFunctionCallNode( LSLParser.Expr_FunctionCallContext context, ILSLFunctionSignature signature, LSLExpressionListNode argumentExpressionList) { if (context == null) { throw new ArgumentNullException("context"); } if (signature == null) { throw new ArgumentNullException("signature"); } if (argumentExpressionList == null) { throw new ArgumentNullException("argumentExpressionList"); } Signature = signature; Name = context.function_name.Text; _libraryFunction = true; ArgumentExpressionList = argumentExpressionList; argumentExpressionList.Parent = this; SourceRange = new LSLSourceCodeRange(context); SourceRangeOpenParenth = new LSLSourceCodeRange(context.open_parenth); SourceRangeCloseParenth = new LSLSourceCodeRange(context.close_parenth); SourceRangeName = new LSLSourceCodeRange(context.function_name); SourceRangesAvailable = true; }
/// <summary> /// Check if a given function signature can be called with the given expressions as parameters /// </summary> /// <param name="expressionValidator"> /// The expression validator, which is used to determine if an expression can be passed /// into a parameter of a certain type. /// </param> /// <param name="functionSignature">The function signature of the functions your passing the parameter expressions to.</param> /// <param name="expressions">The expressions we want to test against this function signatures defined parameters.</param> /// <returns> /// A <see cref="LSLFunctionSignatureMatch"/> object containing information about how the parameters matched /// or did not match the call signature. /// </returns> public static LSLFunctionSignatureMatch TryMatch(ILSLFunctionSignature functionSignature, IReadOnlyGenericArray <ILSLReadOnlyExprNode> expressions, ILSLExpressionValidator expressionValidator) { return(TryMatch(functionSignature, expressions, (expressionValidator.ValidateFunctionParameter))); }
/// <summary> /// Determines if a given <see cref="LSLFunctionSignature" /> is a duplicate definition of this function signature. <para/> /// The logic behind this is a bit different than SignatureMatches(). <para/> /// If the given function signature has the same name, a differing return type and both functions have no parameters; /// than this function will return true /// and <see cref="ILSLFunctionSignature.SignatureEquivalent" /> will not. <para/> /// If the other signature is an overload that is ambiguous in all cases due to variadic parameters, this function /// returns true. /// </summary> /// <remarks> /// </remarks> /// <param name="otherSignature">The other function signature to compare to</param> /// <returns> /// True if the two signatures are duplicate definitions of each other, taking static overloading ambiguities into /// account. /// </returns> public bool DefinitionIsDuplicate(ILSLFunctionSignature otherSignature) { return(LSLFunctionSignatureMatcher.DefinitionIsDuplicate(this, otherSignature)); }
void ILSLSyntaxWarningListener.DeadCodeDetected(LSLSourceCodeRange location, ILSLFunctionSignature currentFunction, ILSLDeadCodeSegment deadSegment) { _warningActionQueue.Enqueue(location.StartIndex, () => SyntaxWarningListener.DeadCodeDetected(location, currentFunction, deadSegment)); }
void ILSLSyntaxErrorListener.NotAllCodePathsReturnAValue(LSLSourceCodeRange location, ILSLFunctionSignature inFunction) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.NotAllCodePathsReturnAValue(location, inFunction)); }
void ILSLSyntaxErrorListener.DeadCodeAfterReturnPath(LSLSourceCodeRange location, ILSLFunctionSignature inFunction, ILSLDeadCodeSegment deadSegment) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.DeadCodeAfterReturnPath(location, inFunction, deadSegment)); }
void ILSLSyntaxErrorListener.RedefinedFunction(LSLSourceCodeRange location, ILSLFunctionSignature previouslyDefinedSignature) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.RedefinedFunction(location, previouslyDefinedSignature)); }
/// <summary> /// Construct an <see cref="LSLFunctionCallNode" /> with an arguments list. /// This represents a call to a library function, since it has no definition node. /// </summary> /// <param name="functionSignature">The signature of the library function.</param> /// <param name="argumentList">The list of expression arguments.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="functionSignature" /> or <paramref name="argumentList" /> is /// <c>null</c>. /// </exception> public LSLFunctionCallNode(ILSLFunctionSignature functionSignature, params ILSLExprNode[] argumentList) : this(functionSignature, new LSLExpressionListNode(argumentList)) { }
void ILSLSyntaxErrorListener.ReturnedVoidFromNonVoidFunction(LSLSourceCodeRange location, ILSLFunctionSignature functionSignature) { _errorActionQueue.Enqueue(location.StartIndex, () => SyntaxErrorListener.ReturnedVoidFromNonVoidFunction(location, functionSignature)); }
/// <summary> /// Check if a given function signature can be called with the given expressions as parameters /// </summary> /// <param name="typeComparer">A function which should return true if two types match</param> /// <param name="functionSignature">The function signature of the functions your passing the parameter expressions to.</param> /// <param name="expressions">The expressions we want to test against this function signatures defined parameters.</param> /// <returns> /// A LSLFunctionCallSignatureMatcher.MatchStatus object containing information about how the parameters matched /// or did not match the call signature. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="functionSignature"/> or <paramref name="expressions"/> or <paramref name="typeComparer"/> is <c>null</c>.</exception> public static LSLFunctionSignatureMatch TryMatch(ILSLFunctionSignature functionSignature, IReadOnlyGenericArray <ILSLReadOnlyExprNode> expressions, Func <LSLParameterSignature, ILSLReadOnlyExprNode, bool> typeComparer) { if (functionSignature == null) { throw new ArgumentNullException("functionSignature"); } if (expressions == null) { throw new ArgumentNullException("expressions"); } if (typeComparer == null) { throw new ArgumentNullException("typeComparer"); } int parameterNumber = 0; bool parameterTypeMismatch = false; //if we supplied to many parameters, and there is not a variadic //parameter at the end of the signature, then there is not a match if (functionSignature.HasVariadicParameter == false && expressions.Count > functionSignature.ParameterCount) { return(new LSLFunctionSignatureMatch(false, true, false, -1)); } //not enough parameters to fill all of the concrete (non variadic) parameters in //we do not have enough expressions to call this function signature if (expressions.Count < functionSignature.ConcreteParameterCount) { return(new LSLFunctionSignatureMatch(true, false, false, -1)); } //check the types of all parameters match, including variadic parameters from the signature if they are not Void //if the variadic parameter is Void than anything can go in it, so it is not even checked for (; parameterNumber < expressions.Count; parameterNumber++) { LSLParameterSignature compareWithThisSignatureParameter; if (parameterNumber > (functionSignature.ParameterCount - 1)) { //If this happens it means we are in a continuation of a variadic parameter, we want to continue comparing the rest of the passed //expressions to the last parameter in the function signature, IE. the variadic parameter. compareWithThisSignatureParameter = functionSignature.Parameters[functionSignature.ParameterCount - 1]; } else { //We have not flowed over the parameter count of the signature, so theres no danger //of an out of bounds index on the parameters array in the signature. compareWithThisSignatureParameter = functionSignature.Parameters[parameterNumber]; } //no type check required, the variadic parameter allows everything in because its type is Void, anything you put in is a match //from here on out. So its safe to return from the loop now and stop checking parameters. if (compareWithThisSignatureParameter.Variadic && compareWithThisSignatureParameter.Type == LSLType.Void) { break; } //use the type comparer to check for a match, there might be some special case like string literals //being passed into a Key parameter, this behavior is delegated for better re-usability if (typeComparer(compareWithThisSignatureParameter, expressions[parameterNumber])) { continue; } //the expression could not be passed into the parameter due to a type mismatch, we are done checking the parameters //because we know for a fact the expressions given do not match this call signature parameterTypeMismatch = true; break; } //if there was a parameter mismatch, the last checked parameter index is the index at which the mismatch occurred var badParameterIndex = parameterTypeMismatch ? parameterNumber : -1; //we had an allowable amount of parameters, but there was a type mismatch somewhere return(new LSLFunctionSignatureMatch(false, false, parameterTypeMismatch, badParameterIndex)); }