Пример #1
0
        private static int CompareCallExpression(ICallExpression left, ICallExpression right)
        {
            // Standard left,right and null checks
            if (left == null && right == null)
            {
                return(0);
            }
            if (left == null)
            {
                return(1);
            }
            if (right == null)
            {
                return(-1);
            }

            var result = CompareExpression(left.Expression, right.Expression);

            if (result != 0)
            {
                return(result);
            }

            result = CompareNodeArrays(left.TypeArguments, right.TypeArguments, (l, r) => CompareNodeAsText(l, r));
            if (result != 0)
            {
                return(result);
            }

            return(CompareNodeArrays(left.Arguments, right.Arguments, (l, r) => CompareExpression(l, r)));
        }
Пример #2
0
        /// <summary>
        /// Whether the <paramref name="node"/> is an <code>importFrom(...)</code> or <code>importFile(...)</code> with the required number of arguments (i.e. with 1 argument).
        /// </summary>
        public static bool IsImportCall(
            [NotNull] this INode node,
            out ICallExpression callExpression,
            out DScriptImportFunctionKind importKind,
            out IExpression argumentAsExpression,
            out ILiteralExpression argumentAsLiteral)
        {
            Contract.Requires(node != null);

            const int parameterCount = 1;

            callExpression = node.As <ICallExpression>();
            var expressionIdentifier = callExpression?.Expression.As <IIdentifier>();

            if (
                (expressionIdentifier?.Text == Names.InlineImportFunction ||
                 expressionIdentifier?.Text == Names.InlineImportFileFunction) &&
                (callExpression.TypeArguments == null || callExpression.TypeArguments.Count == 0) &&
                callExpression.Arguments.Length >= parameterCount)
            {
                importKind = expressionIdentifier.Text == Names.InlineImportFunction
                    ? DScriptImportFunctionKind.ImportFrom
                    : DScriptImportFunctionKind.ImportFile;

                argumentAsExpression = callExpression.Arguments[0];
                argumentAsLiteral    = argumentAsExpression.As <ILiteralExpression>();

                return(true);
            }

            importKind           = DScriptImportFunctionKind.None;
            argumentAsExpression = null;
            argumentAsLiteral    = null;
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Finds the parameter that either contains this node or _is_ this node.
        /// </summary>
        /// <param name="callExpression">The containing call expression for this node</param>
        /// <param name="nodeAtPosition">The current node in the editor</param>
        /// <returns>The index of the argument (or 0 if this didn't correspond to any argument)</returns>
        public static int GetActiveParameterIndex(ICallExpression callExpression, INode nodeAtPosition)
        {
            var arguments = callExpression?.Arguments?.Elements.ToArray();

            if (arguments == null)
            {
                return(DefaultArgIndex);
            }

            // first check the top level arguments (much cheaper and also very likely)
            for (int i = 0; i < arguments.Length; ++i)
            {
                if (ReferenceEquals(arguments[i], nodeAtPosition))
                {
                    return(i);
                }
            }

            // let's try the slightly more expensive check within subfields
            for (int i = 0; i < arguments.Length; ++i)
            {
                var result = NodeWalker.ForEachChildRecursively(arguments[i], node => ReferenceEquals(node, nodeAtPosition) ? node : null);

                if (result != null)
                {
                    return(i);
                }
            }

            return(DefaultArgIndex);
        }
Пример #4
0
        internal static bool IsInlineImport(this ICallExpression callExpression)
        {
            Contract.Requires(callExpression != null);

            var identifier   = callExpression.Expression.As <IIdentifier>();
            var functionName = identifier?.Text;

            // Currently, BuildXL script support two types of inline require. One of them would be obsoleted!
            return(functionName == Names.InlineImportFunction ||
                   functionName == Names.InlineImportFileFunction);
        }
Пример #5
0
        private static bool TryCheckIsUnitTestDecorator(Logger logger, ISourceFile sourceFile, IDecorator decorator, out bool isUnitTestDecorator)
        {
            isUnitTestDecorator = false;
            var expression = decorator.Expression;

            ICallExpression callExpression = null;

            if (expression.Kind == SyntaxKind.CallExpression)
            {
                callExpression = (ICallExpression)expression;
                expression     = callExpression.Expression;
            }

            if (expression.Kind == SyntaxKind.PropertyAccessExpression)
            {
                var propertyAccess = (IPropertyAccessExpression)expression;
                expression = propertyAccess.Name;
            }

            if (expression.Kind == SyntaxKind.Identifier)
            {
                var identifier = (IIdentifier)expression;
                if (string.Equals(UnitTestName, identifier.Text, StringComparison.Ordinal))
                {
                    isUnitTestDecorator = true;
                }
                else if (string.Equals(UnitTestName, identifier.Text, StringComparison.OrdinalIgnoreCase))
                {
                    logger.LogError(sourceFile, decorator, C($"Decorator '{identifier.Text}' is using the wrong casing. Please use '{UnitTestName}'"));
                    return(false);
                }
            }

            // If this is a unit test and it came from a function call, perform some extra checks
            if (isUnitTestDecorator && callExpression != null)
            {
                if (callExpression.Arguments.Count > 0)
                {
                    logger.LogError(sourceFile, decorator, "UnitTest decorators are not allowed to have arguments");
                    return(false);
                }

                if (callExpression.TypeArguments != null && callExpression.TypeArguments.Count > 0)
                {
                    logger.LogError(sourceFile, decorator, "UnitTest decorators are not allowed to be generic");
                    return(false);
                }
            }

            return(true);
        }
Пример #6
0
        public Expression ConvertExpression(ICallExpression node, FunctionScope localScope, bool useSemanticNameResolution)
        {
            try
            {
                return(m_decoratee.ConvertExpression(node, localScope, useSemanticNameResolution));
            }
            catch (Exception e)
            {
                string sourceFragment = node.GetText().SubstringMax(0, MaxSourceLength);

                string message = "Failed to convert expression.\r\n" + sourceFragment;
                throw new ConversionException(message, e);
            }
        }
Пример #7
0
        private void AnalyzeModuleFromImportFrom(ICallExpression node, bool saveIdentifierOnStack = false)
        {
            var moduleName = GetModuleNameFromImportFrom(node);

            if (!string.IsNullOrEmpty(moduleName))
            {
                string fullNameString = string.Concat(Names.InlineImportFunction, ".", moduleName);

                if (saveIdentifierOnStack)
                {
                    m_currentLocationStack.Push(fullNameString);
                }
                else
                {
                    AddOrCreateInteractionSymbol(SymbolKind.ImportedModule, fullNameString);
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Return true iff callExpression is a call to 'config' ('configure' as well for compat reasons), 'package' or 'qualifierSpace' the only allowed top-level function calls.
        /// </summary>
        private static bool IsAllowedTopLevelFunctionCall(ICallExpression callExpression)
        {
            // Call expression should be at the top level to be considered valid.
            // Namespace level calls to predefine functions are invalid.

            // Need to check parent's parent, because for ICallExpression Parent is ExpressionStaement but not a SourceFile directly.
            if (callExpression.Parent.IsTopLevelDeclaration())
            {
                var expressionName = callExpression.Expression.As <IIdentifier>();
                if (expressionName != null)
                {
                    return(expressionName.Text == Names.ConfigurationFunctionCall ||
                           expressionName.Text == Names.LegacyModuleConfigurationFunctionCall ||
                           expressionName.Text == Names.ModuleConfigurationFunctionCall);
                }
            }

            return(false);
        }
Пример #9
0
        public static IExpression TypeOf(ICallExpression call)
        {
            if (call.Method.Method.IsGetTypeFromHandle())
            {
                if (call.Arguments.Count != 1)
                {
                    throw new InvalidOperationException();
                }

                var typeRef = call.Arguments[0] as ITypeReferenceExpression;
                if (typeRef == null)
                {
                    throw new InvalidOperationException();
                }

                return(new TypeOfExpression(typeRef.Type));
            }
            return(null);
        }
Пример #10
0
        private static int FitsOnOneLine(ICallExpression expression, int remainingSpace)
        {
            var space = remainingSpace;

            space = FitsOnOneLine(expression.Expression, space);

            if (space > 0 && expression.TypeArguments != null)
            {
                space -= 2; // The pointy brackets.
                space  = FitsOnOneLine(expression.TypeArguments, 2, space);
            }

            if (space > 0 && expression.Arguments != null)
            {
                space -= 2; // Parenthesis;
                space  = FitsOnOneLine(expression.Arguments, 2, space);
            }

            return(space);
        }
        /// <summary>
        /// Tries to parse the input call expression <param name="callExpression"/> into a GlobDescriptor object.
        /// </summary>
        /// <remarks>
        /// The <param name="basePath"/> and <param name="pathTable"/> must be provided to compute the absolute path of the
        /// 'root' parameter in the call expression.
        /// </remarks>
        public static Possible <GlobDescriptor> TryCreateGlobDescriptorFromCallExpression(
            ICallExpression callExpression,
            AbsolutePath basePath,
            PathTable pathTable)
        {
            var functionName = callExpression.Expression.Cast <IIdentifier>();

            if (!functionName.IsGlob())
            {
                return(new MalformedGlobExpressionFailure(I($"Expecting glob/globR function but got '{functionName.GetText()}'.")));
            }

            if ((callExpression.Arguments?.Count ?? 0) == 0)
            {
                return(new MalformedGlobExpressionFailure("Glob function should take at least one argument but got 0."));
            }

            // Parse the 'root' param
            var root = AbsolutePath.Invalid;
            var pathExpressionString = callExpression.Arguments[0].GetText();

            if (!TryCreateAbsolutePath(
                    pathTable,
                    basePath,
                    pathExpressionString,
                    out root))
            {
                return(new MalformedGlobExpressionFailure(I($"Malformed path expression '{pathExpressionString}'.")));
            }

            // Parse the 'pattern' param. If none is provided, it is defaulted to "*"
            var pattern = callExpression.Arguments.Count > 1 ? callExpression.Arguments[1].Cast <IStringLiteral>().Text : "*";

            // Determine if glob is recursive
            var recursive = functionName.IsGlobRecursive();

            return(new GlobDescriptor(root, pattern, recursive));
        }
Пример #12
0
        private bool FixCreateFunction(ICallExpression call, ISymbol symbol, DiagnosticsContext context, string formatFunction, string interfaceName)
        {
            if (Matches(context, symbol, "Sdk.Prelude", interfaceName + ".create"))
            {
                var arg = call.Arguments.FirstOrDefault();

                var fix = ComputeFix(formatFunction, arg);

                if (Fix)
                {
                    call.Replace(fix);
                }
                else
                {
                    var existingExpression = call.ToDisplayString();
                    var fixExpression      = fix.ToDisplayString();
                    Logger.LegacyLiteralFix(LoggingContext, call.LocationForLogging(context.SourceFile), fixExpression, existingExpression);
                    return(false);
                }
            }

            return(true);
        }
Пример #13
0
 public virtual void VisitCallExpression(ICallExpression e)
 {
 }
Пример #14
0
 private static string GetModuleNameFromImportFrom(ICallExpression node)
 {
     return(node.Arguments.First().TryCast <ILiteralExpression>()?.Text);
 }
Пример #15
0
        /// <nodoc/>
        public Result <SignatureHelp, ResponseError> SignatureHelp(TextDocumentPositionParams positionParams, CancellationToken token)
        {
            // TODO: support cancellation
            if (!TryFindNode(positionParams, out var nodeAtPosition))
            {
                return(Result <SignatureHelp, ResponseError> .Success(new SignatureHelp()));
            }

            ICallExpression callExpression = GetContainingCallExpression(nodeAtPosition);

            if (callExpression == null)
            {
                Logger.LanguageServerNonCriticalInternalIssue(LoggingContext, FormattableStringEx.I($"Couldn't find call expression containing {nodeAtPosition.GetFormattedText()}"));
                return(Result <SignatureHelp, ResponseError> .Success(new SignatureHelp()));
            }

            var callSymbol = TypeChecker.GetSymbolAtLocation(callExpression.Expression);

            // If the user has typed a call expresion to a symbol (function) that doesn't exist (i.e. "foo.bar()")
            // Then just issue a debug writeline and a success instead of crashing.
            // There is going to be a red-line squiggle under it anyway.
            if (callSymbol == null)
            {
                Logger.LanguageServerNonCriticalInternalIssue(LoggingContext, FormattableStringEx.I($"Couldn't find symbol for call expression containing {nodeAtPosition.GetFormattedText()}"));
                return(Result <SignatureHelp, ResponseError> .Success(new SignatureHelp()));
            }

            var signature = TypeChecker.GetSignaturesOfType(TypeChecker.GetTypeAtLocation(callExpression.Expression), SignatureKind.Call).FirstOrDefault();

            if (signature == null)
            {
                Logger.LanguageServerNonCriticalInternalIssue(LoggingContext, FormattableStringEx.I($"Couldn't find call signature for call expression containing {nodeAtPosition.GetFormattedText()}"));
                return(Result <SignatureHelp, ResponseError> .Success(new SignatureHelp()));
            }

            var functionDeclaration = DScriptFunctionSignature.FromSignature(callSymbol.Name, signature);

            var parameterInformations = functionDeclaration.FormattedParameterNames.Select(formattedParameterName => new ParameterInformation()
            {
                Label = formattedParameterName,
            });

            int activeParameterIndex = DScriptFunctionSignature.GetActiveParameterIndex(callExpression, nodeAtPosition);

            var signatureHelp = new SignatureHelp()
            {
                Signatures = new SignatureInformation[]
                {
                    new SignatureInformation()
                    {
                        Label         = functionDeclaration.FormattedFullFunctionSignature,
                        Parameters    = parameterInformations.ToArray(),
                        Documentation = DocumentationUtilities.GetDocumentationForSymbolAsString(callSymbol),
                    },
                },
                ActiveParameter = activeParameterIndex,
                ActiveSignature = 0,
            };

            return(Result <SignatureHelp, ResponseError> .Success(signatureHelp));
        }