/// <summary>
 /// Launches the debugger at the end of the given phase if specified
 /// </summary>
 public static void TryLaunchDebuggerAfterPhase(EnginePhases phase)
 {
     if (LaunchDebuggerAfterPhase != null && LaunchDebuggerAfterPhase.Value == phase)
     {
         Debugger.Launch();
     }
 }
示例#2
0
 private static CommandLineConfiguration GetCommandLineConfiguration(
     WorkspaceBuilderConfiguration configuration,
     EnginePhases phase,
     AbsolutePath configFile)
 {
     return(new CommandLineConfiguration
     {
         Startup =
         {
             ConfigFile = configFile,
         },
         FrontEnd =
         {
             DebugScript                            = false,
             PreserveFullNames                      = true,
             PreserveTrivia                         = true, // We want to preserve comments, so let's not skip trivia
             CancelParsingOnFirstFailure            = configuration.CancelOnFirstParsingFailure,
             UseSpecPublicFacadeAndAstWhenAvailable = configuration.PublicFacadeOptimization,
             ConstructAndSaveBindingFingerprint     = configuration.SaveBindingFingerprint,
             NameResolutionSemantics                = NameResolutionSemantics.ImplicitProjectReferences,
             // If SkipNuget is specified, then all the packages should be on disk.
             // Skipping nuget restore in this case.
             UsePackagesFromFileSystem              = configuration.SkipNuget,
         },
         Engine =
         {
             Phase = phase,
         },
     });
 }
示例#3
0
        /// <summary>
        /// Returns the action associated with a given key in a given dictionary.  If no entry
        /// is found, returns an empty action.
        /// </summary>
        private static Action GetPhaseHook(Dictionary <EnginePhases, Action> hooks, EnginePhases phase)
        {
            Action hook;

            return(hooks.TryGetValue(phase, out hook)
                ? hook
                : () => { });
        }
示例#4
0
        private static CommandLineConfiguration GetCommandLineConfiguration(
            WorkspaceBuilderConfiguration configuration,
            EnginePhases phase,
            AbsolutePath configFile,
            AbsolutePath outputDirectory,
            AbsolutePath objectDirectory)
        {
            return(new CommandLineConfiguration
            {
                Startup =
                {
                    ConfigFile = configFile,
                },
                FrontEnd =
                {
                    DebugScript                            = false,
                    PreserveFullNames                      = true,
                    PreserveTrivia                         = true, // We want to preserve comments, so let's not skip trivia
                    CancelParsingOnFirstFailure            = configuration.CancelOnFirstParsingFailure,
                    UseSpecPublicFacadeAndAstWhenAvailable = configuration.PublicFacadeOptimization,
                    ConstructAndSaveBindingFingerprint     = configuration.SaveBindingFingerprint,
                    NameResolutionSemantics                = NameResolutionSemantics.ImplicitProjectReferences,
                    // If SkipNuget is specified, then all the packages should be on disk.
                    // Skipping nuget restore in this case.
                    UsePackagesFromFileSystem              = configuration.SkipNuget,

                    // Don't release workspace so that analyses can still be done if the min required phase is evaluation.
                    // TODO: Hack -- when phase Evaluate is use, then release workspace. This is for Office to be performant.
                    ReleaseWorkspaceBeforeEvaluation       = !phase.HasFlag(EnginePhases.Evaluate),
                    UnsafeOptimizedAstConversion           = true,
                    AllowUnsafeAmbient                     = true,
                },
                Engine =
                {
                    Phase = phase,
                },
                Schedule =
                {
                    UseFixedApiServerMoniker = true
                },
                Layout =
                {
                    OutputDirectory = outputDirectory,
                    ObjectDirectory = objectDirectory,
                },
                Logging =
                {
                    LogsToRetain = 0,
                },
                Cache =
                {
                    CacheSpecs = SpecCachingOption.Disabled
                }
            });
        }
示例#5
0
        /// <summary>
        /// Composes a given action with any action previously associated with a given key in a given dictionary.
        /// </summary>
        private void AddPhaseHook(Dictionary <EnginePhases, Action> hooks, EnginePhases phase, Action hook)
        {
            Contract.Requires(hooks != null);
            Contract.Requires(hook != null);
            Contract.Requires(!IsSealed);

            var oldHook = GetPhaseHook(hooks, phase);

            hooks[phase] = () =>
            {
                oldHook();
                hook();
            };
        }
