//public UnresolvedInterfaceAnnotation( // CCCheckExtraInfo extra_info, // Squiggle squiggle, // ClousotSuggestion.Kind kind) // : base(null, null, extra_info.SuggestedCode, squiggle, kind) //{ // // TODO there are ways this can fail to create a valid annotation // // there is a lot of string parsing going on that could go wrong // // could be refactored into a TryXXXX? // //this.extraInfo = extra_info; // this.InterfaceMethod = extra_info.CalleeDocumentId; // this.InterfaceName = extra_info.TypeDocumentId; // if (InterfaceName.Contains('<')) // { // var lastAngle = InterfaceName.LastIndexOf('<'); // var beforeAngle = InterfaceName.Remove(lastAngle); // var afterAngle = InterfaceName.Replace(beforeAngle, ""); // InterfaceName = beforeAngle; // var parts = afterAngle.Trim('<', '>').Split(','); // NumberParameters = parts.Count(); // ParametersString = "<" + parts[0].Replace("type parameter.", ""); // for (int i = 1; i < parts.Length; i++) // { // ParametersString += ',' + parts[i].Replace("type parameter.", ""); // } // ParametersString += ">"; // } // this.InterfaceShortName = InterfaceAnnotationHelpers.GetUnqualifiedName(InterfaceName); //} public UnresolvedInterfaceAnnotation(string annotation, Squiggle squiggle, ClousotSuggestion.Kind kind, string parameterstring, string interfacename, string interfacemethod) : base(null, null, annotation, squiggle, kind) { this.ParametersString = parameterstring; this.InterfaceName = interfacename; this.InterfaceMethod = interfacemethod; this.InterfaceShortName = InterfaceAnnotationHelpers.GetUnqualifiedName(interfacename); }
private static Compilation ImplementContractsClass(Project project, Compilation original, string filename, string interfacename, string contractname) { #region CodeContracts Contract.Requires(project != null); Contract.Requires(original != null); Contract.Requires(filename != null); Contract.Requires(interfacename != null); Contract.Requires(contractname != null); Contract.Ensures(Contract.Result <Compilation>() != null); #endregion CodeContracts var interfaceShortName = InterfaceAnnotationHelpers.GetUnqualifiedName(interfacename); var doc = project.Documents.First(x => x.FilePath.Equals(filename, StringComparison.OrdinalIgnoreCase)); var orig_st = original.SyntaxTrees.First(x => x.FilePath.Equals(filename, StringComparison.OrdinalIgnoreCase)); doc = doc.WithSyntaxRoot(orig_st.GetRoot()); var st = doc.GetSyntaxTreeAsync().Result; Contract.Assert(st != null); //var st = CSharpSyntaxTree.Create(doc.GetSyntaxRootAsync().Result as CSharpSyntaxNode, orig_st.FilePath, null); var newcomp = original.ReplaceSyntaxTree(orig_st, st); var sm = newcomp.GetSemanticModel(st); //Console.WriteLine(doc.GetTextAsync().Result); var classes = st.GetRoot().DescendantNodesAndSelf().Where(x => x.CSharpKind().Equals(SyntaxKind.ClassDeclaration)); var node = classes.First(x => sm.GetDeclaredSymbol(x).GetDocumentationCommentId().Equals(contractname)); //var node = st.GetRoot().DescendantNodesAndSelf().First(x => x.CSharpKind().Equals(SyntaxKind.ClassDeclaration) // && sm.GetDeclaredSymbol(x).GetDocumentationCommentId().Equals(contractname)); var baselist = node.DescendantNodes().First(x => x.CSharpKind().Equals(SyntaxKind.BaseList)); var inode = baselist.DescendantTokens().First(x => x.Text.Equals(interfaceShortName)); //var assembly = Assembly.LoadFrom(@"C:\cci\Microsoft.Research\Imported\Tools\Roslyn\v4.5.1\Microsoft.CodeAnalysis.CSharp.Features.dll"); //var assembly = Assembly.LoadFrom(@"C:\Users\t-scottc\Desktop\Signed_20140201.1\Microsoft.CodeAnalysis.CSharp.Features.dll"); //var assembly = Assembly.LoadFrom(@"C:\cci\Microsoft.Research\CCTools\ReviewBot\bin\Debug\Microsoft.CodeAnalysis.CSharp.Features.dll"); Assembly assembly; if (UsingHelpers.TryGetMicrosoftCodeAnalysisCSharpFeatures(out assembly)) { try { var type = assembly.GetType("Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementInterfaceService"); var method = type.GetMethod("ImplementInterfaceAsync"); var service = Activator.CreateInstance(type); var result = method.Invoke(service, new object[] { doc, inode.Parent, CancellationToken.None }) as Task <Document>; var newdoc = result.Result; return(newcomp.ReplaceSyntaxTree(st, newdoc.GetSyntaxTreeAsync().Result)); } catch (Exception e) { Output.WriteWarning("Something went wrong while trying to invoke Roslyn refactoring engine. Details: {0}", e.Message); Output.WriteLine("We continue skipping this interface"); return(original); } } else { Output.WriteWarning("Can't add the interface contract to {0} as we failed loading the Roslyn refactoring engine", interfacename); return(original); } }
private static SyntaxNode MakeContractsClassForNode(string interfacename, string parameters) { string intRawName = InterfaceAnnotationHelpers.GetUnqualifiedName(interfacename); string intName = InterfaceAnnotationHelpers.GetUnqualifiedName(interfacename); var numberparams = GetNumberParameters(parameters); //string contractParams = ""; //var IsInterfaceParameterized = interfacename.Contains('`'); //if (IsInterfaceParameterized) if (numberparams > 0) { //var tickIndex = interfacename.LastIndexOf('`') + 1; //var afterTick = interfacename.Replace(interfacename.Remove(tickIndex), ""); //var numberParameters = int.Parse(afterTick); intName += '<'; for (int i = 1; i < numberparams; i++) { intName += ','; } intName += '>'; //contractParams += "<T"; //for (int i = 1; i < numberParameters; i++) //{ //contractParams += ",T" + i; //} //contractParams += '>'; } var text = String.Format(@" using System; [ContractClassFor(typeof({0}))] internal abstract class {1}Contracts{2} : {1}{2} {{ }}" , intName, intRawName, parameters); var parsed = SyntaxFactory.ParseCompilationUnit(text); return(parsed.SyntaxTree.GetRoot().DescendantNodesAndSelf().OfType <ClassDeclarationSyntax>().First()); }
private static Compilation AddContractsClassAttributeToInterface(Project project, Compilation original, string filename, string interfacename, string parameterstring) { #region CodeContracts Contract.Requires(project != null); Contract.Requires(original != null); Contract.Requires(filename != null); Contract.Requires(interfacename != null); Contract.Ensures(Contract.Result <Compilation>() != null); #endregion CodeContracts var interfaceShortName = InterfaceAnnotationHelpers.GetUnqualifiedName(interfacename); var st = original.SyntaxTrees.Where(x => x.FilePath.Equals(filename, StringComparison.OrdinalIgnoreCase)).First(); var doc = project.GetDocument(st); var sm = original.GetSemanticModel(st); var node = st.GetRoot().DescendantNodes().Where(x => x.CSharpKind() == SyntaxKind.InterfaceDeclaration && sm.GetDeclaredSymbol(x).GetDocumentationCommentId().Equals(interfacename)).First() as InterfaceDeclarationSyntax; Contract.Assert(node != null); var parameters = ""; var numberparams = GetNumberParameters(parameterstring); if (numberparams > 0) { parameters = "<"; var commas = new String(',', numberparams - 1); parameters += commas; parameters += ">"; } var attr_name = SyntaxFactory.ParseName("ContractClass"); var attr_args = SyntaxFactory.ParseAttributeArgumentList(String.Format("(typeof({0}Contracts{1}))", interfaceShortName, parameters)); var attr = SyntaxFactory.Attribute(attr_name, attr_args); var attributes = SyntaxFactory.SeparatedList <AttributeSyntax>().Add(attr); var attr_list = SyntaxFactory.AttributeList(attributes); var newnode = node.AddAttributeLists(attr_list) as SyntaxNode; newnode = node.SyntaxTree.GetRoot().ReplaceNode(node, newnode); var newst = CSharpSyntaxTree.Create(newnode.SyntaxTree.GetRoot() as CSharpSyntaxNode, null, st.FilePath, null); return(original.ReplaceSyntaxTree(st, newst)); }
/// <summary> /// Take all the annotations, select only the interface annotations, create their contract classes (if necessary), /// resolve the contract class name and contract class method names /// </summary> /// <param name="annotations"></param> /// <param name="project"></param> /// <param name="compilation"></param> /// <param name="resolvedannotations">All the annotations with the interface annotation fields completed</param> /// <returns>The compilation with potentially new empty contract classes</returns> internal static Compilation CreateOrFindContractsClasses(IEnumerable <BaseAnnotation> annotations, Project project, Compilation compilation, out IEnumerable <BaseAnnotation> resolvedannotations) { #region CodeContracts Contract.Requires(annotations != null); Contract.Requires(project != null); Contract.Requires(compilation != null); Contract.Ensures(Contract.ValueAtReturn <IEnumerable <BaseAnnotation> >(out resolvedannotations) != null); Contract.Ensures(Contract.Result <Compilation>() != null); #endregion CodeContracts Output.WriteLine("Gathering (and creating) contract classes for interfaces and abstract classes"); var resolvedList = annotations.Where(x => !(x is UnresolvedInterfaceAnnotation)).ToList(); foreach (var interfaceGroup in annotations.OfType <UnresolvedInterfaceAnnotation>().GroupBy(x => x.InterfaceName)) { var first = interfaceGroup.First(); var interfaceSymbol = InterfaceAnnotationHelpers.GetInterfaceSymbol(project, compilation, first.InterfaceName, first.InterfaceShortName); string contractName, fileName, interfaceName; interfaceName = first.InterfaceName; if (!InterfaceAnnotationHelpers.TryFindContractsClass(compilation, interfaceSymbol, out contractName, out fileName)) { //fileName = first.FileName; fileName = interfaceSymbol.Locations[0].SourceTree.FilePath; // hopefully index 0 is where the declaration is? var interfaceMethod = first.InterfaceMethod; contractName = GetCreatedContractClassName(interfaceName, interfaceMethod); compilation = InterfaceAnnotationHelpers.MakeContractsClassFor(project, compilation, interfaceName, fileName, first.ParametersString); compilation = InterfaceAnnotationHelpers.ImplementContractsClass(project, compilation, fileName, interfaceName, contractName); var syntaxTree = compilation.SyntaxTrees.First(x => x.FilePath.Equals(fileName, StringComparison.OrdinalIgnoreCase)); var newSyntaxTree = Replacer.AddUsingsContracts(syntaxTree); compilation = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(newSyntaxTree.GetRoot(), null, fileName)); compilation = InterfaceAnnotationHelpers.AddContractsClassAttributeToInterface(project, compilation, fileName, interfaceName, first.ParametersString); } foreach (var methodgroup in interfaceGroup.GroupBy(annotation => annotation.InterfaceMethod)) { first = methodgroup.First(); var methodName = InterfaceAnnotationHelpers.GetMethodName(first.InterfaceName, first.InterfaceMethod, contractName); resolvedList.AddRange(methodgroup.Select(x => new ResolvedInterfaceAnnotation(fileName, methodName, x.Annotation, x.Squiggle, x.Kind, x))); } //var methodName = InterfaceAnnotationHelpers.GetMethodName(first.InterfaceName, first.InterfaceMethod, contractName); //resolvedList.AddRange(interfaceGroup.Select(x => new ResolvedInterfaceAnnotation(fileName, methodName, x.Annotation, x.Squiggle, x.Kind, x))); //return compilation; //compilation = first.MakeOrFindContractsClass(project, compilation); //foreach (var intf in interfaceGroup) //{ // //intf.CopyFileNameAndContractsClass(first); // //} //foreach (var grp in interfaceGroup.GroupBy(x => x.MethodName)) //{ // first = grp.First(); // first.FindMethodName(compilation); // foreach (var intf in grp) // { // intf.CopyMethodName(first); // } //} } resolvedannotations = resolvedList.AsReadOnly(); return(compilation); }
public static bool TryMakeAnnotation(CCCheckOutputAssemblyMethod method, CCCheckOutputAssemblyMethodSuggestion suggestion, ClousotSuggestion.Kind suggestionKind, string path, Squiggle squiggle, out BaseAnnotation annotation, out string whyFailed) { #region CodeContracts Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out annotation) != null); Contract.Ensures(Contract.Result <bool>() || Contract.ValueAtReturn(out whyFailed) != null); #endregion CodeContracts whyFailed = null; annotation = null; switch (suggestionKind) { case ClousotSuggestion.Kind.AssumeOnEntry: case ClousotSuggestion.Kind.Ensures: case ClousotSuggestion.Kind.Requires: { annotation = new Precondition(path, method.Name, suggestion.Suggested, squiggle, suggestionKind); return(true); } case ClousotSuggestion.Kind.ObjectInvariant: { Contract.Assert(suggestion.SuggestionExtraInfo != null, "We expect to have extra info for the suggestion of an object invariant"); var exinfo2 = suggestion.SuggestionExtraInfo[0]; annotation = new UnresolvedObjectInvariant(path, method.Name, exinfo2.TypeDocumentId, exinfo2.SuggestedCode, squiggle, suggestionKind); return(true); } case ClousotSuggestion.Kind.EnsuresNecessary: { Contract.Assert(suggestion.SuggestionExtraInfo != null, "We expect to have extra info for the suggestion of an ensures necessary"); if (suggestion.SuggestionExtraInfo.First().CalleeMemberKind == "Interface") { var exinfo = suggestion.SuggestionExtraInfo[0]; if (exinfo.CalleeIsDeclaredInTheSameAssembly.Equals("False")) { whyFailed = "Don't know what to do when callee is in another assembly"; return(false); } //annotation = new UnresolvedInterfaceAnnotation(exinfo, squiggle, suggestionKind); UnresolvedInterfaceAnnotation ann; if (InterfaceAnnotationHelpers.TryMakeUnresolvedInterfaceAnnotation(exinfo, squiggle, suggestionKind, out ann)) { annotation = ann; return(true); } whyFailed = "Unknown suggestion"; return(false); } whyFailed = string.Format("Unhandled clousot suggestion kind {0} {1}", suggestionKind, suggestion.SuggestionExtraInfo.First().CalleeMemberKind); return(false); } case ClousotSuggestion.Kind.ReadonlyField: { Contract.Assert(suggestion.SuggestionExtraInfo != null, "We expect to have extra info for the suggestion of a readonly field"); var extraInfo = suggestion.SuggestionExtraInfo[0]; annotation = new ReadonlyField(extraInfo.CalleeDocumentId, path, extraInfo.TypeDocumentId, method.Name, squiggle, ClousotSuggestion.Kind.ReadonlyField); return(true); } default: { whyFailed = string.Format("Unhandled clousot suggestion kind {0}", suggestionKind); return(false); } } }