diff options
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/CopyComponents')
4 files changed, 495 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/CopyComponents/CopyComponents.csproj b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/CopyComponents.csproj new file mode 100644 index 0000000..4f26673 --- /dev/null +++ b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/CopyComponents.csproj @@ -0,0 +1,74 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.30729</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{E64725D7-2208-4C28-922D-B6543C0BC483}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>CopyComponents</RootNamespace> + <AssemblyName>CopyComponents</AssemblyName> + <SccProjectName> + </SccProjectName> + <SccLocalPath> + </SccLocalPath> + <SccAuxPath> + </SccAuxPath> + <SccProvider> + </SccProvider> + <SignAssembly>false</SignAssembly> + <AssemblyOriginatorKeyFile> + </AssemblyOriginatorKeyFile> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>2.0</OldToolsVersion> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.configuration" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="InheritDocumentationComponent.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\BuildComponents\BuildComponents.csproj"> + <Project>{30773718-BC7C-4FCC-A9C2-7EE61DF4EC41}</Project> + <Name>BuildComponents</Name> + </ProjectReference> + <ProjectReference Include="..\..\CommandLine\CommandLine.csproj"> + <Project>{6CF7CA42-3706-4F6B-A2B4-10EF3F511888}</Project> + <Name>CommandLine</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <!-- Copy the output assemblies to a common binaries directory (ProductionTools). --> + <Target Name="AfterBuild"> + <CreateItem Include="$(OutputPath)\$(AssemblyName).*"> + <Output TaskParameter="Include" ItemName="ProductionFiles" /> + </CreateItem> + <Copy SourceFiles="@(ProductionFiles)" DestinationFolder="..\..\..\ProductionTools" /> + </Target> +</Project>
\ No newline at end of file diff --git a/tools/Sandcastle/Source/BuildAssembler/CopyComponents/CopyComponents.csproj.vspscc b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/CopyComponents.csproj.vspscc new file mode 100644 index 0000000..b6d3289 --- /dev/null +++ b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/CopyComponents.csproj.vspscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" +} diff --git a/tools/Sandcastle/Source/BuildAssembler/CopyComponents/InheritDocumentationComponent.cs b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/InheritDocumentationComponent.cs new file mode 100644 index 0000000..9bb045d --- /dev/null +++ b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/InheritDocumentationComponent.cs @@ -0,0 +1,370 @@ +// ------------------------------------------------------------------------------------------------ +// <copyright file="InheritDocumentationComponent.cs" company="Microsoft"> +// Copyright (c) Microsoft Corporation. All rights reserved. +// </copyright> +// <summary>Contains code that indexes XML comments files for <inheritdoc /> tags, reflection files +// for API information and produces a new XML comments file containing the inherited documentation +// for use by Sandcastle. +// </summary> +// ------------------------------------------------------------------------------------------------ +namespace Microsoft.Ddue.Tools +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.Xml; + using System.Xml.XPath; + using System.Configuration; + using System.Globalization; + using Microsoft.Ddue.Tools.CommandLine; + + /// <summary> + /// InheritDocumentationComponent class. + /// </summary> + public class InheritDocumentationComponent : CopyComponent + { + #region private members + /// <summary> + /// XPathExpression for API name. + /// </summary> + private static XPathExpression apiNameExpression = XPathExpression.Compile("string(apidata/@name)"); + + /// <summary> + /// XPathExpression for API group. + /// </summary> + private static XPathExpression apiGroupExpression = XPathExpression.Compile("string(apidata/@group)"); + + /// <summary> + /// XPathExpression for API subgroup. + /// </summary> + private static XPathExpression apiSubgroupExpression = XPathExpression.Compile("string(apidata/@subgroup)"); + + /// <summary> + /// XPathExpression for API ancestors. + /// </summary> + private static XPathExpression typeExpression = XPathExpression.Compile("family/ancestors/type/@api"); + + /// <summary> + /// XPathExpression for API type interface implementations. + /// </summary> + private static XPathExpression interfaceImplementationExpression = XPathExpression.Compile("implements/type/@api"); + + /// <summary> + /// XPathExpression for API containers. + /// </summary> + private static XPathExpression containerTypeExpression = XPathExpression.Compile("string(containers/type/@api)"); + + /// <summary> + /// XPathExpression for override members. + /// </summary> + private static XPathExpression overrideMemberExpression = XPathExpression.Compile("overrides/member/@api"); + + /// <summary> + /// XPathExpression for API member interface implementaions. + /// </summary> + private static XPathExpression interfaceImplementationMemberExpression = XPathExpression.Compile("implements/member/@api"); + + /// <summary> + /// XPathExpression for <inheritdoc /> nodes. + /// </summary> + private static XPathExpression inheritDocExpression = XPathExpression.Compile("//inheritdoc"); + + /// <summary> + /// XPathExpression that looks for example, filterpriority, preliminary, remarks, returns, summary, threadsafety and value nodes. + /// </summary> + private static XPathExpression tagsExpression = XPathExpression.Compile("example|filterpriority|preliminary|remarks|returns|summary|threadsafety|value"); + + /// <summary> + /// XPathExpression for source nodes. + /// </summary> + private static XPathExpression sourceExpression; + + /// <summary> + /// Document to be parsed. + /// </summary> + private XmlDocument sourceDocument; + + /// <summary> + /// A cache for comment files. + /// </summary> + private IndexedDocumentCache index; + + /// <summary> + /// A cache for reflection files. + /// </summary> + private IndexedDocumentCache reflectionIndex; + #endregion + + #region constructor + /// <summary> + /// Creates an instance of InheritDocumentationComponent class. + /// </summary> + /// <param name="configuration">Configuration section to be parsed.</param> + /// <param name="data">A dictionary object with string as key and object as value.</param> + public InheritDocumentationComponent(XPathNavigator configuration, Dictionary<string, object> data) + : base(configuration, data) + { + // get the copy commands + XPathNodeIterator copy_nodes = configuration.Select("copy"); + foreach (XPathNavigator copy_node in copy_nodes) + { + // get the comments info + string source_name = copy_node.GetAttribute("name", string.Empty); + if (String.IsNullOrEmpty(source_name)) + { + throw new ConfigurationErrorsException("Each copy command must specify an index to copy from."); + } + + // get the reflection info + string reflection_name = copy_node.GetAttribute("use", String.Empty); + if (String.IsNullOrEmpty(reflection_name)) + { + throw new ConfigurationErrorsException("Each copy command must specify an index to get reflection information from."); + } + + this.index = (IndexedDocumentCache)data[source_name]; + this.reflectionIndex = (IndexedDocumentCache)data[reflection_name]; + } + } + #endregion + + #region methods + /// <summary> + /// Deletes the specified node and logs the message. + /// </summary> + /// <param name="inheritDocNodeNavigator">navigator for inheritdoc node</param> + /// <param name="key">Id of the topic specified</param> + public static void DeleteNode(XPathNavigator inheritDocNodeNavigator, string key) + { + ConsoleApplication.WriteMessage(LogLevel.Info, string.Format(CultureInfo.InvariantCulture, "Comments are not found for topic:{0}", key)); + inheritDocNodeNavigator.DeleteSelf(); + } + + /// <summary> + /// Implement inheritDocumentation. + /// </summary> + /// <param name="document">document to be parsed</param> + /// <param name="key">Id pf the topic specified</param> + public override void Apply(XmlDocument document, string key) + { + // default selection filter set not to inherit <overloads>. + sourceExpression = XPathExpression.Compile("*[not(local-name()='overloads')]"); + this.sourceDocument = document; + this.InheritDocumentation(key); + } + + /// <summary> + /// Inherit the documentation. + /// </summary> + /// <param name="key">Id of the topic specified</param> + public void InheritDocumentation(string key) + { + foreach (XPathNavigator inheritDocNodeNavigator in this.sourceDocument.CreateNavigator().Select(inheritDocExpression)) + { + inheritDocNodeNavigator.MoveToParent(); + + XPathNodeIterator iterator = (XPathNodeIterator) inheritDocNodeNavigator.CreateNavigator().Evaluate(tagsExpression); + + // do not inherit the comments if the tags specified in tagsExpression are already present. + if (iterator.Count != 0) + { + inheritDocNodeNavigator.MoveTo(this.sourceDocument.CreateNavigator().SelectSingleNode(inheritDocExpression)); + inheritDocNodeNavigator.DeleteSelf(); + continue; + } + + inheritDocNodeNavigator.MoveTo(this.sourceDocument.CreateNavigator().SelectSingleNode(inheritDocExpression)); + + // Inherit from the specified API [id=cref]. + string cref = inheritDocNodeNavigator.GetAttribute("cref", string.Empty); + + if (!string.IsNullOrEmpty(cref)) + { + XPathNavigator contentNodeNavigator = this.index.GetContent(cref); + + // if no comments were found for the specified api, delete the <inheritdoc /> node, + // otherwise update the <inheritdoc /> node with the comments from the specified api. + if (contentNodeNavigator == null) + { + DeleteNode(inheritDocNodeNavigator, cref); + } + else + { + this.UpdateNode(inheritDocNodeNavigator, contentNodeNavigator); + if (this.sourceDocument.CreateNavigator().Select(inheritDocExpression).Count != 0) + { + this.InheritDocumentation(cref); + } + } + } + else + { + XPathNavigator reflectionNodeNavigator = this.reflectionIndex.GetContent(key); + + // no reflection information was found for the api, so delete <inheritdoc /> node. + if (reflectionNodeNavigator == null) + { + DeleteNode(inheritDocNodeNavigator, key); + continue; + } + + string group = (string)reflectionNodeNavigator.Evaluate(apiGroupExpression); + string subgroup = (string)reflectionNodeNavigator.Evaluate(apiSubgroupExpression); + + if (group == "type") + { + // Inherit from base types + XPathNodeIterator typeNodeIterator = (XPathNodeIterator)reflectionNodeNavigator.Evaluate(typeExpression); + this.GetComments(typeNodeIterator, inheritDocNodeNavigator); + + // no <inheritdoc /> nodes were found, so continue with next iteration. Otherwise inherit from interface implementation types. + if (this.sourceDocument.CreateNavigator().Select(inheritDocExpression).Count == 0) + { + continue; + } + + // Inherit from interface implementation types + XPathNodeIterator interfaceNodeIterator = (XPathNodeIterator)reflectionNodeNavigator.Evaluate(interfaceImplementationExpression); + this.GetComments(interfaceNodeIterator, inheritDocNodeNavigator); + } + else if (group == "member") + { + // constructors do not have override member information in reflection files, so search all the base types for a matching signature. + if (subgroup == "constructor") + { + string name = (string)reflectionNodeNavigator.Evaluate(apiNameExpression); + string typeApi = (string) reflectionNodeNavigator.Evaluate(containerTypeExpression); + + // no container type api was found, so delete <inheritdoc /> node. + if (string.IsNullOrEmpty(typeApi)) + { + DeleteNode(inheritDocNodeNavigator, key); + continue; + } + + reflectionNodeNavigator = this.reflectionIndex.GetContent(typeApi); + + // no reflection information for container type api was found, so delete <inheritdoc /> node. + if (reflectionNodeNavigator == null) + { + DeleteNode(inheritDocNodeNavigator, key); + continue; + } + + XPathNodeIterator containerIterator = reflectionNodeNavigator.Select(typeExpression); + + foreach (XPathNavigator containerNavigator in containerIterator) + { + string constructorId = string.Format(CultureInfo.InvariantCulture, "M:{0}.{1}", containerNavigator.Value.Substring(2), name.Replace('.', '#')); + XPathNavigator contentNodeNavigator = this.index.GetContent(constructorId); + + if (contentNodeNavigator == null) + { + continue; + } + + this.UpdateNode(inheritDocNodeNavigator, contentNodeNavigator); + + if (this.sourceDocument.CreateNavigator().Select(inheritDocExpression).Count == 0) + { + break; + } + else + { + inheritDocNodeNavigator.MoveTo(this.sourceDocument.CreateNavigator().SelectSingleNode(inheritDocExpression)); + } + } + } + else + { + // Inherit from override members. + XPathNodeIterator memberNodeIterator = (XPathNodeIterator)reflectionNodeNavigator.Evaluate(overrideMemberExpression); + this.GetComments(memberNodeIterator, inheritDocNodeNavigator); + + if (this.sourceDocument.CreateNavigator().Select(inheritDocExpression).Count == 0) + { + continue; + } + + // Inherit from interface implementations members. + XPathNodeIterator interfaceNodeIterator = (XPathNodeIterator)reflectionNodeNavigator.Evaluate(interfaceImplementationMemberExpression); + this.GetComments(interfaceNodeIterator, inheritDocNodeNavigator); + } + } + + // no comments were found, so delete <iheritdoc /> node. + if (this.sourceDocument.CreateNavigator().Select(inheritDocExpression).Count != 0) + { + DeleteNode(inheritDocNodeNavigator, key); + } + } + } + } + + /// <summary> + /// Updates the node replacing inheritdoc node with comments found. + /// </summary> + /// <param name="inheritDocNodeNavigator">Navigator for inheritdoc node</param> + /// <param name="contentNodeNavigator">Navigator for content</param> + public void UpdateNode(XPathNavigator inheritDocNodeNavigator, XPathNavigator contentNodeNavigator) + { + // retrieve the selection filter if specified. + string selectValue = inheritDocNodeNavigator.GetAttribute("select", string.Empty); + + if (!string.IsNullOrEmpty(selectValue)) + { + sourceExpression = XPathExpression.Compile(selectValue); + } + + inheritDocNodeNavigator.MoveToParent(); + + if (inheritDocNodeNavigator.LocalName != "comments" && inheritDocNodeNavigator.LocalName != "element") + { + sourceExpression = XPathExpression.Compile(inheritDocNodeNavigator.LocalName); + } + else + { + inheritDocNodeNavigator.MoveTo(this.sourceDocument.CreateNavigator().SelectSingleNode(inheritDocExpression)); + } + + XPathNodeIterator sources = (XPathNodeIterator) contentNodeNavigator.CreateNavigator().Evaluate(sourceExpression); + inheritDocNodeNavigator.DeleteSelf(); + + // append the source nodes to the target node + foreach (XPathNavigator source in sources) + { + inheritDocNodeNavigator.AppendChild(source); + } + } + + /// <summary> + /// Gets the comments for inheritdoc node. + /// </summary> + /// <param name="iterator">Iterator for API information</param> + /// <param name="inheritDocNodeNavigator">Navigator for inheritdoc node</param> + public void GetComments(XPathNodeIterator iterator, XPathNavigator inheritDocNodeNavigator) + { + foreach (XPathNavigator navigator in iterator) + { + XPathNavigator contentNodeNavigator = this.index.GetContent(navigator.Value); + + if (contentNodeNavigator == null) + { + continue; + } + + this.UpdateNode(inheritDocNodeNavigator, contentNodeNavigator); + + if (this.sourceDocument.CreateNavigator().Select(inheritDocExpression).Count == 0) + { + break; + } + else + { + inheritDocNodeNavigator.MoveTo(this.sourceDocument.CreateNavigator().SelectSingleNode(inheritDocExpression)); + } + } + } + #endregion + } +} diff --git a/tools/Sandcastle/Source/BuildAssembler/CopyComponents/Properties/AssemblyInfo.cs b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3c269cf --- /dev/null +++ b/tools/Sandcastle/Source/BuildAssembler/CopyComponents/Properties/AssemblyInfo.cs @@ -0,0 +1,41 @@ +//-------------------------------------------------------------------------- +// <copyright file="AssemblyInfo.cs" company="Microsoft"> +// Copyright (c) Microsoft Corporation. All rights reserved. +// </copyright> +// <summary>Contains metadata information for the assembly.</summary> +//-------------------------------------------------------------------------- +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CopyComponents")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CopyComponents")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2008")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b14061be-8075-4418-a99f-432362137031")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("2.4.10522.00")] +[assembly: AssemblyFileVersion("2.4.10522.00")] |