示例#6
0
 /// <summary>
 /// Composes a given hook with any 'end' hook previously associated with a given phase.
 /// </summary>
 public void AddPhaseEndHook(EnginePhases phase, Action hook)
 {
     AddPhaseHook(m_phaseEndHooks, phase, hook);
 }
示例#7
0
 /// <summary>
 /// Returns the 'end' hook associated with a given phase.
 /// If no hook has been associated, an empty action is returned.
 /// </summary>
 public Action GetPhaseEndHook(EnginePhases phase)
 {
     return(GetPhaseHook(m_phaseEndHooks, phase));
 }
示例#8
0
        /// <summary>
        /// Builds a workspace and uses filter to find specs to evaluate.
        /// </summary>
        public static bool TryCollectFilesToAnalyze(
            Tracing.Logger logger,
            PathTable pathTable,
            EnginePhases phase,
            string configFile,
            string filter,
            out Workspace workspace,
            out IReadOnlyDictionary <AbsolutePath, ISourceFile> filesToAnalyze,
            out FrontEndContext context)
        {
            workspace      = null;
            filesToAnalyze = null;

            var loggingContext = new LoggingContext("DScriptAnalyzer");
            var fileSystem     = new PassThroughFileSystem(pathTable);
            var engineContext  = EngineContext.CreateNew(CancellationToken.None, pathTable, fileSystem);

            context = engineContext.ToFrontEndContext(loggingContext);

            // Parse filter string into EvaluationFilter
            var evaluationFilter = EvaluationFilter.Empty;

            if (!string.IsNullOrEmpty(filter))
            {
                if (!TryGetEvaluationFilter(logger, loggingContext, engineContext, filter, out evaluationFilter))
                {
                    // Error has been reported already
                    return(false);
                }
            }

            var configFilePath = AbsolutePath.Create(pathTable, configFile);

            // Try parsing the workspace from config and evaluation filter
            if (!TryBuildWorkspace(
                    phase,
                    context,
                    engineContext,
                    configFilePath,
                    evaluationFilter,
                    progressHandler: null,
                    workspace: out workspace,
                    frontEndHostController: out _,
                    configuration: GetDefaultConfiguration()))
            {
                return(false);
            }

            // Find strict subset of specs in workspace that should be analyzed
            var collectedFilesToAnalyze = CollectFilesToAnalyze(
                workspace,
                pathTable,
                configFilePath,
                evaluationFilter);

            if (collectedFilesToAnalyze.Count == 0)
            {
                logger.ErrorFilterHasNoMatchingSpecs(loggingContext, filter);
                return(false);
            }

            filesToAnalyze = collectedFilesToAnalyze;
            return(true);
        }
