public override void TraverseChildren(IMethodDefinition methodDefinition) { if (AttributeHelper.Contains(methodDefinition.Attributes, this.host.PlatformType.SystemRuntimeCompilerServicesCompilerGeneratedAttribute)) { return; } if (ContractHelper.IsInvariantMethod(this.host, methodDefinition)) { return; } if (IsGetter(methodDefinition) || IsSetter(methodDefinition)) { return; } IMethodContract methodContract; if (this.showInherited) { methodContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(this.host, methodDefinition); } else { methodContract = ContractHelper.GetMethodContractFor(this.host, methodDefinition); } Indent(); var methodSig = MemberHelper.GetMethodSignature(methodDefinition, NameFormattingOptions.Signature | NameFormattingOptions.ParameterName | NameFormattingOptions.ParameterModifiers); Console.WriteLine(methodSig); this.indentLevel++; PrintMethodContract(methodContract); this.indentLevel--; }
public override void TraverseChildren(IPropertyDefinition propertyDefinition) { string propertyId = MemberHelper.GetMemberSignature(propertyDefinition, NameFormattingOptions.SmartTypeName); Indent(); Console.WriteLine(propertyId); this.indentLevel++; if (propertyDefinition.Getter != null) { var getterMethod = propertyDefinition.Getter.ResolvedMethod; IMethodContract getterContract; if (this.showInherited) { getterContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(this.host, getterMethod); } else { getterContract = ContractHelper.GetMethodContractFor(this.host, getterMethod); } Indent(); Console.WriteLine("get"); this.indentLevel++; PrintMethodContract(getterContract); this.indentLevel--; } if (propertyDefinition.Setter != null) { var setterMethod = propertyDefinition.Setter.ResolvedMethod; IMethodContract setterContract; if (this.showInherited) { setterContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(this.host, setterMethod); } else { setterContract = ContractHelper.GetMethodContractFor(this.host, setterMethod); } Indent(); Console.WriteLine("set"); this.indentLevel++; PrintMethodContract(setterContract); this.indentLevel--; } this.indentLevel--; }
public bool TryGetMethodContract(IMethodReference method, out IMethodContract methodContract) { Contract.Ensures(!Contract.Result <bool>() || (Contract.ValueAtReturn(out methodContract) != null)); methodContract = null; #region Check input if (method == null) { return(false); } #endregion try { // Resolving the method works *only* if the unit it is defined in has already been loaded. // That should have happened as part of creating the IMethodReference. var resolvedMethod = method.ResolvedMethod; if (resolvedMethod != Dummy.Method) { methodContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(Host, resolvedMethod); if (methodContract == null) { methodContract = ContractDummy.MethodContract; ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Did not find any method contract(s) for '{0}'", method.Name)); } else { ContractsPackageAccessor.Current.Logger.WriteToLog( String.Format("Got method contract(s) for '{0}': {1} preconditions, {2} postconditions", method.Name, Microsoft.Cci.IteratorHelper.EnumerableCount(methodContract.Preconditions), Microsoft.Cci.IteratorHelper.EnumerableCount(methodContract.Postconditions))); } } else { ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Method '{0}' resolved to dummy", method.Name)); } } catch (NullReferenceException) { methodContract = null; ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("NullReferenceException thrown when getting contracts for '{0}'", method.Name)); } return(methodContract != null); }
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 }