示例#1
0
        public IVariableStatement Build()
        {
            if (m_expression == null)
            {
                throw new InvalidOperationException(FormattableStringEx.I($"The initializer expression was not specified. Did you forget to call Initializer method?"));
            }

            if (m_name == null)
            {
                throw new InvalidOperationException(FormattableStringEx.I($"The name was not specified. Did you forget to call Initializer method?"));
            }

            var nodeFlags = m_isConst ? NodeFlags.Const : NodeFlags.None;

            if (m_visibility == DScript.Visibility.Export || m_visibility == DScript.Visibility.Public)
            {
                nodeFlags |= NodeFlags.Export;
            }

            var result = new VariableStatement(
                m_name,
                m_expression,
                type: m_type,
                flags: nodeFlags);

            if (m_visibility == DScript.Visibility.Public)
            {
                result.WithPublicDecorator();
            }

            return(result);
        }
示例#2
0
        /// <summary>
        /// Returns a properly formatted/sorted list of directory dependencies.
        /// </summary>
        private List <string> GetDirectoryDependencies(ReadOnlyArray <DirectoryArtifact> dependencies)
        {
            var result      = new List <string>();
            var directories = new Stack <(DirectoryArtifact artifact, string path, int tabCount)>(
                dependencies
                .Select(d => (artifact: d, path: d.Path.ToString(PathTable), 0))
                .OrderByDescending(tupple => tupple.path));

            while (directories.Count > 0)
            {
                var directory = directories.Pop();
                result.Add(directory.tabCount == 0
                    ? FormattableStringEx.I($"{directory.path} (PartialSealId: {directory.artifact.PartialSealId}, IsSharedOpaque: {directory.artifact.IsSharedOpaque})")
                    : FormattableStringEx.I($"|{string.Concat(Enumerable.Repeat("---", directory.tabCount))}{directory.path} (PartialSealId: {directory.artifact.PartialSealId}, IsSharedOpaque: {directory.artifact.IsSharedOpaque})"));

                var sealPipId = CachedGraph.PipGraph.GetSealedDirectoryNode(directory.artifact).ToPipId();

                if (PipTable.IsSealDirectoryComposite(sealPipId))
                {
                    var sealPip = (SealDirectory)CachedGraph.PipGraph.GetSealedDirectoryPip(directory.artifact, PipQueryContext.SchedulerExecuteSealDirectoryPip);
                    foreach (var nestedDirectory in sealPip.ComposedDirectories.Select(d => (artifact: d, path: d.Path.ToString(PathTable))).OrderByDescending(tupple => tupple.path))
                    {
                        directories.Push((nestedDirectory.artifact, nestedDirectory.path, directory.tabCount + 1));
                    }
                }
            }

            return(result);
        }
示例#3
0
        /// <summary>
        /// Extracts the qualifier type from the given node and returns a corresponding qualifier space for it
        /// </summary>
        public QualifierSpaceId ConvertQualifierType(INode node)
        {
            var qualifierType = m_semanticModel.GetCurrentQualifierType(node);

            if (qualifierType == null || qualifierType.Flags == TypeFlags.Any)
            {
                // TODO: this needs to be removed once semantic evaluation will work only with new qualifiers.
                // With V1 qualifiers the condition in the if statement can be true.
                return(m_qualifierTable.EmptyQualifierSpaceId);
            }

            var resolvedType = qualifierType as IResolvedType;

            if (resolvedType == null)
            {
                // This method is on a hot path, and string computation is not cheap.
                // Moving this assertion inside the loop saves reasonable amount of time for large builds.
                Contract.Assert(false, FormattableStringEx.I($"Qualifier type should be of 'IResolvedType' but got '{qualifierType.GetType()}'"));
            }

            using (var closure = s_convertQualifierClosures.GetInstance())
            {
                var func = closure.Instance.CreateClosure(resolvedType, m_qualifierTable, m_semanticModel);
                return(m_qualifierSpaceDeclarationCache.GetOrAdd(resolvedType.Id, func));
            }
        }