示例#9
0
        public static bool TryBuildWorkspace(
            EnginePhases phase,
            FrontEndContext frontEndContext,
            PipExecutionContext engineContext,
            AbsolutePath configFile,
            EvaluationFilter evaluationFilter,
            EventHandler <WorkspaceProgressEventArgs> progressHandler,
            out Workspace workspace,
            out FrontEndHostController frontEndHostController,
            WorkspaceBuilderConfiguration configuration,
            FrontEndEngineAbstraction frontEndEngineAbstraction = null,
            bool collectMemoryAsSoonAsPossible = true)
        {
            Contract.Requires((phase & (EnginePhases.ParseWorkspace | EnginePhases.AnalyzeWorkspace)) != EnginePhases.None);
            Contract.Requires(frontEndContext != null);
            Contract.Requires(engineContext != null);
            Contract.Requires(configFile.IsValid);
            Contract.Requires(evaluationFilter != null);

            workspace = null;

            var pathTable      = engineContext.PathTable;
            var loggingContext = frontEndContext.LoggingContext;

            var commandlineConfig = GetCommandLineConfiguration(configuration, phase, configFile);

            BuildXLEngine.PopulateLoggingAndLayoutConfiguration(commandlineConfig, pathTable, bxlExeLocation: null);

            var statistics = new FrontEndStatistics(progressHandler);
            var frontEndControllerFactory = FrontEndControllerFactory.Create(
                mode: FrontEndMode.NormalMode,
                loggingContext: loggingContext,
                configuration: commandlineConfig,
                collector: null,
                statistics: statistics,
                collectMemoryAsSoonAsPossible: collectMemoryAsSoonAsPossible);

            var controller = frontEndControllerFactory.Create(engineContext.PathTable, engineContext.SymbolTable);

            controller.InitializeHost(frontEndContext, commandlineConfig);

            frontEndHostController = controller as FrontEndHostController;

            // If there is an explicit engine abstraction, we set it
            if (frontEndEngineAbstraction != null)
            {
                frontEndHostController.SetState(frontEndEngineAbstraction, pipGraph: null, configuration: commandlineConfig);
            }

            var config = controller.ParseConfig(commandlineConfig);

            if (config == null)
            {
                frontEndHostController = null;
                return(false);
            }

            using (var cache = Task.FromResult <Possible <EngineCache> >(
                       new EngineCache(
                           new InMemoryArtifactContentCache(
                               new SchedulerContext(
                                   CancellationToken.None,
                                   frontEndContext.StringTable,
                                   frontEndContext.PathTable,
                                   frontEndContext.SymbolTable,
                                   frontEndContext.QualifierTable)),

                           // Note that we have an 'empty' store (no hits ever) rather than a normal in memory one.
                           new EmptyTwoPhaseFingerprintStore())))
            {
                // Attempt to build and/or analyze the workspace
                if (!controller.PopulateGraph(
                        cache: cache,
                        graph: null /* No need to create pips */,
                        engineAbstraction: frontEndEngineAbstraction ?? new BasicFrontEndEngineAbstraction(frontEndContext.PathTable, frontEndContext.FileSystem, config),
                        evaluationFilter: evaluationFilter,
                        configuration: config,
                        startupConfiguration: commandlineConfig.Startup))
                {
                    Contract.Assert(frontEndHostController != null);
                    workspace = frontEndHostController.GetWorkspace();

                    // Error has been reported already
                    return(false);
                }
            }

            Contract.Assert(frontEndHostController != null);

            // If workspace construction is successfull, we run the linter on all specs.
            // This makes sure the workspace will carry all the errors that will occur when running the same specs in the regular engine path
            workspace = CreateLintedWorkspace(
                frontEndHostController.GetWorkspace(),

                frontEndContext.LoggingContext,
                config.FrontEnd,
                pathTable);

            return(true);
        }
