private static void AddExplicitSymbolStates(ImmutableDictionary <string, Tristate> .Builder symbolStates, IEnumerable <string> symbols, Tristate explicitState) { if (symbols == null) { return; } foreach (var symbol in symbols) { Tristate state; if (symbolStates.TryGetValue(symbol, out state)) { if (state == explicitState) { throw new ArgumentException( string.Format("Symbol '{0}' appears in the {1} list multiple times", symbol, GetStateString(explicitState))); } else { throw new ArgumentException( string.Format("Symbol '{0}' cannot be both {1} and {2}", symbol, GetStateString(state), GetStateString(explicitState))); } } else { symbolStates[symbol] = explicitState; } } }
public Tristate EvaluateExpression(CSharpSyntaxNode expression) { var it = _expressionEvaluators.GetEnumerator(); if (!it.MoveNext()) { Debug.Assert(false, "We should have at least one expression evaluator"); } Tristate result = expression.Accept(it.Current); if (result == Tristate.Varying) { return(Tristate.Varying); } while (it.MoveNext()) { if (expression.Accept(it.Current) != result) { return(Tristate.Varying); } } return(result); }
internal Options( IEnumerable <Project> projects = null, IEnumerable <string> projectPaths = null, IEnumerable <string> sourcePaths = null, IEnumerable <IEnumerable <string> > symbolConfigurations = null, IEnumerable <string> alwaysIgnoredSymbols = null, IEnumerable <string> alwaysDefinedSymbols = null, IEnumerable <string> alwaysDisabledSymbols = null, Tristate undefinedSymbolValue = default(Tristate), IAnalysisLogger logger = null) { if (projectPaths != null) { List <Project> projectsToAdd = new List <Project>(); projectPaths.ToList().ForEach(filePath => { AnalyzerManager analyzerManager = new AnalyzerManager(); ProjectAnalyzer analyzer = analyzerManager.GetProject(filePath); projectsToAdd.AddRange(analyzerManager.GetWorkspace().CurrentSolution.Projects); }); projects = projectsToAdd.AsEnumerable(); } if (projects != null) { Documents = GetSharedDocuments(projects); } if (projects == null && sourcePaths != null) { var projectId = ProjectId.CreateNewId("AnalysisProject"); var solution = new AdhocWorkspace() .CurrentSolution .AddProject(projectId, "AnalysisProject", "AnalysisProject", LanguageNames.CSharp); foreach (var path in sourcePaths) { var documentId = DocumentId.CreateNewId(projectId); solution = solution.AddDocument( documentId, Path.GetFileName(path), new FileTextLoader(path, defaultEncoding: Encoding.UTF8)); } Documents = solution.Projects.Single().Documents.ToImmutableArray(); } _symbolConfigurations = CalculateSymbolConfigurations( alwaysDisabledSymbols, alwaysDefinedSymbols, alwaysIgnoredSymbols, symbolConfigurations); _undefinedSymbolValue = undefinedSymbolValue; Logger = logger ?? new ConsoleAnalysisLogger(); }
public ConditionalRegion(DirectiveTriviaSyntax startDirective, DirectiveTriviaSyntax endDirective, Tristate state) { Debug.Assert(startDirective.SyntaxTree.FilePath == endDirective.SyntaxTree.FilePath); StartDirective = startDirective; EndDirective = endDirective; SpanStart = CalculateSpanStart(startDirective); SpanEnd = endDirective.FullSpan.End; Location = Location.Create(startDirective.SyntaxTree, new TextSpan(SpanStart, SpanEnd - SpanStart)); State = state; }
private static string GetStateString(Tristate state) { if (state == Tristate.False) { return("always disabled"); } else if (state == Tristate.True) { return("always enabled"); } else { return("ignore"); } }
public static async Task <AnalysisEngine> FromFilePaths( IEnumerable <string> filePaths, IEnumerable <IEnumerable <string> > symbolConfigurations = null, IEnumerable <string> alwaysIgnoredSymbols = null, IEnumerable <string> alwaysDefinedSymbols = null, IEnumerable <string> alwaysDisabledSymbols = null, Tristate undefinedSymbolValue = default(Tristate), CancellationToken cancellationToken = default(CancellationToken)) { if (filePaths == null || !filePaths.Any()) { throw new ArgumentException("Must specify at least one file path"); } IEnumerable <string> sourcePaths = null; List <Project> projects = new List <Project>(); var firstFileExt = Path.GetExtension(filePaths.First()); if (firstFileExt.EndsWith("proj", StringComparison.OrdinalIgnoreCase)) { filePaths.ToList().ForEach(filePath => { AnalyzerManager manager = new AnalyzerManager(); ProjectAnalyzer analyzer = manager.GetProject(filePath); projects.AddRange(manager.GetWorkspace().CurrentSolution.Projects); }); } else { sourcePaths = filePaths; } var options = new Options( projects: projects, sourcePaths: sourcePaths, symbolConfigurations: symbolConfigurations, alwaysIgnoredSymbols: alwaysIgnoredSymbols, alwaysDefinedSymbols: alwaysDefinedSymbols, alwaysDisabledSymbols: alwaysDisabledSymbols, undefinedSymbolValue: undefinedSymbolValue); return(new AnalysisEngine(options)); }
private Tristate EvaluateDirectiveExpression(DirectiveTriviaSyntax directive, Tristate previousRegionState) { switch (directive.Kind()) { case SyntaxKind.IfDirectiveTrivia: return(EvaluateExpression(((IfDirectiveTriviaSyntax)directive).Condition)); case SyntaxKind.ElifDirectiveTrivia: Tristate result = EvaluateExpression(((ElifDirectiveTriviaSyntax)directive).Condition); return(!previousRegionState & result); case SyntaxKind.ElseDirectiveTrivia: return(!previousRegionState); default: Debug.Assert(false); return(Tristate.Varying); } }
private ImmutableArray <ConditionalRegion> ParseConditionalRegionChain(IList <DirectiveTriviaSyntax> directives, HashSet <DirectiveTriviaSyntax> visitedDirectives) { DirectiveTriviaSyntax previousDirective = null; Tristate previousRegionState = Tristate.False; bool hasEnabledRegion = false; var chain = ImmutableArray.CreateBuilder <ConditionalRegion>(); for (int i = 0; i < directives.Count; i++) { var directive = directives[i]; if (visitedDirectives.Contains(directive)) { // We've already visited this chain of linked directives return(default(ImmutableArray <ConditionalRegion>)); } if (previousDirective != null) { var regionState = EvaluateDirectiveExpression(previousDirective, previousRegionState); previousRegionState = regionState; if (regionState == Tristate.True) { // There can only be one always enabled region per chain regionState = hasEnabledRegion ? Tristate.False : Tristate.True; hasEnabledRegion = true; } var region = new ConditionalRegion(previousDirective, directive, regionState); chain.Add(region); } previousDirective = directive; visitedDirectives.Add(directive); } return(chain.ToImmutable()); }
public static AnalysisEngine FromProjects( IEnumerable <Project> projects, IEnumerable <IEnumerable <string> > symbolConfigurations = null, IEnumerable <string> alwaysIgnoredSymbols = null, IEnumerable <string> alwaysDefinedSymbols = null, IEnumerable <string> alwaysDisabledSymbols = null, Tristate undefinedSymbolValue = default(Tristate)) { if (projects != null && !projects.Any()) { throw new ArgumentException("Must specify at least one project"); } var options = new Options( projects: projects, symbolConfigurations: symbolConfigurations, alwaysIgnoredSymbols: alwaysIgnoredSymbols, alwaysDefinedSymbols: alwaysDefinedSymbols, alwaysDisabledSymbols: alwaysDisabledSymbols, undefinedSymbolValue: undefinedSymbolValue); return(new AnalysisEngine(options)); }
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { Tristate leftState = _expressionEvaluator.EvaluateExpression(node.Left); Tristate rightState = _expressionEvaluator.EvaluateExpression(node.Right); var left = (ExpressionSyntax)node.Left.Accept(this); var right = (ExpressionSyntax)node.Right.Accept(this); if (node.Left != left) { node = node.WithLeft(left); } if (node.Right != right) { node = node.WithRight(right); } if (leftState != Tristate.Varying && rightState != Tristate.Varying) { return(node); } ExpressionSyntax newExpression = null; if (node.Kind() == SyntaxKind.LogicalAndExpression) { if (leftState == Tristate.True) { // true && varying == varying newExpression = right; } else if (rightState == Tristate.True) { // varying && true == varying newExpression = left; } } else if (node.Kind() == SyntaxKind.LogicalOrExpression) { if (leftState == Tristate.False) { // false || varying == varying newExpression = right; } else if (rightState == Tristate.False) { // varying || false == varying newExpression = left; } } if (newExpression != null) { return(newExpression .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia())); } return(node); }