示例#4
0
        /// <summary>
        /// Tries to read a package's hash file from disk.
        /// </summary>
        /// <remarks>
        /// The <see cref="Failure"/> returned from this method is recoverable.
        /// </remarks>
        public static Possible <PackageHashFile> TryReadFrom(string path)
        {
            string[] content;
            try
            {
                content = ExceptionUtilities.HandleRecoverableIOException(
                    () =>
                {
                    if (!File.Exists(path))
                    {
                        return(null);
                    }

                    return(File.ReadAllLines(path));
                },
                    e => throw new BuildXLException(FormattableStringEx.I($"Failed to parse package hash file."), e));
            }
            catch (BuildXLException e)
            {
                return(new PackageHashFileFailure(e.LogEventMessage));
            }

            if (content == null)
            {
                return(new PackageHashFileFailure(FormattableStringEx.I($"Package hash file is missing.")));
            }

            if (content.Length < MinNumberOfLines)
            {
                // The version field potentially can be used for invalidating generated packages as well.
                // The new file format is:
                // Version
                // Specs format version
                // SHA
                // Fingerprint
                // List of files
                return(new PackageHashFileFailure(FormattableStringEx.I($"Package hash file has an invalid content. Expected at least {MinNumberOfLines} lines but got {content.Length} lines.")));
            }

            var version = content[0];

            if (version != HashFileFormatVersion)
            {
                return(new PackageHashFileFailure(FormattableStringEx.I($"Package hash file has different version. Expected version: {HashFileFormatVersion}, actual version: {version}.")));
            }

            var specsFileVersion = content[1];

            var fingerprintHash = content[2];
            var fingerprintText = content[3];

            var files = content.Skip(MinNumberOfLines).Where(s => !string.IsNullOrEmpty(s)).ToArray();

            if (files.Length == 0)
            {
                return(new PackageHashFileFailure(FormattableStringEx.I($"Package hash file does not have package content files.")));
            }

            return(new PackageHashFile(fingerprintHash, fingerprintText, files, specsFormatIsUpToDate: specsFileVersion == GeneratedSpecsVersion));
        }
示例#5
0
        private CodeLens GetModuleReference(ParsedModule module, ISourceFile spec)
        {
            var moduleVersion = string.IsNullOrEmpty(module.Descriptor.Version) ? null : $" (version: {module.Descriptor.Version})";

            // Ideally we want to navigate to the module declaration, but unfortunately we don't keep proper track of that.
            // Therefore we do a quick file existence check, try to find the common name and then fall back to the current spec file.
            var moduleConfigFile = module.Definition.ModuleConfigFile.ToString(PathTable);

            if (!File.Exists(moduleConfigFile))
            {
                moduleConfigFile = Path.Combine(Path.GetDirectoryName(moduleConfigFile), "module.config.dsc");
            }
            else if (!File.Exists(moduleConfigFile))
            {
                // Fall back to the current spec....
                moduleConfigFile = spec.FileName;
            }

            return
                (new CodeLens
            {
                Range = spec.ToRange(),
                Command = new Command
                {
                    Title = FormattableStringEx.I($"Module: {module.Descriptor.Name}{moduleVersion} - {module.Definition.Root.ToString(PathTable)}"),
                    CommandIdentifier = "DScript.openDocument",
                    Arguments = new object[] { UriExtensions.GetUriFromPath(moduleConfigFile) },
                },
            });
        }
示例#6
0
        private void Log(FormattableString message)
        {
            var pid = -1;

#pragma warning disable ERP022 // Unobserved exception in generic exception handler
            try { pid = ProcessId; } catch {}
#pragma warning restore ERP022 // Unobserved exception in generic exception handler
            m_logger?.Invoke(FormattableStringEx.I($"Process({pid}) - {message}"));
        }
示例#7
0
        private static string GetIdentifierForNode(INode node)
        {
            var asDeclaration = node.As <IDeclaration>();

            if (asDeclaration != null)
            {
                return(asDeclaration.Name.Text);
            }

            var asVariableStatement = node.As <IVariableStatement>();

            if (asVariableStatement != null)
            {
                return(asVariableStatement.DeclarationList.Declarations[0].Name.GetText());
            }

            return(FormattableStringEx.I($"Unknown({node.Kind})"));
        }