示例#10
0
        public static bool TryBuildWorkspace(
            EnginePhases phase,
            FrontEndContext frontEndContext,
            EngineContext engineContext,
            AbsolutePath configFile,
            EvaluationFilter evaluationFilter,
            AbsolutePath outputDirectory,
            AbsolutePath objectDirectory,
            EventHandler <WorkspaceProgressEventArgs> progressHandler,
            out Workspace workspace,
            out FrontEndHostController frontEndHostController,
            out IPipGraph pipGraph,
            WorkspaceBuilderConfiguration configuration,
            FrontEndEngineAbstraction frontEndEngineAbstraction = null,
            bool collectMemoryAsSoonAsPossible = true)
        {
            Contract.Requires((phase & (EnginePhases.ParseWorkspace | EnginePhases.AnalyzeWorkspace)) != EnginePhases.None);
            Contract.Requires(frontEndContext != null);
            Contract.Requires(engineContext != null);
            Contract.Requires(configFile.IsValid);
            Contract.Requires(evaluationFilter != null);

            workspace = null;
            frontEndHostController = null;
            pipGraph = null;

            var pathTable      = engineContext.PathTable;
            var loggingContext = frontEndContext.LoggingContext;

            var commandlineConfig = GetCommandLineConfiguration(
                configuration,
                phase,
                configFile,
                outputDirectory,
                objectDirectory);

            BuildXLEngine.PopulateLoggingAndLayoutConfiguration(commandlineConfig, pathTable, bxlExeLocation: null);

            var statistics = new FrontEndStatistics(progressHandler);
            var frontEndControllerFactory = FrontEndControllerFactory.Create(
                mode: FrontEndMode.NormalMode,
                loggingContext: loggingContext,
                configuration: commandlineConfig,
                collector: null,
                statistics: statistics,
                collectMemoryAsSoonAsPossible: collectMemoryAsSoonAsPossible);

            var controller = frontEndControllerFactory.Create(engineContext.PathTable, engineContext.SymbolTable);

            controller.InitializeHost(frontEndContext, commandlineConfig);

            frontEndHostController = (FrontEndHostController)controller;

            // If there is an explicit engine abstraction, we set it. This is used by IDE test.
            if (frontEndEngineAbstraction != null)
            {
                frontEndHostController.SetState(frontEndEngineAbstraction, pipGraph: null, configuration: commandlineConfig);
            }

            var config = controller.ParseConfig(commandlineConfig);

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

            IPipGraph pipGraphBuilder = null;

            using (var cache = Task.FromResult <Possible <EngineCache> >(
                       new EngineCache(
                           new InMemoryArtifactContentCache(),

                           // Note that we have an 'empty' store (no hits ever) rather than a normal in memory one.
                           new EmptyTwoPhaseFingerprintStore())))
            {
                if (frontEndEngineAbstraction == null)
                {
                    if (phase.HasFlag(EnginePhases.Schedule))
                    {
                        var mountsTable = MountsTable.CreateAndRegister(loggingContext, engineContext, config, commandlineConfig.Startup.Properties);
                        frontEndEngineAbstraction = new FrontEndEngineImplementation(
                            loggingContext,
                            frontEndContext.PathTable,
                            config,
                            commandlineConfig.Startup,
                            mountsTable,
                            InputTracker.CreateDisabledTracker(loggingContext),
                            null,
                            null,
                            () => FileContentTable.CreateStub(),
                            5000,
                            false);

                        pipGraphBuilder = new GraphFragmentBuilder(loggingContext, engineContext, config);

                        // TODO: Think more if an analyzer wants to use the real pip graph builder.
                        //pipGraphBuilder = new PipGraph.Builder(
                        //    EngineSchedule.CreateEmptyPipTable(engineContext),
                        //    engineContext,
                        //    Scheduler.Tracing.Logger.Log,
                        //    loggingContext,
                        //    config,
                        //    mountsTable.MountPathExpander,
                        //    fingerprintSalt: config.Cache.CacheSalt,
                        //    directoryMembershipFingerprinterRules: new DirectoryMembershipFingerprinterRuleSet(config, engineContext.StringTable));
                        if (!AddConfigurationMountsAndCompleteInitialization(config, loggingContext, mountsTable))
                        {
                            return(false);
                        }

                        IDictionary <ModuleId, MountsTable> moduleMountsTableMap;
                        if (!mountsTable.PopulateModuleMounts(config.ModulePolicies.Values, out moduleMountsTableMap))
                        {
                            Contract.Assume(loggingContext.ErrorWasLogged, "An error should have been logged after MountTable.PopulateModuleMounts()");
                            return(false);
                        }
                    }
                    else
                    {
                        frontEndEngineAbstraction = new BasicFrontEndEngineAbstraction(frontEndContext.PathTable, frontEndContext.FileSystem, config);
                    }
                }

                using (frontEndEngineAbstraction is IDisposable ? (IDisposable)frontEndEngineAbstraction : null)
                {
                    // Attempt to build and/or analyze the workspace
                    if (!controller.PopulateGraph(
                            cache: cache,
                            graph: pipGraphBuilder,
                            engineAbstraction: frontEndEngineAbstraction,
                            evaluationFilter: evaluationFilter,
                            configuration: config,
                            startupConfiguration: commandlineConfig.Startup))
                    {
                        workspace = frontEndHostController.GetWorkspace();

                        // Error has been reported already
                        return(false);
                    }

                    pipGraph = pipGraphBuilder;

                    //if (pipGraphBuilder != null)
                    //{
                    //    pipGraph = pipGraphBuilder.Build();

                    //    if (pipGraph == null)
                    //    {
                    //        // Error has been reported already.
                    //        return false;
                    //    }
                    //}
                }
            }

            Contract.Assert(frontEndHostController != null);

            workspace = frontEndHostController.GetWorkspace();

            if (phase == EnginePhases.AnalyzeWorkspace)
            {
                // If workspace construction is successful, we run the linter on all specs.
                // This makes sure the workspace will carry all the errors that will occur when running the same specs in the regular engine path
                workspace = CreateLintedWorkspace(
                    workspace,
                    frontEndContext.LoggingContext,
                    config.FrontEnd,
                    pathTable);
            }

            return(true);
        }