private ImmutableArray<Diagnostic> CheckDependencies(CSharpCompilation compilation, IList<Tuple<AttributeData, ISymbol>> dependencies, INamedTypeSymbol recognizerType) { string[] ruleNames = GetRuleNames(recognizerType); int[] ruleVersions = GetRuleVersions(recognizerType, ruleNames); RuleRelations relations = ExtractRuleRelations(recognizerType); ImmutableArray<Diagnostic>.Builder errors = ImmutableArray.CreateBuilder<Diagnostic>(); foreach (var dependency in dependencies) { if (ruleNames == null) { Location location = GetRecognizerTypeLocation(dependency.Item1); errors.Add(Diagnostic.Create(AnalysisError, location, "could not read rule names from generated parser")); continue; } if (ruleVersions == null) { Location location = GetRecognizerTypeLocation(dependency.Item1); errors.Add(Diagnostic.Create(AnalysisError, location, "could not read rule versions from generated parser")); continue; } if (relations == null) { Location location = GetRecognizerTypeLocation(dependency.Item1); errors.Add(Diagnostic.Create(AnalysisError, location, "could not read the ATN from the generated parser")); continue; } if (!compilation.ClassifyConversion(recognizerType, GetRecognizerType(dependency.Item1)).IsImplicit) { Location location = GetRecognizerTypeLocation(dependency.Item1); errors.Add(Diagnostic.Create(AnalysisError, location, string.Format("could not convert '{0}' to '{1}'", recognizerType, GetRecognizerType(dependency.Item1)))); continue; } // this is the rule in the dependency set with the highest version number int effectiveRule = GetRule(dependency.Item1); if (effectiveRule < 0 || effectiveRule >= ruleVersions.Length) { Location location = GetRuleLocation(dependency.Item1); errors.Add(Diagnostic.Create(UnknownRule, location, GetRule(dependency.Item1), GetRecognizerType(dependency.Item1))); continue; } Dependents dependents = Dependents.Self | (GetDependents(dependency.Item1) ?? Dependents.Parents); bool containsUnimplemented = ReportUnimplementedDependents(errors, dependency, ruleNames, dependents); bool[] @checked = new bool[ruleNames.Length]; int highestRequiredDependency = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions, effectiveRule, null); if ((dependents & Dependents.Parents) != 0) { bool[] parents = relations.parents[GetRule(dependency.Item1)]; for (int parent = Array.IndexOf(parents, true, 0); parent >= 0; parent = Array.IndexOf(parents, true, parent + 1)) { if (parent >= ruleVersions.Length) { errors.Add(Diagnostic.Create(AnalysisError, GetLocation(dependency.Item1), "parent index out of range during analysis")); continue; } if (@checked[parent]) continue; @checked[parent] = true; int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions, parent, "parent"); highestRequiredDependency = Math.Max(highestRequiredDependency, required); } } if ((dependents & Dependents.Children) != 0) { bool[] children = relations.children[GetRule(dependency.Item1)]; for (int child = Array.IndexOf(children, true, 0); child >= 0; child = Array.IndexOf(children, true, child + 1)) { if (child >= ruleVersions.Length) { errors.Add(Diagnostic.Create(AnalysisError, GetLocation(dependency.Item1), "child index out of range during analysis")); continue; } if (@checked[child]) continue; @checked[child] = true; int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions, child, "child"); highestRequiredDependency = Math.Max(highestRequiredDependency, required); } } if ((dependents & Dependents.Ancestors) != 0) { bool[] ancestors = relations.GetAncestors(GetRule(dependency.Item1)); for (int ancestor = Array.IndexOf(ancestors, true, 0); ancestor >= 0; ancestor = Array.IndexOf(ancestors, true, ancestor + 1)) { if (ancestor >= ruleVersions.Length) { errors.Add(Diagnostic.Create(AnalysisError, GetLocation(dependency.Item1), "ancestor index out of range during analysis")); continue; } if (@checked[ancestor]) continue; @checked[ancestor] = true; int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions, ancestor, "ancestor"); highestRequiredDependency = Math.Max(highestRequiredDependency, required); } } if ((dependents & Dependents.Descendants) != 0) { bool[] descendants = relations.GetDescendants(GetRule(dependency.Item1)); for (int descendant = Array.IndexOf(descendants, true, 0); descendant >= 0; descendant = Array.IndexOf(descendants, true, descendant + 1)) { if (descendant >= ruleVersions.Length) { errors.Add(Diagnostic.Create(AnalysisError, GetLocation(dependency.Item1), "descendant index out of range during analysis")); continue; } if (@checked[descendant]) continue; @checked[descendant] = true; int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions, descendant, "descendant"); highestRequiredDependency = Math.Max(highestRequiredDependency, required); } } int declaredVersion = GetVersion(dependency.Item1); if (declaredVersion > highestRequiredDependency && !containsUnimplemented) { Location location = Location.Create(dependency.Item1.ApplicationSyntaxReference.SyntaxTree, dependency.Item1.ApplicationSyntaxReference.Span); errors.Add(Diagnostic.Create(VersionTooHigh, location, ruleNames[GetRule(dependency.Item1)], highestRequiredDependency, declaredVersion, GetRecognizerType(dependency.Item1))); } } return errors.ToImmutable(); }