public IAssemblyReference Map(IAssemblySymbol assembly) { Contract.Requires(assembly != null); Contract.Ensures(Contract.Result <IAssemblyReference>() != null); IAssemblyReference cciAssembly = null; if (!assemblySymbolCache.TryGetValue(assembly, out cciAssembly)) { var an = assembly.Identity; IEnumerable <byte> pkt = an.PublicKeyToken.AsEnumerable(); if (pkt == null) { pkt = new byte[0]; } var identity = new Microsoft.Cci.AssemblyIdentity( this.nameTable.GetNameFor(an.Name), an.CultureName == null ? "" : an.CultureName, // REVIEW: This can't be right an.Version, pkt, "unknown://location" // BUGBUG an.Location == null ? "unknown://location" : an.Location ); cciAssembly = new Microsoft.Cci.Immutable.AssemblyReference(this.host, identity); assemblySymbolCache[assembly] = cciAssembly; } Contract.Assume(cciAssembly != null); return(cciAssembly); }
public IAssemblyReference Map(R.IAssemblySymbol assembly) { Contract.Requires(assembly != null); Contract.Ensures(Contract.Result<IAssemblyReference>() != null); IAssemblyReference cciAssembly = null; if (!assemblySymbolCache.TryGetValue(assembly, out cciAssembly)) { var an = assembly.Identity; IEnumerable<byte> pkt = an.PublicKeyToken.AsEnumerable(); if (pkt == null) pkt = new byte[0]; var identity = new Microsoft.Cci.AssemblyIdentity( this.nameTable.GetNameFor(an.Name), an.CultureName == null ? "" : an.CultureName, // REVIEW: This can't be right an.Version, pkt, an.Location == null ? "unknown://location" : an.Location ); cciAssembly = new Microsoft.Cci.Immutable.AssemblyReference(this.host, identity); assemblySymbolCache[assembly] = cciAssembly; } Contract.Assume(cciAssembly != null); return cciAssembly; }
void DoWork() { string assemblyName; Version assemblyVersion; string assemblyLocation; string typeName; int genericParameterCount; GetNecessaryInfo(out assemblyName, out assemblyVersion, out assemblyLocation, out typeName, out genericParameterCount); #region Create host var host = this._projectTracker.Host; if (host == null) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't create host."); return; } #endregion #region Find and load assembly IAssembly iAssembly = null; if (assemblyName.Equals(host.CoreAssemblySymbolicIdentity.Name.Value, StringComparison.OrdinalIgnoreCase) && assemblyVersion.Equals(host.CoreAssemblySymbolicIdentity.Version)) { iAssembly = host.FindAssembly(host.CoreAssemblySymbolicIdentity); } else { var references = _projectTracker.References; VSLangProj.Reference reference = null; var assemblyNameWithoutExtension = Path.GetFileNameWithoutExtension(assemblyName); for (int i = 1; i <= references.Count; i++)//TODO: Unify this code. This process of looking up a reference from a name is also done in ContractsProvider.TryGetAssemblyReference { var tempRef = references.Item(i); string refName = tempRef.Name; if (refName.Equals(assemblyNameWithoutExtension, StringComparison.OrdinalIgnoreCase)) { reference = tempRef; break; } } if (reference != null) { IName iName = host.NameTable.GetNameFor(Path.GetFileNameWithoutExtension(reference.Path)); string culture = reference.Culture; Version version = new Version(reference.MajorVersion, reference.MinorVersion, reference.BuildNumber, reference.RevisionNumber); string location = reference.Path; var tempRef2 = new Microsoft.Cci.Immutable.AssemblyReference(host, new AssemblyIdentity(iName, culture, version, Enumerable <byte> .Empty, location)); iAssembly = host.LoadAssembly(tempRef2.AssemblyIdentity); } else { VSServiceProvider.Current.Logger.WriteToLog("Couldn't find reference for metadata file."); return; } } if (iAssembly == null || iAssembly == Dummy.Assembly) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't get assembly for metadata file."); return; } #endregion #region Get contracts provider var contractsProvider = host.GetContractExtractor(iAssembly.UnitIdentity); if (contractsProvider == null) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't get contracts provider."); return; } #endregion #region Collect contracts var type = UnitHelper.FindType(host.NameTable, iAssembly, typeName, genericParameterCount); if (type == null || type is Dummy) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't find metadata type '" + typeName + "' in assembly."); return; } //This dictionaries will map the method/property signature to the contracts for the method/property var methodsToContracts = new Dictionary <string, IMethodContract>(type.Methods.Count()); var gettersToContracts = new Dictionary <string, IMethodContract>(); var settersToContracts = new Dictionary <string, IMethodContract>(); //Set the formatting options for property getters and setters var propertySignatureFormattingOptions = NameFormattingOptions.OmitContainingNamespace | // NameFormattingOptions.ReturnType | NameFormattingOptions.TypeParameters | NameFormattingOptions.UseTypeKeywords | NameFormattingOptions.OmitContainingType; //NameFormattingOptions.Visibility; //Set the formating options for methods var methodSignatureFormattingOptions = NameFormattingOptions.OmitContainingNamespace | NameFormattingOptions.ReturnType | NameFormattingOptions.ParameterName | NameFormattingOptions.ParameterModifiers | NameFormattingOptions.TypeParameters | NameFormattingOptions.UseTypeKeywords | NameFormattingOptions.OmitContainingType | //NameFormattingOptions.Modifiers | NameFormattingOptions.Signature //NameFormattingOptions.Visibility ; //var sourceEmitterOutput = new SourceEmitterOutputString();//TODO: Use source emitter for all my printing? Instead of the whole NameFormattingOptions ordeal. //var csSourceEmitter = new SourceEmitter(sourceEmitterOutput); foreach (var method in type.Methods) { var methodContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(host, method); if (methodContract != null && methodContract != ContractDummy.MethodContract) { if (IsGetter(method)) { if (method.ParameterCount > 0) //We have an indexer! { var indexerSignature = PrintIndexer(method, true); gettersToContracts.Add(indexerSignature, methodContract); } else { var getterSignature = MemberHelper.GetMemberSignature(method, propertySignatureFormattingOptions);//Example: "XmlSchemaSet Schemas.get" getterSignature = getterSignature.Substring(0, getterSignature.LastIndexOf('.')); gettersToContracts.Add(getterSignature, methodContract); } } else if (IsSetter(method)) { if (method.ParameterCount > 1) //We have an indexer! { var indexerSignature = PrintIndexer(method, false); settersToContracts.Add(indexerSignature, methodContract); } else { var setterSignature = MemberHelper.GetMemberSignature(method, propertySignatureFormattingOptions); setterSignature = setterSignature.Substring(0, setterSignature.LastIndexOf('.')); settersToContracts.Add(setterSignature, methodContract); } } else { //#region Print method, stolen from CSharpSourceEmitter //csSourceEmitter.PrintMethodDefinitionVisibility(method); //csSourceEmitter.PrintMethodDefinitionModifiers(method); //bool conversion = csSourceEmitter.IsConversionOperator(method); //if (!conversion) { // csSourceEmitter.PrintMethodDefinitionReturnType(method); // if (!method.IsConstructor && !csSourceEmitter.IsDestructor(method)) // csSourceEmitter.PrintToken(CSharpToken.Space); //} //csSourceEmitter.PrintMethodDefinitionName(method); //if (conversion) // csSourceEmitter.PrintMethodDefinitionReturnType(method); //if (method.IsGeneric) { // csSourceEmitter.Traverse(method.GenericParameters); //} //csSourceEmitter.Traverse(method.Parameters); //#endregion //var methodSignature = sourceEmitterOutput.Data; //sourceEmitterOutput.ClearData(); var methodSignature = MemberHelper.GetMemberSignature(method, methodSignatureFormattingOptions);//Example: "XmlAttribute CreateAttribute(string name)" methodsToContracts.Add(methodSignature, methodContract); } } } #endregion var hasMethodContracts = methodsToContracts.Count > 0; var hasPropertyContracts = gettersToContracts.Count > 0 || settersToContracts.Count > 0; if (!hasMethodContracts && !hasPropertyContracts) { VSServiceProvider.Current.Logger.WriteToLog("No contracts found."); return; } int propertyCounter = 0; //Counts the number of adornments added for property contracts int methodCounter = 0; //Counts the number of adornments added for method contracts foreach (var line in _textView.TextSnapshot.Lines) { var lineText = line.GetText(); //Skip lines with comments //This assumes that no method/property decelerations in metadata files will have comments in them if (lineText.Contains("//")) { continue; } // bail out on nested types var typeNameMatch = Regex.Match(lineText, @"(class|struct|interface|enum) (\w+)"); if (typeNameMatch.Success) { if (typeNameMatch.Groups[2].Value == type.Name.Value) { continue; } break; } if (hasPropertyContracts && lineText.Contains('{') && (lineText.Contains(" get; ") || lineText.Contains(" set; ")) && lineText.Contains('}')) //Check if line is a property decleration { #region Add property contracts //Parse the property decleration to get a signature we can compare to our contract dictionaries //Example of a property decleration: " public int Build { get; }" int endOfSig = lineText.IndexOf('{') - 1; int startOfSig = endOfSig - 1; bool hasHitSpace = false; bool isInPropertyParameter = false; for (int i = startOfSig; i > 0; i--) { char c = lineText[i]; if (c == ']') { isInPropertyParameter = true; } else if (c == '[') { isInPropertyParameter = false; } else if (hasHitSpace && c == ' ') { startOfSig = i + 1; break; } else if (!isInPropertyParameter && c == ' ') { startOfSig = i + 1; break; // MAF: ignore return type of properties. //hasHitSpace = true; } } var propertySignature = lineText.Substring(startOfSig, endOfSig - startOfSig); //Example: "int Build" IMethodContract getterContract = null; IMethodContract setterContract = null; if (gettersToContracts.TryGetValue(propertySignature, out getterContract) | // yes eager evaluation!!! settersToContracts.TryGetValue(propertySignature, out setterContract)) { var tag = propertySignature.GetHashCode();//We use this to uniquely identify the particular method/property decleration //Find this first non-whitespace character. This is were we'll place the adornment. int firstNonWhitespace = 0; for (int i = 0; i < lineText.Length; i++) { char c = lineText[i]; if (c != ' ') { firstNonWhitespace = i; break; } } var span = _textView.TextSnapshot.CreateTrackingSpan(line.Start + firstNonWhitespace, propertySignature.Length, SpanTrackingMode.EdgeExclusive); _vsTextProperties.LineHeight = _textView.LineHeight; var ops = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage); var adornment = new MetadataContractAdornment(span, _vsTextProperties, VSServiceProvider.Current.Logger, _adornmentManager.QueueRefreshLineTransformer, ops); adornment.SetContracts(getterContract, setterContract, null /* "Contracts from " + typeName + "." */); _adornmentManager.AddAdornment(adornment, tag); propertyCounter++; } #endregion continue; } if (hasMethodContracts && lineText.Contains('(') && lineText.Contains(')') && lineText.Contains(';')) //Check if line is a method decleration { #region Add method contracts //Parse the method decleration to get a signature we can compare to our contract dictionaries //Example of a method decleration: " public static Version Parse(string input);" int endOfSig = lineText.LastIndexOf(')') + 1; //int startOfSig = !Char.IsWhiteSpace(lineText[0]) ? 0 : lineText.IndexOf(lineText.First(c => !Char.IsWhiteSpace(c))); //int startOfSig = lineText.IndexOf('('); //bool hitSpace = false; //for (int i = startOfSig; i > 0; i--) { // char c = lineText[i]; // if (c == ' ' && hitSpace) { // startOfSig = i + 1; // break; // } else if (c == ' ') { // hitSpace = true; // } //} var methodSignature = lineText.Substring(0, endOfSig); //Example: "Version Parse(string input)" // remove modifiers methodSignature = Regex.Replace(methodSignature, modifierFilter, ""); methodSignature = methodSignature.Trim(); if (methodSignature.StartsWith(type.Name.Value + "(")) { methodSignature = "void .ctor" + methodSignature.Substring(type.Name.Value.Length); } IMethodContract methodContract; if (methodsToContracts.TryGetValue(methodSignature, out methodContract)) { var tag = methodSignature.GetHashCode();//We use this to uniquely identify the particular method/property decleration //Find this first non-whitespace character. This is were we'll place the adornment. int firstNonWhitespace = 0; for (int i = 0; i < lineText.Length; i++) { char c = lineText[i]; if (c != ' ') { firstNonWhitespace = i; break; } } var span = _textView.TextSnapshot.CreateTrackingSpan(line.Start + firstNonWhitespace, methodSignature.Length, SpanTrackingMode.EdgeExclusive); _vsTextProperties.LineHeight = _textView.LineHeight; var ops = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage); var adornment = new MetadataContractAdornment(span, _vsTextProperties, VSServiceProvider.Current.Logger, _adornmentManager.QueueRefreshLineTransformer, ops); adornment.SetContracts(methodContract, "Contracts from " + typeName + "."); _adornmentManager.AddAdornment(adornment, tag); //if (methodContract.IsPure) { // var purityAdornment = new PurityAdornment(_vsTextProperties, adornment); // //_adornmentManager.AddAdornment(purityAdornment, null); //} methodCounter++; } #endregion continue; } } #region Add button to collapse all contracts if (propertyCounter > 0 || methodCounter > 0) { var button = new Button(); button.Content = "Hide all contracts"; button.Click += OnCollapseAllClick; button.Cursor = Cursors.Hand; var collapseAllAdornment = new StaticAdornment(false, 10d, true, 10d, button); _adornmentManager.AddStaticAdornment(collapseAllAdornment); } #endregion }
public bool TryGetAssemblyReference(IAssemblySymbol semanticAssembly, out IAssemblyReference cciAssembly) { Contract.Ensures(!Contract.Result<bool>() || Contract.ValueAtReturn(out cciAssembly) != null); cciAssembly = null; #region Check input if (semanticAssembly == null) { return false; } #endregion #region Check cache if (ContractsPackageAccessor.Current.VSOptionsPage.Caching) if (_semanticAssemblysToCCIAssemblys.TryGetValue(semanticAssembly, out cciAssembly)) return cciAssembly != Dummy.AssemblyReference && cciAssembly != null; #endregion // distinguish between the AssemblyName and the ProjectName var semanticAssemblyFileName = (semanticAssembly.Name == null) ? null : semanticAssembly.Name; if (string.IsNullOrWhiteSpace(semanticAssemblyFileName)) return false; var semanticAssemblyName = Path.GetFileName(semanticAssemblyFileName); if (semanticAssemblyName.EndsWith(".dll") || semanticAssemblyName.EndsWith(".exe")) semanticAssemblyName = semanticAssemblyName.Remove(semanticAssemblyName.Length - 4, 4); #region Try to get assembly from previously loaded assemblies from host foreach (var unit in Host.LoadedUnits) { if (unit == null) continue; if (unit is Dummy) continue; if (unit.Name.Value == semanticAssemblyName) { cciAssembly = (IAssemblyReference)unit; if (cciAssembly.ResolvedAssembly.Location == semanticAssemblyFileName) { goto ReturnTrue; } } } #endregion #region Check if assembly is the same as the current project's output assembly if (_projectTracker.AssemblyIdentity != null && _projectTracker.AssemblyIdentity.Name != null) { if (semanticAssemblyName.Equals(_projectTracker.AssemblyIdentity.Name.Value, StringComparison.OrdinalIgnoreCase) || semanticAssemblyName.Equals(_projectTracker.ProjectName, StringComparison.OrdinalIgnoreCase)) { cciAssembly = new Microsoft.Cci.Immutable.AssemblyReference(this.Host, _projectTracker.AssemblyIdentity); Host.AddLibPath(Path.Combine(Path.GetDirectoryName(semanticAssemblyFileName), "CodeContracts")); Host.AddLibPath(Path.Combine(Path.GetDirectoryName(semanticAssemblyFileName), @"..\Debug\CodeContracts")); goto ReturnTrue; } } else ContractsPackageAccessor.Current.Logger.WriteToLog("Assembly identity for the project: " + _projectTracker.ProjectName + " was null."); #endregion #region Build assembly reference if (semanticAssembly.Name == null || string.IsNullOrWhiteSpace(semanticAssembly.Name)) goto ReturnFalseNoOutput; // because we have no name. var projectName = Path.GetFileName(semanticAssembly.Name); if (projectName.EndsWith(".dll") || projectName.EndsWith(".exe")) projectName = projectName.Remove(projectName.Length - 4, 4); var references = _projectTracker.References; VSLangProj.Reference reference = null; for (int i = 1, refcount = references == null ? 0 : references.Count; i <= refcount; i++) { var tempRef = references.Item(i); if (tempRef == null) continue; string refName = tempRef.Name;//Path.GetFileNameWithoutExtension(tempRef.Name); if (refName == null) continue; if (refName.Equals(projectName, StringComparison.OrdinalIgnoreCase)) { reference = tempRef; break; } } if (reference != null) { IName iName = Host.NameTable.GetNameFor(Path.GetFileNameWithoutExtension(reference.Path)); string culture = reference.Culture ?? "en"; Version version = new Version(reference.MajorVersion, reference.MinorVersion, reference.BuildNumber, reference.RevisionNumber); string location = reference.Path; if (!string.IsNullOrEmpty(location)) { Host.AddLibPath(Path.Combine(location.Substring(0, location.Length - Path.GetFileName(location).Length), "CodeContracts")); var assemblyIdentity = new AssemblyIdentity(iName, culture, version, Enumerable<byte>.Empty, location); cciAssembly = new Microsoft.Cci.Immutable.AssemblyReference(this.Host, assemblyIdentity); goto ReturnTrue; } } goto ReturnFalse; #endregion #region ReturnTrue: ReturnTrue: if (ContractsPackageAccessor.Current.VSOptionsPage.Caching) _semanticAssemblysToCCIAssemblys[semanticAssembly] = cciAssembly; EnsureAssemblyIsLoaded(semanticAssembly, ref cciAssembly); return true; #endregion #region ReturnFalse: ReturnFalse: ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to build assembly reference for: " + semanticAssembly.Name); ReturnFalseNoOutput: if (ContractsPackageAccessor.Current.VSOptionsPage.Caching) _semanticAssemblysToCCIAssemblys[semanticAssembly] = Dummy.AssemblyReference; return false; #endregion }
public bool TryGetAssemblyReference(CSharpAssembly semanticAssembly, out IAssemblyReference cciAssembly) { Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out cciAssembly) != null); cciAssembly = null; #region Check input if (semanticAssembly == null) { return(false); } #endregion #region Check cache if (ContractsPackageAccessor.Current.VSOptionsPage.Caching) { if (_semanticAssemblysToCCIAssemblys.TryGetValue(semanticAssembly, out cciAssembly)) { return(cciAssembly != Dummy.AssemblyReference && cciAssembly != null); } } #endregion // distinguish between the AssemblyName and the ProjectName var semanticAssemblyFileName = semanticAssembly.BinaryFileName.Value ?? ((semanticAssembly.Name == null) ? null : semanticAssembly.Name.Text); if (string.IsNullOrWhiteSpace(semanticAssemblyFileName)) { return(false); } var semanticAssemblyName = Path.GetFileName(semanticAssemblyFileName); if (semanticAssemblyName.EndsWith(".dll") || semanticAssemblyName.EndsWith(".exe")) { semanticAssemblyName = semanticAssemblyName.Remove(semanticAssemblyName.Length - 4, 4); } #region Try to get assembly from previously loaded assemblies from host foreach (var unit in Host.LoadedUnits) { if (unit == null) { continue; } if (unit is Dummy) { continue; } if (unit.Name.Value == semanticAssemblyName) { cciAssembly = (IAssemblyReference)unit; if (cciAssembly.ResolvedAssembly.Location == semanticAssemblyFileName) { goto ReturnTrue; } } } #endregion #region Check if assembly is the same as the current project's output assembly if (_projectTracker.AssemblyIdentity != null && _projectTracker.AssemblyIdentity.Name != null) { if (semanticAssemblyName.Equals(_projectTracker.AssemblyIdentity.Name.Value, StringComparison.OrdinalIgnoreCase) || semanticAssemblyName.Equals(_projectTracker.ProjectName, StringComparison.OrdinalIgnoreCase)) { cciAssembly = new Microsoft.Cci.Immutable.AssemblyReference(this.Host, _projectTracker.AssemblyIdentity); Host.AddLibPath(Path.Combine(Path.GetDirectoryName(semanticAssemblyFileName), "CodeContracts")); Host.AddLibPath(Path.Combine(Path.GetDirectoryName(semanticAssemblyFileName), @"..\Debug\CodeContracts")); goto ReturnTrue; } } else { ContractsPackageAccessor.Current.Logger.WriteToLog("Assembly identity for the project: " + _projectTracker.ProjectName + " was null."); } #endregion #region Build assembly reference if (semanticAssembly.Name == null || string.IsNullOrWhiteSpace(semanticAssembly.Name.Text)) { goto ReturnFalseNoOutput; // because we have no name. } var projectName = Path.GetFileName(semanticAssembly.Name.Text); if (projectName.EndsWith(".dll") || projectName.EndsWith(".exe")) { projectName = projectName.Remove(projectName.Length - 4, 4); } var references = _projectTracker.References; VSLangProj.Reference reference = null; for (int i = 1, refcount = references == null ? 0 : references.Count; i <= refcount; i++) { var tempRef = references.Item(i); if (tempRef == null) { continue; } string refName = tempRef.Name;//Path.GetFileNameWithoutExtension(tempRef.Name); if (refName == null) { continue; } if (refName.Equals(projectName, StringComparison.OrdinalIgnoreCase)) { reference = tempRef; break; } } if (reference != null) { IName iName = Host.NameTable.GetNameFor(Path.GetFileNameWithoutExtension(reference.Path)); string culture = reference.Culture ?? "en"; Version version = new Version(reference.MajorVersion, reference.MinorVersion, reference.BuildNumber, reference.RevisionNumber); string location = reference.Path; if (!string.IsNullOrEmpty(location)) { Host.AddLibPath(Path.Combine(location.Substring(0, location.Length - Path.GetFileName(location).Length), "CodeContracts")); var assemblyIdentity = new AssemblyIdentity(iName, culture, version, Enumerable <byte> .Empty, location); cciAssembly = new Microsoft.Cci.Immutable.AssemblyReference(this.Host, assemblyIdentity); goto ReturnTrue; } } goto ReturnFalse; #endregion #region ReturnTrue: ReturnTrue: if (ContractsPackageAccessor.Current.VSOptionsPage.Caching) { _semanticAssemblysToCCIAssemblys[semanticAssembly] = cciAssembly; } EnsureAssemblyIsLoaded(semanticAssembly, ref cciAssembly); return(true); #endregion #region ReturnFalse: ReturnFalse: ContractsPackageAccessor.Current.Logger.WriteToLog("Failed to build assembly reference for: " + semanticAssembly.Name.Text); ReturnFalseNoOutput: if (ContractsPackageAccessor.Current.VSOptionsPage.Caching) { _semanticAssemblysToCCIAssemblys[semanticAssembly] = Dummy.AssemblyReference; } return(false); #endregion }
void DoWork() { string assemblyName; Version assemblyVersion; string assemblyLocation; string typeName; int genericParameterCount; GetNecessaryInfo(out assemblyName, out assemblyVersion, out assemblyLocation, out typeName, out genericParameterCount); #region Create host var host = this._projectTracker.Host; if (host == null) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't create host."); return; } #endregion #region Find and load assembly IAssembly iAssembly = null; if (assemblyName.Equals(host.CoreAssemblySymbolicIdentity.Name.Value, StringComparison.OrdinalIgnoreCase) && assemblyVersion.Equals(host.CoreAssemblySymbolicIdentity.Version)) { iAssembly = host.FindAssembly(host.CoreAssemblySymbolicIdentity); } else { var references = _projectTracker.References; VSLangProj.Reference reference = null; var assemblyNameWithoutExtension = Path.GetFileNameWithoutExtension(assemblyName); for (int i = 1; i <= references.Count; i++) {//TODO: Unify this code. This process of looking up a reference from a name is also done in ContractsProvider.TryGetAssemblyReference var tempRef = references.Item(i); string refName = tempRef.Name; if (refName.Equals(assemblyNameWithoutExtension, StringComparison.OrdinalIgnoreCase)) { reference = tempRef; break; } } if (reference != null) { IName iName = host.NameTable.GetNameFor(Path.GetFileNameWithoutExtension(reference.Path)); string culture = reference.Culture; Version version = new Version(reference.MajorVersion, reference.MinorVersion, reference.BuildNumber, reference.RevisionNumber); string location = reference.Path; var tempRef2 = new Microsoft.Cci.Immutable.AssemblyReference(host, new AssemblyIdentity(iName, culture, version, Enumerable<byte>.Empty, location)); iAssembly = host.LoadAssembly(tempRef2.AssemblyIdentity); } else { VSServiceProvider.Current.Logger.WriteToLog("Couldn't find reference for metadata file."); return; } } if (iAssembly == null || iAssembly == Dummy.Assembly) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't get assembly for metadata file."); return; } #endregion #region Get contracts provider var contractsProvider = host.GetContractExtractor(iAssembly.UnitIdentity); if (contractsProvider == null) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't get contracts provider."); return; } #endregion #region Collect contracts var type = UnitHelper.FindType(host.NameTable, iAssembly, typeName, genericParameterCount); if (type == null || type is Dummy) { VSServiceProvider.Current.Logger.WriteToLog("Couldn't find metadata type '" + typeName + "' in assembly."); return; } //This dictionaries will map the method/property signature to the contracts for the method/property var methodsToContracts = new Dictionary<string, IMethodContract>(type.Methods.Count()); var gettersToContracts = new Dictionary<string, IMethodContract>(); var settersToContracts = new Dictionary<string, IMethodContract>(); //Set the formatting options for property getters and setters var propertySignatureFormattingOptions = NameFormattingOptions.OmitContainingNamespace | // NameFormattingOptions.ReturnType | NameFormattingOptions.TypeParameters | NameFormattingOptions.UseTypeKeywords | NameFormattingOptions.OmitContainingType; //NameFormattingOptions.Visibility; //Set the formating options for methods var methodSignatureFormattingOptions = NameFormattingOptions.OmitContainingNamespace | NameFormattingOptions.ReturnType | NameFormattingOptions.ParameterName | NameFormattingOptions.ParameterModifiers | NameFormattingOptions.TypeParameters | NameFormattingOptions.UseTypeKeywords | NameFormattingOptions.OmitContainingType | //NameFormattingOptions.Modifiers | NameFormattingOptions.Signature //NameFormattingOptions.Visibility ; //var sourceEmitterOutput = new SourceEmitterOutputString();//TODO: Use source emitter for all my printing? Instead of the whole NameFormattingOptions ordeal. //var csSourceEmitter = new SourceEmitter(sourceEmitterOutput); foreach (var method in type.Methods) { var methodContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(host, method); if (methodContract != null && methodContract != ContractDummy.MethodContract) { if (IsGetter(method)) { if (method.ParameterCount > 0) { //We have an indexer! var indexerSignature = PrintIndexer(method, true); gettersToContracts.Add(indexerSignature, methodContract); } else { var getterSignature = MemberHelper.GetMemberSignature(method, propertySignatureFormattingOptions);//Example: "XmlSchemaSet Schemas.get" getterSignature = getterSignature.Substring(0, getterSignature.LastIndexOf('.')); gettersToContracts.Add(getterSignature, methodContract); } } else if (IsSetter(method)) { if (method.ParameterCount > 1) { //We have an indexer! var indexerSignature = PrintIndexer(method, false); settersToContracts.Add(indexerSignature, methodContract); } else { var setterSignature = MemberHelper.GetMemberSignature(method, propertySignatureFormattingOptions); setterSignature = setterSignature.Substring(0, setterSignature.LastIndexOf('.')); settersToContracts.Add(setterSignature, methodContract); } } else { //#region Print method, stolen from CSharpSourceEmitter //csSourceEmitter.PrintMethodDefinitionVisibility(method); //csSourceEmitter.PrintMethodDefinitionModifiers(method); //bool conversion = csSourceEmitter.IsConversionOperator(method); //if (!conversion) { // csSourceEmitter.PrintMethodDefinitionReturnType(method); // if (!method.IsConstructor && !csSourceEmitter.IsDestructor(method)) // csSourceEmitter.PrintToken(CSharpToken.Space); //} //csSourceEmitter.PrintMethodDefinitionName(method); //if (conversion) // csSourceEmitter.PrintMethodDefinitionReturnType(method); //if (method.IsGeneric) { // csSourceEmitter.Traverse(method.GenericParameters); //} //csSourceEmitter.Traverse(method.Parameters); //#endregion //var methodSignature = sourceEmitterOutput.Data; //sourceEmitterOutput.ClearData(); var methodSignature = MemberHelper.GetMemberSignature(method, methodSignatureFormattingOptions);//Example: "XmlAttribute CreateAttribute(string name)" methodsToContracts.Add(methodSignature, methodContract); } } } #endregion var hasMethodContracts = methodsToContracts.Count > 0; var hasPropertyContracts = gettersToContracts.Count > 0 || settersToContracts.Count > 0; if (!hasMethodContracts && !hasPropertyContracts) { VSServiceProvider.Current.Logger.WriteToLog("No contracts found."); return; } int propertyCounter = 0; //Counts the number of adornments added for property contracts int methodCounter = 0; //Counts the number of adornments added for method contracts foreach (var line in _textView.TextSnapshot.Lines) { var lineText = line.GetText(); //Skip lines with comments //This assumes that no method/property decelerations in metadata files will have comments in them if (lineText.Contains("//")) continue; // bail out on nested types var typeNameMatch = Regex.Match(lineText, @"(class|struct|interface|enum) (\w+)"); if (typeNameMatch.Success) { if (typeNameMatch.Groups[2].Value == type.Name.Value) continue; break; } if (hasPropertyContracts && lineText.Contains('{') && (lineText.Contains(" get; ") || lineText.Contains(" set; ")) && lineText.Contains('}')) { //Check if line is a property decleration #region Add property contracts //Parse the property decleration to get a signature we can compare to our contract dictionaries //Example of a property decleration: " public int Build { get; }" int endOfSig = lineText.IndexOf('{') - 1; int startOfSig = endOfSig - 1; bool hasHitSpace = false; bool isInPropertyParameter = false; for (int i = startOfSig; i > 0; i--) { char c = lineText[i]; if (c == ']') isInPropertyParameter = true; else if (c == '[') isInPropertyParameter = false; else if (hasHitSpace && c == ' ') { startOfSig = i + 1; break; } else if (!isInPropertyParameter && c == ' ') { startOfSig = i + 1; break; // MAF: ignore return type of properties. //hasHitSpace = true; } } var propertySignature = lineText.Substring(startOfSig, endOfSig - startOfSig); //Example: "int Build" IMethodContract getterContract = null; IMethodContract setterContract = null; if (gettersToContracts.TryGetValue(propertySignature, out getterContract) | // yes eager evaluation!!! settersToContracts.TryGetValue(propertySignature, out setterContract)) { var tag = propertySignature.GetHashCode();//We use this to uniquely identify the particular method/property decleration //Find this first non-whitespace character. This is were we'll place the adornment. int firstNonWhitespace = 0; for (int i = 0; i < lineText.Length; i++) { char c = lineText[i]; if (c != ' ') { firstNonWhitespace = i; break; } } var span = _textView.TextSnapshot.CreateTrackingSpan(line.Start + firstNonWhitespace, propertySignature.Length, SpanTrackingMode.EdgeExclusive); _vsTextProperties.LineHeight = _textView.LineHeight; var ops = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage); var adornment = new MetadataContractAdornment(span, _vsTextProperties, VSServiceProvider.Current.Logger, _adornmentManager.QueueRefreshLineTransformer, ops); adornment.SetContracts(getterContract, setterContract, null /* "Contracts from " + typeName + "." */); _adornmentManager.AddAdornment(adornment, tag); propertyCounter++; } #endregion continue; } if (hasMethodContracts && lineText.Contains('(') && lineText.Contains(')') && lineText.Contains(';')) { //Check if line is a method decleration #region Add method contracts //Parse the method decleration to get a signature we can compare to our contract dictionaries //Example of a method decleration: " public static Version Parse(string input);" int endOfSig = lineText.LastIndexOf(')') + 1; //int startOfSig = !Char.IsWhiteSpace(lineText[0]) ? 0 : lineText.IndexOf(lineText.First(c => !Char.IsWhiteSpace(c))); //int startOfSig = lineText.IndexOf('('); //bool hitSpace = false; //for (int i = startOfSig; i > 0; i--) { // char c = lineText[i]; // if (c == ' ' && hitSpace) { // startOfSig = i + 1; // break; // } else if (c == ' ') { // hitSpace = true; // } //} var methodSignature = lineText.Substring(0, endOfSig); //Example: "Version Parse(string input)" // remove modifiers methodSignature = Regex.Replace(methodSignature, modifierFilter, ""); methodSignature = methodSignature.Trim(); if (methodSignature.StartsWith(type.Name.Value + "(")) { methodSignature = "void .ctor" + methodSignature.Substring(type.Name.Value.Length); } IMethodContract methodContract; if (methodsToContracts.TryGetValue(methodSignature, out methodContract)) { var tag = methodSignature.GetHashCode();//We use this to uniquely identify the particular method/property decleration //Find this first non-whitespace character. This is were we'll place the adornment. int firstNonWhitespace = 0; for (int i = 0; i < lineText.Length; i++) { char c = lineText[i]; if (c != ' ') { firstNonWhitespace = i; break; } } var span = _textView.TextSnapshot.CreateTrackingSpan(line.Start + firstNonWhitespace, methodSignature.Length, SpanTrackingMode.EdgeExclusive); _vsTextProperties.LineHeight = _textView.LineHeight; var ops = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage); var adornment = new MetadataContractAdornment(span, _vsTextProperties, VSServiceProvider.Current.Logger, _adornmentManager.QueueRefreshLineTransformer, ops); adornment.SetContracts(methodContract, "Contracts from " + typeName + "."); _adornmentManager.AddAdornment(adornment, tag); //if (methodContract.IsPure) { // var purityAdornment = new PurityAdornment(_vsTextProperties, adornment); // //_adornmentManager.AddAdornment(purityAdornment, null); //} methodCounter++; } #endregion continue; } } #region Add button to collapse all contracts if (propertyCounter > 0 || methodCounter > 0) { var button = new Button(); button.Content = "Hide all contracts"; button.Click += OnCollapseAllClick; button.Cursor = Cursors.Hand; var collapseAllAdornment = new StaticAdornment(false, 10d, true, 10d, button); _adornmentManager.AddStaticAdornment(collapseAllAdornment); } #endregion }