private void WalkMethod(MetadataReader mdReader, MethodDefinitionHandle handle, MutableSymbol parent) { MethodDefinition method = mdReader.GetMethodDefinition(handle); MethodAttributes attributes = method.Attributes; string name = mdReader.GetString(method.Name); MutableSymbol result = new MutableSymbol(name, GetMethodType(attributes, name)); AddModifiers(attributes, result); AddLocation(handle, result); AddParameters(mdReader, method, result); // Make Constructor/Destructors use the type name as the method name [like Ctrl+, search] if (result.Type == SymbolType.Constructor || result.Type == SymbolType.StaticConstructor || result.Type == SymbolType.Destructor) { result.Name = parent.Name.ToString(); } if (IsExcluded(result)) { return; } parent.AddChild(result); // TODO: Identify Extension Methods. Issue: Requires a lot of Blob reading. See http://source.roslyn.io/#q=PEMethodSymbol.IsExtensionMethod, http://source.roslyn.io/#q=PEModule.HasExtensionAttribute }
private void WalkMethod(IMethodSymbol method, MutableSymbol parent) { MutableSymbol result = new MutableSymbol(method.AdjustedName(), GetMethodType(method)); AddModifiers(method, result); AddLocation(method, result); if (this.IncludeSignatures) { result.Parameters = method.MinimalParameters(); } if (IsExcluded(method, result)) { return; } parent.AddChild(result); // Add the extended type under Extension Methods if (result.Type == SymbolType.ExtensionMethod && method.Parameters.Length > 0) { IParameterSymbol thisParameter = method.Parameters[0]; ITypeSymbol thisType = thisParameter.Type; MutableSymbol extendedType = new MutableSymbol(thisType.NamespaceAndName(), SymbolType.ExtendedType); extendedType.Modifiers = result.Modifiers; result.AddChild(extendedType); } }
private void WalkIncremental(string filePath, MutableSymbol parent) { // Copy the old database for this binary if it is older than the old index and we find it if (this.Previous != null) { DateTime binaryModifiedUtc = File.GetLastWriteTimeUtc(filePath); if (binaryModifiedUtc <= this.PreviousWriteUtc) { Symbol oldAssembly; if (TryFindAssembly(Path.GetFileName(filePath), out oldAssembly)) { parent.AddTree(oldAssembly); return; } else if (TryFindAssembly(Path.GetFileNameWithoutExtension(filePath), out oldAssembly)) { parent.AddTree(oldAssembly); return; } } } // Otherwise, recrawl InnerCrawler.Walk(filePath, parent); }
internal static void AddSampleMembers(PackageDatabase db) { MutableSymbol packageRoot = db.MutableRoot.AddChild(new MutableSymbol(db.Identity.PackageName, SymbolType.Package)); AddSampleTypes(packageRoot, NET20, addMemoryType: false); AddSampleTypes(packageRoot, NET35, addMemoryType: true); }
public void Walk(string walkPath, MutableSymbol parent) { string encodedFrameworkNames = null; string[] walkPathTokens = walkPath.Split('\t'); Debug.Assert(walkPathTokens.Length == 1 || walkPathTokens.Length == 2); walkPath = walkPathTokens[0]; if (walkPathTokens.Length > 1) { encodedFrameworkNames = walkPathTokens[1]; } // Index the directory|file list|solution|project|binary string extension = Path.GetExtension(walkPath).ToLowerInvariant(); if (FileIO.IsManagedBinary(walkPath)) { WalkBinary(walkPath, parent, encodedFrameworkNames); } else if (extension.Equals(".sln")) { WalkSolution(walkPath, parent); } else if (extension.EndsWith("proj")) { WalkProject(walkPath, parent); } else { throw new ArgumentException(String.Format("RoslynCompilationCrawler doesn't know how to walk item with extension '{0}'", extension)); } }
private void WalkProject(string projectPath, MutableSymbol parent) { using (MSBuildWorkspace workspace = BuildWorkspace()) { // Open Project with Roslyn var project = workspace.OpenProjectAsync(projectPath).Result; WalkProject(project, parent); } }
private void WalkProject(Project project, MutableSymbol parent) { // Get the consolidated assembly symbols and walk them Compilation rootCompilation = project.GetCompilationAsync().Result; IAssemblySymbol assembly = rootCompilation.Assembly; MutableSymbol assemblyRoot = parent.AddChild(new MutableSymbol(Path.GetFileName(project.OutputFilePath), SymbolType.Assembly)); WalkNamespace(assembly.GlobalNamespace, assemblyRoot); }
private void WalkField(IFieldSymbol field, MutableSymbol parent) { MutableSymbol result = new MutableSymbol(field.Name, GetFieldType(field)); AddModifiers(field, result); AddLocation(field, result); if (!IsExcluded(field, result)) { parent.AddChild(result); } }
private static void AddSampleTypes(MutableSymbol packageRoot, string frameworkTargets, bool addMemoryType) { string fx = frameworkTargets.ToFrameworkNames().First(); MutableSymbol assembly = packageRoot.AddChild(new MutableSymbol(DLL_NAME, SymbolType.Assembly)); MutableSymbol frameworkTarget = assembly.AddChild(new MutableSymbol(frameworkTargets, SymbolType.FrameworkTarget)); MutableSymbol sample = frameworkTarget.AddChild(new MutableSymbol(NS_SAMPLE, SymbolType.Namespace)); MutableSymbol diagnostics = sample.AddChild(new MutableSymbol(NS_DIAGNOSTICS, SymbolType.Namespace)); MutableSymbol logger = diagnostics.AddChild(new MutableSymbol(TYPE_LOGGER, SymbolType.Class) { Modifiers = SymbolModifier.Public, FilePath = @"src\" + fx + @"\Diagnostics\Logger.cs", Line = 8, CharInLine = 18 }); logger.AddChild(new MutableSymbol(TYPE_LOGGER, SymbolType.Constructor) { Modifiers = SymbolModifier.Public, Parameters = "string", FilePath = @"src\" + fx + @"\Diagnostics\Logger.cs", Line = 22, CharInLine = 16 }); logger.AddChild(new MutableSymbol("LogUse", SymbolType.Method) { Modifiers = SymbolModifier.Public, FilePath = @"src\" + fx + @"\Diagnostics\Logger.cs", Line = 32, CharInLine = 21 }); logger.AddChild(new MutableSymbol("LogException", SymbolType.Method) { Modifiers = SymbolModifier.Public, Parameters = "Exception", FilePath = @"src\" + fx + @"\Diagnostics\Logger.cs", Line = 37, CharInLine = 21 }); logger.AddChild(new MutableSymbol("TryLog", SymbolType.Method) { Modifiers = SymbolModifier.Private, Parameters = "string, string", FilePath = @"src\" + fx + @"\Diagnostics\Logger.cs", Line = 44, CharInLine = 22 }); // Nested public types should appear in the IDX but not the ARDB logger.AddChild(new MutableSymbol("NestedPublicType", SymbolType.Class) { Modifiers = SymbolModifier.Public, FilePath = @"src\" + fx + @"\Diagnostics\Logger.cs", Line = 22, CharInLine = 16 }); if (addMemoryType) { MutableSymbol memory = diagnostics.AddChild(new MutableSymbol(TYPE_MEMORY, SymbolType.Class) { Modifiers = SymbolModifier.Public | SymbolModifier.Static, FilePath = @"src\" + fx + @"\Diagnostics\Memory.cs", Line = 5, CharInLine = 25 }); memory.AddChild(new MutableSymbol("MeasureObjectSize", SymbolType.Method) { Modifiers = SymbolModifier.Public | SymbolModifier.Static, Parameters = "Func<object>", FilePath = @"src\" + fx + @"\Diagnostics\Memory.cs", Line = 13, CharInLine = 28 }); memory.AddChild(new MutableSymbol("FromGigabytes", SymbolType.Method) { Modifiers = SymbolModifier.Public | SymbolModifier.Static, Parameters = "double", FilePath = @"src\" + fx + @"\Diagnostics\Memory.cs", Line = 32, CharInLine = 28 }); } }
private bool IsExcluded(MutableSymbol symbolToAdd) { // Exclude members we don't want indexed (backing fields, property get/set methods) if (symbolToAdd.Type == SymbolType.Excluded) { return(true); } // Exclude types which are generated under the covers (IEnumerable worker classes) if (symbolToAdd.Name.StartsWith("<")) { return(true); } // Exclude weird value__ fields appearing on enum types if (symbolToAdd.Name.Equals("value__")) { return(true); } // Exclude constructors for enums [TODO] //if (symbolToAdd.Type == SymbolType.Constructor) //{ // INamedTypeSymbol parentType = symbol.ContainingType.BaseType; // if (parentType != null && parentType.Name.Equals("Enum")) // { // return true; // } //} // Exclude Event add_ and remove_ methods [rolled up in Event] if (symbolToAdd.Type == SymbolType.Method && (symbolToAdd.Name.StartsWith("add_") || symbolToAdd.Name.StartsWith("remove_"))) { if (!this.IncludeSignatures || symbolToAdd.Parameters.Equals("EventHandler")) { return(true); } } // Exclude non-public members *if configured to* if (this.IncludeNonPublicMembers == false) { if (!symbolToAdd.Modifiers.HasFlag(SymbolModifier.Public)) { return(true); } } return(false); }
private void WalkSolution(string solutionPath, MutableSymbol parent) { using (MSBuildWorkspace workspace = BuildWorkspace()) { // Open Solution with Roslyn var solution = workspace.OpenSolutionAsync(solutionPath).Result; // Build assembly symbols for each project in a shared tree foreach (Project project in solution.Projects) { WalkProject(project, parent); } } }
private void WalkField(MetadataReader mdReader, FieldDefinitionHandle handle, MutableSymbol parent) { FieldDefinition field = mdReader.GetFieldDefinition(handle); MutableSymbol result = new MutableSymbol(mdReader.GetString(field.Name), SymbolType.Field); AddModifiers(field.Attributes, result); AddLocation(handle, result); if (IsExcluded(result)) { return; } parent.AddChild(result); }
private bool IsExcluded(ISymbol MutableSymbol, MutableSymbol symbolToAdd) { //// Debugging: Uncomment to stop at MutableSymbol causing trouble //if (MutableSymbol.Name.EndsWith("BackingField")) //{ // Debugger.Break(); //} // Exclude members we don't want indexed (backing fields, property get/set methods) if (symbolToAdd.Type == SymbolType.Excluded) { return(true); } // Exclude types which are generated under the covers (IEnumerable worker classes) if (MutableSymbol.CanBeReferencedByName == false && MutableSymbol is INamedTypeSymbol) { return(true); } // Exclude weird value__ fields appearing on enum types if (MutableSymbol.Name.Equals("value__")) { return(true); } // Exclude constructors for enums if (symbolToAdd.Type == SymbolType.Constructor) { INamedTypeSymbol parentType = MutableSymbol.ContainingType.BaseType; if (parentType != null && parentType.Name.Equals("Enum")) { return(true); } } // Exclude non-public members *if configured to* if (this.IncludeNonPublicMembers == false) { if (!symbolToAdd.Modifiers.HasFlag(SymbolModifier.Public)) { return(true); } } // Include everything else return(false); }
private void WalkType(INamedTypeSymbol symbol, MutableSymbol parent) { // Build this type MutableSymbol result = new MutableSymbol(symbol.Name, GetNamedTypeType(symbol)); AddModifiers(symbol, result); AddLocation(symbol, result); // Stop if it should be excluded if (IsExcluded(symbol, result)) { return; } // Add the type itself MutableSymbol thisSymbol = parent.AddChild(result); // Recurse on members foreach (ISymbol child in symbol.GetMembers()) { if (child is INamedTypeSymbol) { WalkType((INamedTypeSymbol)child, thisSymbol); } else { if (this.IncludeMembers) { if (child is IMethodSymbol) { WalkMethod((IMethodSymbol)child, thisSymbol); } else if (child is IPropertySymbol) { WalkProperty((IPropertySymbol)child, thisSymbol); } else if (child is IFieldSymbol) { WalkField((IFieldSymbol)child, thisSymbol); } else { // Other contents excluded } } } } }
private void AddModifiers(ISymbol MutableSymbol, MutableSymbol result) { SymbolModifier modifiers = SymbolModifier.None; // Convert individual properties if (MutableSymbol.IsStatic) { modifiers |= SymbolModifier.Static; } // Not needed for scenarios. //if (MutableSymbol.IsAbstract) modifiers |= SymbolModifier.Abstract; //if (MutableSymbol.IsExtern) modifiers |= SymbolModifier.Extern; //if (MutableSymbol.IsOverride) modifiers |= SymbolModifier.Override; //if (MutableSymbol.IsSealed) modifiers |= SymbolModifier.Sealed; //if (MutableSymbol.IsVirtual) modifiers |= SymbolModifier.Virtual; // Convert accessibility switch (MutableSymbol.DeclaredAccessibility) { case Accessibility.Public: modifiers |= SymbolModifier.Public; break; case Accessibility.Protected: modifiers |= SymbolModifier.Protected; break; case Accessibility.Private: modifiers |= SymbolModifier.Private; break; case Accessibility.Internal: modifiers |= SymbolModifier.Internal; break; case Accessibility.ProtectedAndInternal: case Accessibility.ProtectedOrInternal: modifiers |= SymbolModifier.Protected | SymbolModifier.Internal; break; default: throw new ArgumentException("Accessibility unhandled: " + MutableSymbol.DeclaredAccessibility.ToString()); } result.Modifiers = modifiers; }
private void WalkType(MetadataReader mdReader, TypeDefinitionHandle handle, MutableSymbol parent) { TypeDefinition type = mdReader.GetTypeDefinition(handle); var attributes = type.Attributes; // Get the name and remove generic suffix (List`1 => List) string metadataName = mdReader.GetString(type.Name); int genericNameSuffixIndex = metadataName.IndexOf('`'); string baseName = (genericNameSuffixIndex < 0 ? metadataName : metadataName.Substring(0, genericNameSuffixIndex)); MutableSymbol result = new MutableSymbol(baseName, GetTypeType(mdReader, type)); AddModifiers(attributes, result); AddLocation(handle, result); if (IsExcluded(result)) { return; } parent.AddChild(result); foreach (TypeDefinitionHandle nestedTypeHandle in type.GetNestedTypes()) { WalkType(mdReader, nestedTypeHandle, result); } if (this.IncludeMembers) { foreach (MethodDefinitionHandle methodHandle in type.GetMethods()) { WalkMethod(mdReader, methodHandle, result); } foreach (FieldDefinitionHandle fieldHandle in type.GetFields()) { WalkField(mdReader, fieldHandle, result); } foreach (PropertyDefinitionHandle propertyHandle in type.GetProperties()) { WalkProperty(mdReader, propertyHandle, result); } // NOTE: type.GetEvents, type.GetInterfaceImplementations are not converted. } }
private void WalkProperty(IPropertySymbol property, MutableSymbol parent) { MutableSymbol result = new MutableSymbol(property.Name, GetPropertyType(property)); AddModifiers(property, result); AddLocation(property, result); if (this.IncludeSignatures) { result.Parameters = property.MinimalParameters(); } if (!IsExcluded(property, result)) { parent.AddChild(result); } }
public PackageDatabase Walk(string walkPath, PackageIdentity identity = null) { // Normalize WalkPath to ensure we can get a name for it walkPath = Path.GetFullPath(walkPath); if (identity == null) { identity = new PackageIdentity(Path.GetFileName(walkPath)); } if (String.IsNullOrEmpty(identity.IndexFileName)) { throw new ArgumentException(String.Format("ERROR: Unable to compute database name for path \"{0}\"", walkPath)); } PackageDatabase db = new PackageDatabase(identity); MutableSymbol packageRoot = db.MutableRoot.AddChild(new MutableSymbol(identity.PackageName, SymbolType.Package)); // Index the directory|file list|solution|project|binary string extension = Path.GetExtension(walkPath).ToLowerInvariant(); if (Directory.Exists(walkPath)) { if (this.IncludeSymbolCacheIndices) { WalkEverythingAndSymbolCache(walkPath, packageRoot); } else { WalkJustMyCode(walkPath, packageRoot); } } else if (extension.Equals(".txt")) { foreach (string itemPath in File.ReadAllLines(walkPath)) { WalkIncremental(itemPath, packageRoot); } } else { InnerCrawler.Walk(walkPath, packageRoot); } return(db); }
private void AddModifiers(TypeAttributes attributes, MutableSymbol symbolToAdd) { SymbolModifier modifiers = symbolToAdd.Modifiers; // Same as Roslyn PENamedTypeSymbol.DeclaredAccessibility switch (attributes & TypeAttributes.VisibilityMask) { case TypeAttributes.NestedAssembly: modifiers = SymbolModifier.Internal; break; case TypeAttributes.NestedFamORAssem: case TypeAttributes.NestedFamANDAssem: modifiers = SymbolModifier.Protected | SymbolModifier.Internal; break; case TypeAttributes.NestedPrivate: modifiers = SymbolModifier.Private; break; case TypeAttributes.Public: case TypeAttributes.NestedPublic: modifiers = SymbolModifier.Public; break; case TypeAttributes.NestedFamily: modifiers = SymbolModifier.Protected; break; case TypeAttributes.NotPublic: modifiers = SymbolModifier.Internal; break; } // Same as Roslyn PENamedTypeSymbol.IsStatic if (attributes.HasFlag(TypeAttributes.Sealed) && attributes.HasFlag(TypeAttributes.Abstract)) { modifiers |= SymbolModifier.Static; } symbolToAdd.Modifiers = modifiers; }
private void WalkProperty(MetadataReader mdReader, PropertyDefinitionHandle handle, MutableSymbol parent) { PropertyDefinition prop = mdReader.GetPropertyDefinition(handle); MutableSymbol result = new MutableSymbol(mdReader.GetString(prop.Name), SymbolType.Property); // Use the accessibility and location of the getter [or setter, if write only property] // Not identical to Roslyn PEPropertyDeclaration but much simpler MethodDefinitionHandle getterOrSetterHandle = prop.GetAccessors().Getter; if (getterOrSetterHandle.IsNil) { getterOrSetterHandle = prop.GetAccessors().Setter; } // If we couldn't retrieve a getter or setter, exclude this property if (getterOrSetterHandle.IsNil) { return; } MethodDefinition getterOrSetter = mdReader.GetMethodDefinition(getterOrSetterHandle); AddModifiers(getterOrSetter.Attributes, result); AddLocation(getterOrSetterHandle, result); AddParameters(mdReader, getterOrSetter, result); // If this is an Indexer, rename it and retype it // Roslyn PEPropertySymbol.IsIndexer is also just based on the name. if (result.Name == "Item") { result.Name = "this[]"; result.Type = SymbolType.Indexer; } if (IsExcluded(result)) { return; } parent.AddChild(result); }
public void Walk(string binaryPath, MutableSymbol parent) { if (!FileIO.IsManagedBinary(binaryPath)) { throw new ArgumentException(String.Format("SrmCrawler doesn't know how to walk file with extension '{0}'", Path.GetExtension(binaryPath))); } FileStream stream = new FileStream(binaryPath, FileMode.Open, FileAccess.Read); // NOTE: Need to keep PEReader alive through crawl to avoid AV in looking up signatures using (PEReader peReader = new PEReader(stream)) { if (peReader.HasMetadata == false) { return; } Trace.WriteLine("\t" + binaryPath); using (PdbSymbolProvider pdbProvider = PdbSymbolProvider.TryBuildProvider(binaryPath)) { PDB = pdbProvider; MutableSymbol assemblyRoot = parent.AddChild(new MutableSymbol(Path.GetFileName(binaryPath), SymbolType.Assembly)); // Walk all non-nested types. Namespaces are derived as found. Nested types will be found during crawl of containing type. MetadataReader mdReader = peReader.GetMetadataReader(); foreach (TypeDefinitionHandle typeHandle in mdReader.TypeDefinitions) { TypeDefinition type = mdReader.GetTypeDefinition(typeHandle); string namespaceString = mdReader.GetString(type.Namespace); if (!type.Attributes.IsNested()) { MutableSymbol ns = assemblyRoot.FindOrAddPath(namespaceString, '.', SymbolType.Namespace); WalkType(mdReader, typeHandle, ns); } } } } }
private void WalkNamespace(INamespaceSymbol ns, MutableSymbol parent) { // Build a MutableSymbol for this namespace; collapse the global namespace right under the binary MutableSymbol thisSymbol = parent; if (!ns.IsGlobalNamespace) { thisSymbol = parent.AddChild(new MutableSymbol(ns.Name, SymbolType.Namespace)); } // Enumerate child namespaces foreach (INamespaceSymbol childNamespace in ns.GetNamespaceMembers()) { WalkNamespace(childNamespace, thisSymbol); } // Enumerate types foreach (INamedTypeSymbol childType in ns.GetTypeMembers()) { WalkType(childType, thisSymbol); } }
private void WalkJustMyCode(string rootPath, MutableSymbol parent) { List <string> justMyCodeBinaries = new List <string>(); // Find each PDB for which we can find the binary and find the first referenced source file using (new TraceWatch("Finding 'Just My Code' binaries...")) { justMyCodeBinaries = JustMyCodeBinaryFinder.FindJustMyCodeUnder(rootPath); } // Index each binary ProgressWriter p = new ProgressWriter(justMyCodeBinaries.Count); using (new TraceWatch("Indexing {0:n0} binaries...", justMyCodeBinaries.Count)) { foreach (string binaryPath in justMyCodeBinaries) { WalkIncremental(binaryPath, parent); p.IncrementProgress(); } } }
private void AddLocation(Handle handle, MutableSymbol symbolToAdd) { if (!this.IncludeCodeLocations) { return; } if (PDB != null) { int token = MetadataTokens.GetToken(handle); // If found, associate the member with the first location found IEnumerable <ILSequencePoint> locations = PDB.GetSequencePointsForMethod(token); foreach (ILSequencePoint location in locations) { symbolToAdd.FilePath = location.Document; symbolToAdd.Line = location.StartLine.TrimToUShort(); symbolToAdd.CharInLine = location.StartCharInLine.TrimToUShort(); return; } } }
private void AddLocation(ISymbol symbol, MutableSymbol symbolToAdd) { if (this.IncludeCodeLocations) { // Get MutableSymbol declaration location from Roslyn, if available if (symbol.Locations.Length != 0) { if (symbol.Locations[0].IsInSource) { // Roslyn locations are zero-based. Correct to normal positions. FileLinePositionSpan location = symbol.Locations[0].GetLineSpan(); symbolToAdd.FilePath = location.Path; symbolToAdd.Line = (location.StartLinePosition.Line + 1).TrimToUShort(); symbolToAdd.CharInLine = (location.StartLinePosition.Character + 1).TrimToUShort(); return; } } // Get MutableSymbol declaration location from the PDB, if available if (PDB != null) { MethodDefinitionHandle handle = symbol.GetMethodDefinitionHandle(); if (!handle.IsNil) { int token = MetadataTokens.GetToken(handle); // If found, associate the member with the first location found ILSequencePoint location; if (PDB.TryGetFirstPointForMethod(token, out location)) { symbolToAdd.FilePath = location.Document; symbolToAdd.Line = location.StartLine.TrimToUShort(); symbolToAdd.CharInLine = location.StartCharInLine.TrimToUShort(); } } } } }
private void AddModifiers(FieldAttributes attributes, MutableSymbol symbolToAdd) { SymbolModifier modifiers = symbolToAdd.Modifiers; // Same as Roslyn PEFieldSymbol.DeclaredAccessibility switch (attributes & FieldAttributes.FieldAccessMask) { case FieldAttributes.Assembly: modifiers = SymbolModifier.Internal; break; case FieldAttributes.FamORAssem: case FieldAttributes.FamANDAssem: modifiers = SymbolModifier.Protected | SymbolModifier.Internal; break; case FieldAttributes.Private: case FieldAttributes.PrivateScope: modifiers = SymbolModifier.Private; break; case FieldAttributes.Public: modifiers = SymbolModifier.Public; break; case FieldAttributes.Family: modifiers = SymbolModifier.Protected; break; } if (attributes.HasFlag(FieldAttributes.Static)) { modifiers |= SymbolModifier.Static; } symbolToAdd.Modifiers = modifiers; }
private void AddParameters(MetadataReader mdReader, MethodDefinition method, MutableSymbol result) { if (!this.IncludeSignatures) { return; } StringBuilder parameterString = new StringBuilder(); StringSignatureProvider provider = new StringSignatureProvider(mdReader, mdReader.GetTypeDefinition(method.GetDeclaringType()), method); MethodSignature <string> signature = method.DecodeSignature <string, DisassemblingGenericContext>(provider, null); foreach (string value in signature.ParameterTypes) { if (parameterString.Length > 0) { parameterString.Append(", "); } parameterString.Append(value); } result.Parameters = parameterString.ToString(); }
public void Walk(string filePath, MutableSymbol parent) { this.Count++; this.InnerCrawler.Walk(filePath, parent); }
private void WalkBinary(string binaryPath, MutableSymbol parent, string encodedFrameworkNames) { // Add the binary as a reference to resolve symbols in it MetadataReference reference = MetadataReference.CreateFromFile(binaryPath); CSharpCompilationOptions compilationOptions = new CSharpCompilationOptions( outputKind: OutputKind.ConsoleApplication, reportSuppressedDiagnostics: false); compilationOptions.SetMetadataImportOptions(MetadataImportOptions.All); // Create an empty binary to 'host' the reference CSharpCompilation emptyCompilation = CSharpCompilation.Create("Empty.exe", references: new[] { reference }, options: compilationOptions); // Get the root of the reference specifically ISymbol referenceRootSymbol = emptyCompilation.GetAssemblyOrModuleSymbol(reference); // If this wasn't a managed assembly, don't add anything if (referenceRootSymbol == null) { return; } string assemblyName = null; INamespaceSymbol globalNamespace = null; if (referenceRootSymbol is IAssemblySymbol) { // NOTE: Use the Assembly.Identity.Name specifically as the root to allow VS to identify binaries (potentially) already referenced safely. assemblyName = ((IAssemblySymbol)referenceRootSymbol).Identity.Name; globalNamespace = ((IAssemblySymbol)referenceRootSymbol).GlobalNamespace; } else if (referenceRootSymbol is IModuleSymbol) { assemblyName = Path.GetFileName(binaryPath); globalNamespace = ((IModuleSymbol)referenceRootSymbol).GlobalNamespace; } else { // Unable to crawl if we didn't find an assembly or module Trace.WriteLine(String.Format("ERROR: Unable to crawl binary with root symbol type '{0}'", referenceRootSymbol.GetType().Name)); return; } // Walk the binary MutableSymbol addUnderRoot = parent.AddChild(new MutableSymbol(assemblyName, SymbolType.Assembly)); // Add the target framework [if requested and identifiable] if (this.IncludeFrameworkTargets) { if (!String.IsNullOrEmpty(encodedFrameworkNames)) { addUnderRoot = addUnderRoot.AddChild(new MutableSymbol(encodedFrameworkNames, SymbolType.FrameworkTarget)); } } // PRIVATE ROSLYN: Attempt to build a PDB reader for the binary using (PdbSymbolProvider pdbProvider = PdbSymbolProvider.TryBuildProvider(binaryPath)) { PDB = pdbProvider; WalkNamespace(globalNamespace, addUnderRoot); // Remove the PdbSymbolProvider PDB = null; } }
public void MergedMembersDatabase_Merging() { MergedMembersDatabase db = new MergedMembersDatabase(); DatabaseAddResult result; string lastAddResult; PackageDatabase source = PackageDatabaseTests.BuildDefaultSample(); source.Identity.PackageName = "V1"; result = db.Add(source, ArdbVersion.Current); lastAddResult = Write.ToString(result.WriteMemberResults); Trace.WriteLine("First Sample Import:\r\n" + lastAddResult); Trace.WriteLine(Write.ToString(result.WriteDuplicateComponents)); // Sample has at least one unique thing Assert.IsTrue(result.WasMemberAdded[0].Value); // Memory class is included Assert.IsTrue(result.WasMemberAdded[ItemTreeTests.FindByPath(source.DeclaredMembers, source.StringStore, DIAGNOSTICS_NAMESPACE_REF35 + "|Memory", PackageDatabaseTests.SEPARATOR_CHAR)].Value); // FromGigabytes member is ignored (not a type) Assert.IsFalse(result.WasMemberAdded[ItemTreeTests.FindByPath(source.DeclaredMembers, source.StringStore, DIAGNOSTICS_NAMESPACE_REF35 + "|Memory|FromGigabytes", PackageDatabaseTests.SEPARATOR_CHAR)].HasValue); // Add the source again (a complete duplicate) source.Identity.PackageName = "V2"; result = db.Add(source, ArdbVersion.Current); lastAddResult = Write.ToString(result.WriteMemberResults); Trace.WriteLine("Duplicate Sample Import:\r\n" + lastAddResult); Trace.WriteLine(Write.ToString(result.WriteDuplicateComponents)); // Verify nothing is unique this time Assert.IsFalse(result.WasMemberAdded[0].Value); // Add a new public class to the sample (should be added) MutableSymbol diagnostics = source.MutableRoot.FindByFullName(DIAGNOSTICS_NAMESPACE_LIB20, PackageDatabaseTests.SEPARATOR_CHAR); diagnostics.AddChild(new MutableSymbol("TraceWatch", SymbolType.Class) { Modifiers = SymbolModifier.Public | SymbolModifier.Static }); // Add a new method to Logger (no effect) MutableSymbol logger = source.MutableRoot.FindByFullName(DIAGNOSTICS_NAMESPACE_LIB20 + "|Logger", PackageDatabaseTests.SEPARATOR_CHAR); logger.AddChild(new MutableSymbol("LogTime", SymbolType.Method) { Modifiers = SymbolModifier.Public }); // Add the source with additions, verify something is new source.Identity.PackageName = "V3"; result = db.Add(source, ArdbVersion.Current); lastAddResult = Write.ToString(result.WriteMemberResults); Trace.WriteLine("Sample with additions Import:\r\n" + lastAddResult); Trace.WriteLine(Write.ToString(result.WriteDuplicateComponents)); Assert.IsTrue(result.WasMemberAdded[0].Value); // Verify Diagnostics contains changes Assert.IsTrue(result.WasMemberAdded[ItemTreeTests.FindByPath(source.DeclaredMembers, source.StringStore, DIAGNOSTICS_NAMESPACE_LIB20, PackageDatabaseTests.SEPARATOR_CHAR)].Value); // Verify Logger wasn't considered changed Assert.IsFalse(result.WasMemberAdded[ItemTreeTests.FindByPath(source.DeclaredMembers, source.StringStore, TYPE_LOGGER, PackageDatabaseTests.SEPARATOR_CHAR)].Value); // Add a new private class to the sample (should not be added) diagnostics.AddChild(new MutableSymbol("SmartTimer", SymbolType.Class) { Modifiers = SymbolModifier.Internal }); // Add the source again, verify nothing is new source.Identity.PackageName = "V4"; result = db.Add(source, ArdbVersion.Current); lastAddResult = Write.ToString(result.WriteMemberResults); Trace.WriteLine("Sample with private class Import:\r\n" + lastAddResult); Trace.WriteLine(Write.ToString(result.WriteDuplicateComponents)); Assert.IsFalse(result.WasMemberAdded[0].Value); Trace.WriteLine(Write.ToString((w) => db.WriteMergedTree(w))); }