public void Build(
            XDocument doc, ITextSource textSource,
            MSBuildParserContext context)
        {
            var project = doc.Nodes.OfType <XElement> ().FirstOrDefault(x => x.Name == xnProject);

            if (project == null)
            {
                //TODO: error
                return;
            }

            var sdks = ResolveSdks(context, project).ToList();

            var pel = MSBuildLanguageElement.Get("Project");

            GetPropertiesToTrack(context.PropertyCollector, project);

            var importResolver = context.CreateImportResolver(Filename);

            AddSdkProps(sdks, context.PropertyCollector, importResolver);

            var resolver = new MSBuildSchemaBuilder(IsToplevel, context, importResolver);

            resolver.Run(doc, textSource, this);

            AddSdkTargets(sdks, context.PropertyCollector, importResolver);
        }
 public MSBuildSchemaBuilder(
     bool isToplevel, MSBuildParserContext parseContext,
     MSBuildImportResolver resolveImport)
 {
     this.isToplevel     = isToplevel;
     this.parseContext   = parseContext;
     this.importResolver = resolveImport;
 }
Ejemplo n.º 3
0
 void LoadTasks(MSBuildParserContext context, string label, string filename)
 {
     try {
         var import = context.GetCachedOrParse(label, filename, null, File.GetLastWriteTimeUtc(filename));
         AddImport(import);
     } catch (Exception ex) {
         LoggingService.LogError($"Error loading tasks file {filename}", ex);
     }
 }
        void ResolveImport(MSBuildImportElement element, MSBuildParserContext parseContext, MSBuildImportResolver importResolver)
        {
            var importAtt = element.ProjectAttribute;
            var sdkAtt    = element.SdkAttribute;

            ExpressionNode import    = null;
            string         importTxt = null;

            if (importAtt?.Value != null)
            {
                import    = importAtt.Value;
                importTxt = importAtt.XAttribute.Value;
            }

            if (sdkAtt?.Value is ExpressionText sdkTxt)
            {
                var    loc     = sdkAtt.XAttribute.ValueSpan;
                string sdkPath = parseContext.GetSdkPath(this, sdkTxt.Value, loc);
                import = import == null ? null : new ExpressionText(0, Path.Combine(sdkPath, importTxt), true);

                if (IsToplevel && sdkPath != null)
                {
                    Annotations.Add(sdkAtt.XAttribute, new NavigationAnnotation(sdkPath, loc));
                }
            }

            if (import != null)
            {
                bool wasResolved = false;
                var  loc         = importAtt.XAttribute.ValueSpan;
                foreach (var resolvedImport in importResolver.Resolve(import, importTxt, null))
                {
                    this.AddImport(resolvedImport);
                    wasResolved |= resolvedImport.IsResolved;
                    if (IsToplevel && wasResolved)
                    {
                        Annotations.Add(importAtt.XAttribute, new NavigationAnnotation(resolvedImport.Filename, loc));
                    }
                }
                if (!wasResolved && IsToplevel)
                {
                    DiagnosticSeverity type = element.ConditionAttribute == null ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
                    Diagnostics.Add(CoreDiagnostics.UnresolvedImport, loc, importTxt);
                }
            }
        }
        void ResolveImports(MSBuildProjectElement project, MSBuildParserContext context)
        {
            var sdks = ResolveSdks(project, context).ToList();

            //tag the properties we need to track for the imports
            GetPropertiesToTrack(context.PropertyCollector, project);

            var importResolver = context.CreateImportResolver(Filename);

            AddSdkProps(sdks, context.PropertyCollector, importResolver);

            void ExtractProperties(MSBuildPropertyGroupElement pg)
            {
                foreach (var prop in pg.Elements)
                {
                    context.PropertyCollector.Collect(prop.ElementName, prop.Value);
                }
            }

            foreach (var el in project.Elements)
            {
                switch (el)
                {
                case MSBuildPropertyGroupElement pg:
                    ExtractProperties(pg);
                    break;

                case MSBuildChooseElement choose:
                    foreach (var c in choose.Elements)
                    {
                        foreach (var pg in c.GetElements <MSBuildPropertyGroupElement> ())
                        {
                            ExtractProperties(pg);
                        }
                    }
                    break;

                case MSBuildImportElement imp:
                    ResolveImport(imp, context, importResolver);
                    break;
                }
            }

            AddSdkTargets(sdks, context.PropertyCollector, importResolver);
        }
        IEnumerable <(string id, string path, TextSpan span)> ResolveSdks(MSBuildParserContext context, XElement project)
        {
            var sdksAtt = project.Attributes.Get("Sdk", true);

            if (sdksAtt == null)
            {
                yield break;
            }

            string sdks = sdksAtt?.Value;

            if (string.IsNullOrEmpty(sdks))
            {
                yield break;
            }

            int offset = IsToplevel ? sdksAtt.ValueOffset : sdksAtt.Span.Start;

            foreach (var sdk in SplitSdkValue(offset, sdksAtt.Value))
            {
                if (sdk.id == null)
                {
                    if (IsToplevel)
                    {
                        Diagnostics.Add(CoreDiagnostics.EmptySdkAttribute, sdk.span);
                    }
                }
                else
                {
                    var sdkPath = context.GetSdkPath(this, sdk.id, sdk.span);
                    if (sdkPath != null)
                    {
                        yield return(sdk.id, sdkPath, sdk.span);
                    }
                    if (IsToplevel)
                    {
                        Annotations.Add(sdksAtt, new NavigationAnnotation(sdkPath, sdk.span)
                        {
                            IsSdk = true
                        });
                    }
                }
            }
        }
        IEnumerable <(string id, string path, TextSpan span)> ResolveSdks(MSBuildParserContext context, XElement project)
        {
            var sdksAtt = project.Attributes.Get(new XName("Sdk"), true);

            if (sdksAtt == null)
            {
                yield break;
            }

            string sdks = sdksAtt?.Value;

            if (string.IsNullOrEmpty(sdks))
            {
                yield break;
            }

            int offset = IsToplevel ? sdksAtt.ValueOffset : sdksAtt.Span.Start;

            foreach (var sdk in SplitSdkValue(offset, sdksAtt.Value))
            {
                if (sdk.id == null)
                {
                    if (IsToplevel)
                    {
                        Errors.Add(new XmlDiagnosticInfo(DiagnosticSeverity.Warning, "Empty value", sdk.span));
                    }
                }
                else
                {
                    var sdkPath = context.GetSdkPath(this, sdk.id, sdk.span);
                    if (sdkPath != null)
                    {
                        yield return(sdk.id, sdkPath, sdk.span);
                    }
                    if (IsToplevel)
                    {
                        Annotations.Add(sdksAtt, new NavigationAnnotation(sdkPath, sdk.span));
                    }
                }
            }
        }
        public void Build(XDocument doc, MSBuildParserContext context)
        {
            var project = doc.Nodes.OfType <XElement> ().FirstOrDefault(x => x.NameEquals("Project", true));

            if (project == null)
            {
                //TODO: error
                return;
            }

            var projectElement = new MSBuildProjectElement(project);

            if (IsToplevel)
            {
                ProjectElement = projectElement;
            }

            ResolveImports(projectElement, context);

            InferredSchema = MSBuildInferredSchema.Build(projectElement, Filename, IsToplevel, context);
        }