示例#8
0
        private List <string> GetDirectoryOutputsWithContent(Process pip)
        {
            var outputs      = new List <string>();
            var rootExpander = new RootExpander(PathTable);

            foreach (var directoryOutput in pip.DirectoryOutputs)
            {
                outputs.Add(FormattableStringEx.I($"{directoryOutput.Path.ToString(PathTable)} (PartialSealId: {directoryOutput.PartialSealId}, IsSharedOpaque: {directoryOutput.IsSharedOpaque})"));
                if (m_directoryContents.TryGetValue(directoryOutput, out var directoryContent))
                {
                    foreach (var file in directoryContent)
                    {
                        outputs.Add(FormattableStringEx.I($"|--- {file.Path.ToString(PathTable, rootExpander)}"));
                    }
                }
            }

            return(outputs);
        }
示例#9
0
        private bool GetQualifierAsCodeLens(INode node, out CodeLens codeLens)
        {
            codeLens = default(CodeLens);

            // If the current module is V1 the qualifier types would be unavailable
            var qualifierType = SemanticModel.GetCurrentQualifierType(node);

            if (qualifierType == null)
            {
                return(false);
            }

            var qualifierDeclaration = SemanticModel.GetCurrentQualifierDeclaration(node);

            if (qualifierDeclaration == null)
            {
                return(false);
            }

            var formattedQualifier = TypeChecker.TypeToString(qualifierType);

            var fileUri = qualifierDeclaration.GetSourceFile().ToUri().AbsoluteUri;
            var range   = qualifierDeclaration.ToRange();

            codeLens = new CodeLens
            {
                Range   = node.ToRange(),
                Command = new Command
                {
                    Title             = FormattableStringEx.I($"Qualifier type: {formattedQualifier}"),
                    CommandIdentifier = "DScript.openDocument",
                    Arguments         = new object[]
                    {
                        fileUri,
                        range,
                    },
                },
            };

            return(true);
        }
示例#10
0
 /// <summary>
 /// Returns a friendly name for a current package.
 /// </summary>
 public string GetFriendlyName()
 => FormattableStringEx.I($"{Protocol}://{Id}/{Version}");
示例#11
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));
        }
示例#12
0
        private static bool TryCreateImportStatementCommand(
            Workspace workspace,
            PathTable pathTable,
            CodeActionParams actionParams,
            out dynamic[] commandArguments)
        {
            commandArguments = default(dynamic[]);

            var typeChecker = workspace.GetSemanticModel().TypeChecker;

            if (!actionParams.TextDocument.Uri.TryGetSourceFile(workspace, pathTable, out var sourceUri))
            {
                return(false);
            }

            Contract.Assert(actionParams.Range?.Start != null);
            if (!DScriptNodeUtilities.TryGetNodeAtPosition(sourceUri, actionParams.Range.Start.ToLineAndColumn(), out var node))
            {
                return(false);
            }

            var nodeFlags = NodeUtilities.GetCombinedNodeFlags(node);

            if ((nodeFlags & NodeFlags.ScriptPublic) == NodeFlags.None)
            {
                return(false);
            }

            var symbol = typeChecker.GetSymbolAtLocation(node) ?? node.Symbol ?? node.ResolvedSymbol;

            if (symbol == null)
            {
                return(false);
            }

            var symbolFullName = typeChecker.GetFullyQualifiedName(symbol);

            // The import statement can only contain a single identifier, so if the symbol's full name
            // is Namespace.Subnamespace.value, we care about just 'Namespace'
            var identifier = GetFirstIdentifier(symbolFullName);

            var module = workspace.TryGetModuleBySpecFileName(sourceUri.GetAbsolutePath(pathTable));

            if (module == null)
            {
                return(false);
            }

            var importString = string.Format(
                CultureInfo.InvariantCulture,
                "import {{{0}}} from \"{1}\";",
                identifier,
                module.Definition.Descriptor.Name);

            var bannerString = FormattableStringEx.I($"Import string for '{symbolFullName}' placed on clipboard");

            commandArguments = new dynamic[]
            {
                importString,
                bannerString,
            };

            return(true);
        }
示例#13
0
 /// <inheritdoc />
 public override string ToString()
 {
     return(FormattableStringEx.I($"WF:{WeakFingerprint}, PS#:{PathSetHash}, SF:{StrongFingerprint}, MD#:{CacheEntry.MetadataHash}"));
 }