private IEnumerable <Microsoft.CodeAnalysis.CodeActions.CodeIssue> GetIssuesInternal(IEnumerable <ClousotOutput> results, CompilationUnitSyntax compilationUnitDeclaration) { IEnumerator <ClousotOutput> enumerator; try { enumerator = results.GetEnumerator(); } catch { yield break; } bool hasNext; try { hasNext = enumerator.MoveNext(); } catch { yield break; } while (hasNext) { var result = enumerator.Current; //foreach (var result in results ) { var msg = result.Message; var span = result.Span; var action = result.action; if (span.IsEmpty) { msg = "Unknown location: " + msg; span = compilationUnitDeclaration.GetFirstToken().Span; } if (action == null) { yield return(new Microsoft.CodeAnalysis.CodeActions.CodeIssue(Microsoft.CodeAnalysis.CodeActions.CodeIssueKind.Warning, span, msg)); } else { yield return(new Microsoft.CodeAnalysis.CodeActions.CodeIssue(Microsoft.CodeAnalysis.CodeActions.CodeIssueKind.Warning, span, msg, action)); } } try { hasNext = enumerator.MoveNext(); } catch { yield break; } } }
public static CompilationUnitSyntax AddUsingDirectives( this CompilationUnitSyntax root, IList <UsingDirectiveSyntax> usingDirectives, bool placeSystemNamespaceFirst, params SyntaxAnnotation[] annotations) { if (!usingDirectives.Any()) { return(root); } var specialCaseSystem = placeSystemNamespaceFirst; var comparer = specialCaseSystem ? UsingsAndExternAliasesDirectiveComparer.SystemFirstInstance : UsingsAndExternAliasesDirectiveComparer.NormalInstance; var usings = new List <UsingDirectiveSyntax>(); usings.AddRange(root.Usings); usings.AddRange(usingDirectives); // If the user likes to have their Usings statements unsorted, allow them to if (root.Usings.IsSorted(comparer)) { usings.Sort(comparer); } // If any using we added was moved to the first location, then take the trivia from // the start of the first token and add it to the using we added. This way things // like #define's and #r's will stay above the using. var firstUsingChanged = root.Usings.Count == 0 || usings[0] != root.Usings[0]; if (firstUsingChanged && root.Externs.Count == 0) { var firstToken = root.GetFirstToken(); // Move the leading directives from the first directive to the new using. var firstUsing = usings[0].WithLeadingTrivia(firstToken.LeadingTrivia.Where(t => !t.IsDocComment() && !t.IsElastic())); // Remove the leading directives from the first token. var newFirstToken = firstToken.WithLeadingTrivia(firstToken.LeadingTrivia.Where(t => t.IsDocComment() || t.IsElastic())); // Remove the leading trivia from the first token from the tree. root = root.ReplaceToken(firstToken, newFirstToken); // Create the new list of usings. var finalUsings = new List <UsingDirectiveSyntax>(); finalUsings.Add(firstUsing); finalUsings.AddRange(root.Usings); finalUsings.AddRange(usingDirectives.Except(new[] { usings[0] })); finalUsings.Sort(comparer); usings = finalUsings; } usings = usings.Select(u => u.WithAdditionalAnnotations(annotations)).ToList(); return(root.WithUsings(usings.ToSyntaxList())); }
public override void Open() { base.Open(); tree = (CSharpSyntaxTree)CSharpSyntaxTree.ParseText(Source, CSharpParseOptions.Default); CompilationUnitSyntax root = (CompilationUnitSyntax)tree.GetRoot(); MemberDeclarationSyntax firstMember = root.Members [0]; Console.WriteLine(firstMember.GetType().FullName); SyntaxToken tok = root.GetFirstToken(); while (tok.Value != null) { Console.Write(tok.Text); tok = tok.GetNextToken(true, true); } Console.Out.Flush(); }
public IEnumerable <Tuple <string, TextSpan> > AnalyzeMeAUnit( Microsoft.CodeAnalysis.Document document, CompilationUnitSyntax compilationUnitDeclaration, CancellationToken cancellationToken) { var semanticModel = document.GetSemanticModel(cancellationToken); var semanticNode = semanticModel.GetDeclaredSymbol(compilationUnitDeclaration); this.sourceLocationProvider = new SourceLocationProvider(); string exceptionMessage = null; IAssemblyReference ar = null; try { // Constructs a full metadata model for the assembly the semantic model is from var transformer = new NodeVisitor(this.host, semanticModel, sourceLocationProvider); // Constructs the method bodies all of the methods in the compilation unit var tree = document.GetSyntaxTree(cancellationToken); var tree2 = transformer.Visit(compilationUnitDeclaration); ar = tree2 as IAssemblyReference; } catch (ConverterException e) { exceptionMessage = e.Message; } if (exceptionMessage != null) { yield return(Tuple.Create(exceptionMessage, compilationUnitDeclaration.GetFirstToken().Span)); yield break; } var unit = ar; this.host.RegisterUnit(unit.ResolvedUnit); this.cciProvider.MetaDataDecoder.RegisterSourceLocationProvider(unit, sourceLocationProvider); this.methodAnalyzer.AnalyzeAssembly(ar); foreach (var result in this.analysisResults) { yield return(result); } }
public static CompilationUnitSyntax AddUsingDirectives( this CompilationUnitSyntax root, IList <UsingDirectiveSyntax> usingDirectives, bool placeSystemNamespaceFirst, params SyntaxAnnotation[] annotations) { if (usingDirectives.Count == 0) { return(root); } var comparer = placeSystemNamespaceFirst ? UsingsAndExternAliasesDirectiveComparer.SystemFirstInstance : UsingsAndExternAliasesDirectiveComparer.NormalInstance; var usings = AddUsingDirectives(root, usingDirectives); // Keep usings sorted if they were originally sorted. if (root.Usings.IsSorted(comparer)) { usings.Sort(comparer); } if (root.Externs.Count == 0) { if (root.Usings.Count == 0) { // We don't have any existing usings. Move any trivia on the first token // of the file to the first using. // // Don't do this for doc comments, as they belong to the first element // already in the file (like a class) and we don't want it to move to // the using. var firstToken = root.GetFirstToken(); // Remove the leading directives from the first token. var newFirstToken = firstToken.WithLeadingTrivia( firstToken.LeadingTrivia.Where(t => IsDocCommentOrElastic(t))); root = root.ReplaceToken(firstToken, newFirstToken); // Move the leading trivia from the first token to the first using. var newFirstUsing = usings[0].WithLeadingTrivia( firstToken.LeadingTrivia.Where(t => !IsDocCommentOrElastic(t))); usings[0] = newFirstUsing; } else { var originalFirstUsing = root.Usings[0]; if (usings[0] != originalFirstUsing) { // We added a new first-using. Take the trivia on the existing first using // And move it to the new using. var originalFirstUsingCurrentIndex = usings.IndexOf(originalFirstUsing); var newFirstUsing = usings[0].WithLeadingTrivia(originalFirstUsing.GetLeadingTrivia()) .WithAppendedTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed); usings[0] = newFirstUsing; usings[originalFirstUsingCurrentIndex] = originalFirstUsing.WithoutLeadingTrivia(); } } } return(root.WithUsings( usings.Select(u => u.WithAdditionalAnnotations(annotations)).ToSyntaxList())); }
public static CompilationUnitSyntax Visit(CompilationUnitSyntax code) { var modifications = new Dictionary <SyntaxToken, SyntaxToken>(); var token = code.GetFirstToken(); Action modifyPrevEol = () => { }; var addAtPrevEol = new List <(string errorCode, bool isRestore)>(); var addAtNextEol = new List <(string errorCode, bool isRestore)>(); while (!token.IsKind(SyntaxKind.None)) { token = token.GetNextToken(); var localToken = token; var leadingTrivia = token.GetAllTrivia().TakeWhile(x => x.SpanStart < token.SpanStart).ToList(); HandleEol(leadingTrivia, t => t.WithLeadingTrivia); var warnings = token.GetAnnotations(PragmaWarnings.AnnotationKind); if (warnings.Any()) { var errorCodes = warnings.Select(x => x.Data).ToList(); addAtPrevEol.AddRange(errorCodes.Select(x => (x, false))); addAtNextEol.AddRange(errorCodes.Select(x => (x, true))); } var trailingTrivia = token.GetAllTrivia().SkipWhile(x => x.SpanStart < token.SpanStart).ToList(); HandleEol(trailingTrivia, t => t.WithTrailingTrivia); void HandleEol(IReadOnlyList <SyntaxTrivia> trivia, Func <SyntaxToken, Func <IEnumerable <SyntaxTrivia>, SyntaxToken> > mod) { if (trivia.Any(ContainsEol)) { modifyPrevEol(); addAtPrevEol = addAtNextEol; addAtNextEol = new List <(string errorCode, bool isRestore)>(); modifyPrevEol = () => { if (!addAtPrevEol.Any()) { return; } var disables0 = addAtPrevEol.Where(x => !x.isRestore).Select(x => x.errorCode).Distinct().ToList(); var restores0 = addAtPrevEol.Where(x => x.isRestore).Select(x => x.errorCode).Distinct().ToList(); var disables = disables0.Except(restores0).ToList(); var restores = restores0.Except(disables0).ToList(); if (!disables.Any() && !restores.Any()) { return; } var preEol = trivia.TakeWhile(x => !ContainsEol(x)).ToList(); var postEol = Enumerable.Reverse(trivia).TakeWhile(x => !ContainsEol(x)).Reverse().ToList(); var midEol = trivia.Skip(preEol.Count).Take(trivia.Count - preEol.Count - postEol.Count); var modifiedTrivia = preEol .Concat(restores.Any() ? new[] { WhitespaceFormatterNewLine.NewLine, PragmaWarningRestore(restores.ToArray()) } : Enumerable.Empty <SyntaxTrivia>()) .Concat(midEol) .Concat(disables.Any() ? new[] { PragmaWarningDisable(disables.ToArray()), WhitespaceFormatterNewLine.NewLine } : Enumerable.Empty <SyntaxTrivia>()) .Concat(postEol); var existingToken = modifications.TryGetValue(localToken, out var modifiedToken) ? modifiedToken : localToken; modifications[localToken] = mod(existingToken)(modifiedTrivia); }; } bool ContainsEol(SyntaxTrivia st) { if (st.IsKind(SyntaxKind.EndOfLineTrivia)) { return(true); } var structure = st.GetStructure(); if (structure is object) { if (structure.DescendantNodesAndTokensAndSelf().Any(nt => nt.GetLeadingTrivia().Concat(nt.GetTrailingTrivia()).Any(ContainsEol))) { return(true); } } return(false); } } } modifyPrevEol(); code = code.ReplaceTokens(modifications.Keys, (orgtoken, _) => modifications[orgtoken]); code = (CompilationUnitSyntax) new PragmaVisitor().Visit(code); return(code); }
/// <summary> /// Checks the <paramref name="compilationUnitDeclaration"/> for syntax and semantic /// errors and returns an empty enumerable if any are found. /// </summary> public IEnumerable <ClousotOutput> AnalyzeMeAUnit( Microsoft.CodeAnalysis.Document document, CompilationUnitSyntax compilationUnitDeclaration, CancellationToken cancellationToken, ClousotOptions options, string[] extraOptions, bool showOnlyAnswersToAskClousot = false ) { if (options == null) { options = new ClousotOptions(); } // Don't do anything if there are syntactic errors. if (compilationUnitDeclaration.ContainsDiagnostics) { yield break; } var semanticModel = document.GetSemanticModel(cancellationToken); // Don't do anything if there are semantic errors. var diagnostics = semanticModel.GetDiagnostics(cancellationToken); if (diagnostics.Any(d => d.Info.Severity == DiagnosticSeverity.Error || d.Info.IsWarningAsError)) { yield break; } this.host = new ClousotGlueHost((document.Project).MetadataReferences); this.sourceLocationProvider = new SourceLocationProvider(); string exceptionMessage = null; IAssemblyReference ar = null; try { // Constructs a full metadata model for the assembly the semantic model is from var transformer = new NodeVisitor(this.host, semanticModel, sourceLocationProvider); // Constructs the method bodies all of the methods in the compilation unit // var tree = document.GetSyntaxTree(cancellationToken); var tree2 = transformer.Visit(compilationUnitDeclaration); ar = tree2 as IAssemblyReference; } catch (ConverterException e) { exceptionMessage = e.Message; } catch (OperationCanceledException) { // just return nothing yield break; } if (exceptionMessage != null) { yield return(new ClousotOutput(null, exceptionMessage, compilationUnitDeclaration.GetFirstToken().Span, null, (ICodeAction)null, ClousotOutput.ExtraInfo.None)); yield break; } var spanToMethodMap = MethodSpanFinder.GetMethodSpans(compilationUnitDeclaration); lock (this) { // Clousot is single-threaded var cciProvider = Microsoft.Cci.Analysis.CciILCodeProvider.CreateCodeProvider(host); var unit = ar; this.host.RegisterUnit(unit.ResolvedUnit); cciProvider.MetaDataDecoder.RegisterSourceLocationProvider(unit, sourceLocationProvider); var metadataDecoder = cciProvider.MetaDataDecoder; var contractDecoder = cciProvider.ContractDecoder; var defaultargs = new string[] { "-nonnull", "-bounds", "-arithmetic", "-sortwarns:-", //"-arrays", "-cache", //"-suggest=methodensures", "-suggest=propertyensures", "-suggest=objectinvariants", //"-infer=requires", //"-infer=objectinvariants", //"-clearcache", //"-prefrompost" }; var codefixesargs = new string[] { "-nonnull", "-bounds", "-arithmetic", "-suggest=codefixes", "-cache", "-libpaths:\"c:\\program files (x86)\\Microsoft\\Contracts\\Contracts\\.NetFramework\\v4.0\"", //"-suggest=methodensures", "-suggest=objectinvariants", "-infer=objectinvariants", "-suggest=assumes", "-premode=backwards", }; var args = codefixesargs; if (extraOptions != null) { args = args.Concat(extraOptions).ToArray(); } var w = (options == null || String.IsNullOrWhiteSpace(options.WarningLevel)) ? "low" : options.WarningLevel; var warninglevel = String.Format("-warninglevel={0}", w); var x = new string[] { warninglevel, }; args = args.Concat(x).ToArray(); if (options != null) { var otherOptions = options.OtherOptions; if (!String.IsNullOrWhiteSpace(otherOptions)) { var otherOpts = otherOptions.Split(' '); args = args.Concat(otherOpts).ToArray(); } } this.analysisResults = new List <ClousotOutput>(); var output = new RoslynOutput(showOnlyAnswersToAskClousot, this.analysisResults, document, spanToMethodMap, null); var methodAnalyzer = Clousot.GetIndividualMethodAnalyzer(metadataDecoder, contractDecoder, args, output, new[] { this.cacheFactory }); foreach (var path in methodAnalyzer.Options.libPaths) { host.AddLibPath(path); } methodAnalyzer.AnalyzeAssembly(ar); } foreach (var result in this.analysisResults) { yield return(result); } }