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 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 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 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 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 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 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 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); }
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); } }
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))); }
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; } }
private void AddReferenceDatabaseBasicHelper(ArdbVersion version) { AddReferenceDatabase ardb = new AddReferenceDatabase(version); DatabaseAddResult result; // Build and add the sample PackageDatabase PackageDatabase source = PackageDatabaseTests.BuildDefaultSample("V1"); result = CallAddUniqueMembers(ardb, source); // Verify at least something was added int ardbCountFirstAdd = ardb.Count; Assert.IsTrue(result.WasMemberAdded[0].Value); // Add the sample again; verify nothing was added source = PackageDatabaseTests.BuildDefaultSample("V2"); result = CallAddUniqueMembers(ardb, source); Assert.IsFalse(result.WasMemberAdded[0].Value); Assert.AreEqual(ardbCountFirstAdd, ardb.Count); // Add a namespace with a private class; verify nothing added source = PackageDatabaseTests.BuildDefaultSample("V3"); MutableSymbol diagnostics = source.MutableRoot.FindByFullName(BuildDiagnosticsNamespaceFor(source.Identity.PackageName), PackageDatabaseTests.SEPARATOR_CHAR); MutableSymbol internalNs = diagnostics.AddChild(new MutableSymbol("Internal", SymbolType.Namespace)); internalNs.AddChild(new MutableSymbol("Tracer", SymbolType.Class) { Modifiers = SymbolModifier.Internal }); result = CallAddUniqueMembers(ardb, source); Assert.IsFalse(result.WasMemberAdded[0].Value); Assert.AreEqual(ardbCountFirstAdd, ardb.Count); // Add a new public class (existing namespace); verify it is added source = PackageDatabaseTests.BuildDefaultSample("V4"); diagnostics = source.MutableRoot.FindByFullName(BuildDiagnosticsNamespaceFor(source.Identity.PackageName), PackageDatabaseTests.SEPARATOR_CHAR); diagnostics.AddChild(new MutableSymbol("TraceWatch", SymbolType.Class) { Modifiers = SymbolModifier.Public | SymbolModifier.Static }); result = CallAddUniqueMembers(ardb, source); Assert.IsTrue(result.WasMemberAdded[0].Value); Assert.IsTrue(result.WasMemberAdded[result.WasMemberAdded.Length - 1].Value); Assert.AreNotEqual(ardbCountFirstAdd, ardb.Count); // Verify a query [expect Diagnostics. to match Logger, Memory, and TraceWatch ardb.ConvertToImmutable(); VerifyQueryResults(ardb, version); // Double-convert ARDB. Verify queries still work correctly. ardb.ConvertToImmutable(); VerifyQueryResults(ardb, version); // Round trip to string; verify query still right, count matches string sampleArdbFilePath = "Sample.ardb.txt"; Write.ToFile(ardb.WriteText, sampleArdbFilePath); AddReferenceDatabase reloaded = new AddReferenceDatabase(version); Read.FromFile(reloaded.ReadText, sampleArdbFilePath); VerifyQueryResults(reloaded, version); Assert.AreEqual(ardb.Count, reloaded.Count); string sampleRewriteArdbFilePath = "Sample.Rewrite.ardb.txt"; Write.ToFile(reloaded.WriteText, sampleRewriteArdbFilePath); Assert.AreEqual(File.ReadAllText(sampleArdbFilePath), File.ReadAllText(sampleRewriteArdbFilePath)); }