Ejemplo n.º 9
0
        public static MSBuildRootDocument Parse(
            ITextSource textSource, string filePath, MSBuildRootDocument previous,
            MSBuildSchemaProvider schemaProvider, IRuntimeInformation runtimeInfo,
            ITaskMetadataBuilder taskBuilder,
            CancellationToken token)
        {
            var xmlParser = new XmlTreeParser(new XmlRootState());

            var(xdocument, _) = xmlParser.Parse(textSource.CreateReader());

            var propVals = new PropertyValueCollector(true);

            var doc = new MSBuildRootDocument(filePath)
            {
                XDocument          = xdocument,
                Text               = textSource,
                RuntimeInformation = runtimeInfo
            };

            var importedFiles = new HashSet <string> (StringComparer.OrdinalIgnoreCase);

            if (filePath != null)
            {
                try {
                    doc.Schema = previous?.Schema ?? schemaProvider.GetSchema(filePath, null);
                } catch (Exception ex) {
                    LoggingService.LogError("Error loading schema", ex);
                }
                importedFiles.Add(filePath);
            }

            var parseContext = new MSBuildParserContext(
                runtimeInfo,
                doc,
                previous,
                importedFiles,
                filePath,
                propVals,
                taskBuilder,
                schemaProvider,
                token);

            if (filePath != null)
            {
                doc.FileEvaluationContext = new MSBuildFileEvaluationContext(parseContext.RuntimeEvaluationContext, filePath, filePath);
            }
            else
            {
                doc.FileEvaluationContext = parseContext.RuntimeEvaluationContext;
            }

            string MakeRelativeMSBuildPathAbsolute(string path)
            {
                var dir = Path.GetDirectoryName(doc.Filename);

                path = path.Replace('\\', Path.DirectorySeparatorChar);
                return(Path.GetFullPath(Path.Combine(dir, path)));
            }

            Import TryImportFile(string label, string possibleFile)
            {
                try {
                    var fi = new FileInfo(possibleFile);
                    if (fi.Exists)
                    {
                        var imp = parseContext.GetCachedOrParse(label, possibleFile, null, fi.LastWriteTimeUtc);
                        doc.AddImport(imp);
                        return(imp);
                    }
                } catch (Exception ex) when(parseContext.IsNotCancellation(ex))
                {
                    LoggingService.LogError($"Error importing '{possibleFile}'", ex);
                }
                return(null);
            }

            Import TryImportSibling(string ifHasThisExtension, string thenTryThisExtension)
            {
                if (filePath == null)
                {
                    return(null);
                }
                var extension = Path.GetExtension(filePath);

                if (string.Equals(ifHasThisExtension, extension, StringComparison.OrdinalIgnoreCase))
                {
                    var siblingFilename = Path.ChangeExtension(filePath, thenTryThisExtension);
                    return(TryImportFile("(implicit)", siblingFilename));
                }
                return(null);
            }

            void TryImportIntellisenseImports(MSBuildSchema schema)
            {
                foreach (var intellisenseImport in schema.IntelliSenseImports)
                {
                    TryImportFile("(from schema)", MakeRelativeMSBuildPathAbsolute(intellisenseImport));
                }
            }

            try {
                //if this is a targets file, try to import the props _at the top_
                var propsImport = TryImportSibling(".targets", ".props");

                // this currently only happens in the root file
                // it's a quick hack to allow files to get some basic intellisense by
                // importing the files _that they themselves expect to be imported from_.
                // we also try to load them from the sibling props, as a paired targets/props
                // will likely share a schema file.
                var schema = doc.Schema ?? propsImport?.Document?.Schema;
                if (schema != null)
                {
                    TryImportIntellisenseImports(doc.Schema);
                }

                doc.Build(xdocument, textSource, parseContext);

                //if this is a props file, try to import the targets _at the bottom_
                var targetsImport = TryImportSibling(".props", ".targets");

                //and if we didn't load intellisense import already, try to load them from the sibling targets
                if (schema == null && targetsImport?.Document?.Schema != null)
                {
                    TryImportIntellisenseImports(targetsImport.Document.Schema);
                }
            } catch (Exception ex) when(parseContext.IsNotCancellation(ex))
            {
                LoggingService.LogError($"Error building document '{filePath ?? "[unnamed]"}'", ex);
            }

            try {
                var binpath = parseContext.RuntimeInformation.BinPath;
                foreach (var t in Directory.GetFiles(binpath, "*.tasks"))
                {
                    doc.LoadTasks(parseContext, "(core tasks)", t);
                }
                foreach (var t in Directory.GetFiles(binpath, "*.overridetasks"))
                {
                    doc.LoadTasks(parseContext, "(core overridetasks)", t);
                }
            } catch (Exception ex) when(parseContext.IsNotCancellation(ex))
            {
                LoggingService.LogError("Error resolving tasks", ex);
            }

            try {
                if (previous != null)
                {
                    // try to recover some values that may have been collected from the imports, as they
                    // will not have been re-evaluated
                    var fx = previous.Frameworks.FirstOrDefault();
                    if (fx != null)
                    {
                        propVals.Collect("TargetFramework", fx.GetShortFolderName());
                        propVals.Collect("TargetFrameworkVersion", FrameworkInfoProvider.FormatDisplayVersion(fx.Version));
                        propVals.Collect("TargetFrameworkIdentifier", fx.Framework);
                    }
                }
                doc.Frameworks = propVals.GetFrameworks();
            } catch (Exception ex) {
                LoggingService.LogError("Error determining project framework", ex);
                doc.Frameworks = new List <NuGetFramework> ();
            }

            try {
                //this has to run in a second pass so that it runs after all the schemas are loaded
                var validator = new MSBuildDocumentValidator();
                validator.Run(doc.XDocument, textSource, doc);
            } catch (Exception ex) when(parseContext.IsNotCancellation(ex))
            {
                LoggingService.LogError("Error in validation", ex);
            }

            return(doc);
        }
Ejemplo n.º 10
0
 public MSBuildImportResolver(MSBuildParserContext parseContext, string parentFilePath, IMSBuildEvaluationContext fileEvalContext)
 {
     this.parseContext    = parseContext;
     this.parentFilePath  = parentFilePath;
     this.fileEvalContext = fileEvalContext;
 }
Ejemplo n.º 11
0
 public MSBuildImportResolver(MSBuildParserContext parseContext, string parentFilePath)
     : this(parseContext, parentFilePath, null)
 {
 }
        IEnumerable <(string id, string path, TextSpan span)> ResolveSdks(MSBuildProjectElement project, MSBuildParserContext context)
        {
            var sdksAtt = project.SdkAttribute?.XAttribute;

            if (sdksAtt == null)
            {
                yield break;
            }

            string sdks = sdksAtt.Value;

            if (string.IsNullOrEmpty(sdks))
            {
                yield break;
            }

            int offset = IsToplevel ? sdksAtt.ValueOffset : sdksAtt.Span.Start;

            foreach (var sdk in SplitSdkValue(offset, sdksAtt.Value))
            {
                if (sdk.id == null)
                {
                    if (IsToplevel)
                    {
                        Diagnostics.Add(CoreDiagnostics.EmptySdkAttribute, sdk.span);
                    }
                }
                else
                {
                    var sdkInfo = context.ResolveSdk(this, sdk.id, sdk.span);
                    if (sdkInfo == null)
                    {
                        continue;
                    }

                    yield return(sdk.id, sdkInfo.Path, sdk.span);

                    if (IsToplevel)
                    {
                        Annotations.Add(sdksAtt, new NavigationAnnotation(sdkInfo.Path, sdk.span)
                        {
                            IsSdk = true
                        });
                    }

                    if (sdkInfo.AdditionalPaths != null && sdkInfo.AdditionalPaths.Count > 0)
                    {
                        foreach (var p in sdkInfo.AdditionalPaths)
                        {
                            yield return(sdk.id, p, sdk.span);
                        }
                        if (IsToplevel)
                        {
                            foreach (var p in sdkInfo.AdditionalPaths)
                            {
                                Annotations.Add(sdksAtt, new NavigationAnnotation(p, sdk.span)
                                {
                                    IsSdk = true
                                });
                            }
                        }
                    }
                }
            }
        }
        void ResolveImport(MSBuildImportElement element, MSBuildParserContext parseContext, MSBuildImportResolver importResolver)
        {
            var importAtt = element.ProjectAttribute;
            var sdkAtt    = element.SdkAttribute;

            ExpressionNode[] import    = null;
            string           importTxt = null;

            if (importAtt?.Value != null)
            {
                import    = new ExpressionNode[] { importAtt.Value };
                importTxt = importAtt.XAttribute.Value;
            }

            if (sdkAtt?.Value is ExpressionText sdkTxt)
            {
                var loc     = sdkAtt.XAttribute.ValueSpan;
                var sdkInfo = parseContext.ResolveSdk(this, sdkTxt.Value, loc);

                if (sdkInfo == null)
                {
                    if (IsToplevel)
                    {
                        Diagnostics.Add(CoreDiagnostics.UnresolvedSdk, loc, sdkTxt.Value);
                    }
                    return;
                }

                if (import != null)
                {
                    if (sdkInfo.AdditionalPaths != null && sdkInfo.AdditionalPaths.Count > 0)
                    {
                        import = new ExpressionNode[sdkInfo.AdditionalPaths.Count + 1];
                        for (int i = 0; i < sdkInfo.AdditionalPaths.Count; i++)
                        {
                            import[i + 1] = new ExpressionText(0, Path.Combine(sdkInfo.AdditionalPaths[i], importTxt), true);
                        }
                    }
                    import[0] = new ExpressionText(0, Path.Combine(sdkInfo.Path, importTxt), true);
                }

                if (IsToplevel)
                {
                    Annotations.Add(sdkAtt.XAttribute, new NavigationAnnotation(sdkInfo.Path, loc));
                }
            }

            if (import != null)
            {
                bool wasResolved = false;
                var  loc         = importAtt.XAttribute.ValueSpan;
                foreach (var resolvedImport in import.SelectMany(imp => importResolver.Resolve(imp, importTxt, null)))
                {
                    AddImport(resolvedImport);
                    wasResolved |= resolvedImport.IsResolved;
                    if (IsToplevel && wasResolved)
                    {
                        Annotations.Add(importAtt.XAttribute, new NavigationAnnotation(resolvedImport.Filename, loc));
                    }
                }
                if (!wasResolved && IsToplevel)
                {
                    DiagnosticSeverity type = element.ConditionAttribute == null ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
                    Diagnostics.Add(CoreDiagnostics.UnresolvedImport, loc, importTxt);
                }
            }
        }