public override List<OutputEntry> Process(DependencyGraph graph, Library element)
        {
            var proj = element as Project;
            if (proj == null)
                return null;

            var result = new List<OutputEntry>();

            var same = graph.OutEdges(proj)
                .Where(d => filter(d, Matchers.NullReporter))
                .GroupBy(d => d.Target)
                .Where(g => g.Count() > 1);

            same.ForEach(g =>
            {
                var message = new OutputMessage();
                message.Append("The project ")
                    .Append(proj, OutputMessage.ProjInfo.Name)
                    .Append(" has multiple dependencies with ")
                    .Append(g.Key, OutputMessage.ProjInfo.Name);

                result.Add(new UniqueDependencyOutputEntry(Severity, message, this, g));
            });

            return result;
        }
        protected BaseOutputEntry(string type, Severity severity, OutputMessage messsage, IEnumerable<Library> projects = null,
            IEnumerable<Dependency> dependencies = null, IEnumerable<ProcessedField> processedFields = null)
        {
            Type = type;
            Severity = severity;
            Messsage = messsage;

            if (dependencies == null)
                dependencies = messsage.Elements.Select(e => e.Dependendcy)
                    .Where(d => d != null)
                    .Distinct();

            Dependencies = dependencies.ToList();
            Dependencies.Sort(Dependency.NaturalOrdering);

            if (projects == null)
                projects = messsage.Elements.Select(e => e.Project)
                    .Concat(Dependencies.Select(d => d.Source))
                    .Concat(Dependencies.Select(d => d.Target))
                    .Where(p => p != null)
                    .Distinct();

            Projects = projects.ToList();
            Projects.Sort(Library.NaturalOrdering);

            ProcessedFields = processedFields != null ? processedFields.ToList() : new List<ProcessedField>();
        }
        public override List<OutputEntry> Process(DependencyGraph graph)
        {
            var result = new List<OutputEntry>();

            graph.Edges.Where(d => filter(d, Matchers.NullReporter))
                .Where(e => e.Source.Equals(e.Target))
                .GroupBy(e => e.Source)
                .ForEach(deps =>
                {
                    var message = new OutputMessage();
                    message.Append(deps.Key, OutputMessage.ProjInfo.Name)
                        .Append(" depends on itself");
                    result.Add(new SelfDependencyRuleMatch(Severity, message, this, deps));
                });

            return result;
        }
        public override List<OutputEntry> Process(DependencyGraph graph)
        {
            var result = new List<OutputEntry>();

            IDictionary<Library, int> components;
            graph.StronglyConnectedComponents(out components);

            var circularDependencies = components.Select(c => new { Proj = c.Key, Group = c.Value })
                .GroupBy(c => c.Group)
                .Where(g => g.Count() > 1);

            foreach (var g in circularDependencies)
            {
                var projs = g.Select(i => i.Proj)
                    .ToList();
                projs.Sort(Library.NaturalOrdering);

                var projsSet = new HashSet<Library>(projs);

                var deps = graph.Edges.Where(e => projsSet.Contains(e.Source) && projsSet.Contains(e.Target));

                var message = new OutputMessage();
                message.Append("Circular dependency found between projects ");

                var first = true;
                foreach (var proj in projs)
                {
                    if (first)
                        first = false;
                    else
                        message.Append(", ");

                    message.Append(proj, OutputMessage.ProjInfo.Name);
                }

                result.Add(new CircularDependencyRuleMatch(Severity, message, this, deps));
            }

            return result;
        }
        public override List<OutputEntry> Process(DependencyGraph graph)
        {
            var result = new List<OutputEntry>();

            var same = graph.Vertices.OfType<Project>()
                .Where(v => filter(v))
                .GroupBy(v => id(v))
                .Where(g => g.Count() > 1);
            same.ForEach(g =>
            {
                var projs = g.ToList();

                var message = new OutputMessage();
                message.Append(projs.Count())
                    .Append(" projects ")
                    .Append(description(projs.First()))
                    .Append(" found");

                result.Add(new UniqueProjectOutputEntry(Severity, message, this, projs));
            });

            return result;
        }
        public override OutputEntry Process(Dependency dep)
        {
            var fields = new List<ProcessedField>();

            if (!Dependency(dep, (f, v, m) => fields.Add(new ProcessedField("Dependency " + f, v, m))))
                return null;

            if (!Matches(Source, dep.Source, (f, v, m) => fields.Add(new ProcessedField("Source " + f, v, m))))
                return null;

            if (!Matches(Target, dep.Target, (f, v, m) => fields.Add(new ProcessedField("Target " + f, v, m))))
                return null;

            var messsage = new OutputMessage();
            messsage.Append("Dependency between ")
                .Append(dep.Source, OutputMessage.ProjInfo.Name)
                .Append(" and ")
                .Append(dep.Target, OutputMessage.ProjInfo.Name)
                .Append(Allow ? "" : " not")
                .Append(" allowed");

            return new DependencyRuleMatch(Allow, "Dependency", Severity, messsage, this, dep.AsList(), fields);
        }
 private static string ToConsole(Dependency dep, OutputMessage.DepInfo info)
 {
     switch (info)
     {
         case OutputMessage.DepInfo.Type:
         {
             switch (dep.Type)
             {
                 case Dependency.Types.LibraryReference:
                     return "library reference";
                 case Dependency.Types.ProjectReference:
                     return "project reference";
                 default:
                     throw new InvalidDataException();
             }
         }
         case OutputMessage.DepInfo.Line:
         {
             return "line " + dep.Location.Line;
         }
         case OutputMessage.DepInfo.FullDescription:
         {
             return string.Format("{0} in {1} of {2} pointing to {3}", ToConsole(dep, OutputMessage.DepInfo.Type),
                 ToConsole(dep, OutputMessage.DepInfo.Line), ToConsole(dep.Source, OutputMessage.ProjInfo.NameAndProjectPath),
                 ToConsole(dep.Target, OutputMessage.ProjInfo.NameAndPath));
         }
         default:
             throw new InvalidDataException();
     }
 }
        private static string ToConsole(Library proj, OutputMessage.ProjInfo info)
        {
            switch (info)
            {
                case OutputMessage.ProjInfo.Name:
                {
                    return string.Join(" or ", proj.SortedNames);
                }
                case OutputMessage.ProjInfo.NameAndGroup:
                {
                    var result = ToConsole(proj, OutputMessage.ProjInfo.Name);

                    var group = proj.GroupElement;
                    if (group != null)
                        result = string.Format("{0} (in group {1})", result, group.Name);

                    return result;
                }
                case OutputMessage.ProjInfo.NameAndProjectPath:
                {
                    return string.Format("{0} ({1})", ToConsole(proj, OutputMessage.ProjInfo.Name), ToConsole(proj, OutputMessage.ProjInfo.ProjectPath));
                }
                case OutputMessage.ProjInfo.NameAndPath:
                {
                    if (proj.Paths.Any())
                        return string.Format("{0} ({1})", ToConsole(proj, OutputMessage.ProjInfo.Name), ToConsole(proj, OutputMessage.ProjInfo.Path));
                    else
                        return ToConsole(proj, OutputMessage.ProjInfo.Name);
                }
                case OutputMessage.ProjInfo.Path:
                {
                    if (proj.Paths.Any())
                        return string.Join(" or ", proj.Paths);
                    else
                        return ToConsole(proj, OutputMessage.ProjInfo.Name);
                }
                case OutputMessage.ProjInfo.ProjectPath:
                {
                    if (proj is Project)
                        return ((Project) proj).ProjectPath;
                    else
                        throw new InvalidDataException();
                }
                default:
                    throw new InvalidDataException();
            }
        }
        public static string ToConsole(OutputMessage messsage)
        {
            return string.Join("", messsage.Elements.Select(e =>
            {
                if (e.Text != null)
                    return e.Text;

                else if (e.Project != null)
                    return ToConsole(e.Project, e.ProjInfo);

                else if (e.Dependendcy != null)
                    return ToConsole(e.Dependendcy, e.DepInfo);

                else
                    throw new InvalidDataException();
            }));
        }
 public UniqueProjectOutputEntry(Severity severity, OutputMessage messsage, Rule rule, IEnumerable<Library> projs)
     : base("Non unique project", severity, messsage, rule, projs, null)
 {
 }
        private OutputEntry CreateMultipleReferencesWarning(List<Library> candidates, Project proj, Dependency dep, string refName)
        {
            var message = new OutputMessage().Append("The project ")
                .Append(proj, OutputMessage.ProjInfo.NameAndProjectPath)
                .Append(" references the project ")
                .Append(refName)
                .Append(", but there are ")
                .Append(candidates.Count)
                .Append(" projects that match:");

            candidates.ForEach(c => message.Append("\n  - ")
                .Append(c, OutputMessage.ProjInfo.ProjectPath));
            message.Append("\nMultiple dependencies will be created.");

            return new LoadingOutputEntry("Multiple projects found", message, candidates.Select(dep.WithTarget)
                .ToArray());
        }
 protected BaseOutputEntry(string type, Severity severity, OutputMessage messsage, IEnumerable<Dependency> dependencies)
     : this(type, severity, messsage, null, dependencies)
 {
 }
 public LoadingOutputEntry(string type, OutputMessage messsage, params Dependency[] dependencies)
     : base("Loading/" + type, Severity.Info, messsage, dependencies)
 {
 }
        private void WarnIfSimilarFound(List<Library> result, Project proj, Dependency dep, string filename, string refName)
        {
            if (result == null || !result.Any())
                return;

            var message = new OutputMessage().Append("The project ")
                .Append(proj, OutputMessage.ProjInfo.Name)
                .Append(" references the project ")
                .Append(filename)
                .Append(" but it could not be loaded. Using project")
                .Append(result.Count > 1 ? "s" : "")
                .Append(" ")
                .Append(refName)
                .Append(" instead:");

            if (result.Count == 1)
                result.ForEach(p => message.Append(result.First(), OutputMessage.ProjInfo.ProjectPath));
            else
                result.ForEach(p => message.Append("\n  - ")
                    .Append(p, OutputMessage.ProjInfo.ProjectPath));

            warnings.Add(new LoadingOutputEntry("Only similar project found", message, result.Select(dep.WithTarget)
                .ToArray()));
        }
 protected RuleOutputEntry(string type, Severity severity, OutputMessage messsage, Rule rule, IEnumerable<Library> projects = null,
     IEnumerable<Dependency> dependencies = null, IEnumerable<ProcessedField> processedFields = null)
     : base(type, severity, messsage, projects, dependencies, processedFields)
 {
     Rule = rule;
 }
 protected RuleOutputEntry(string type, Severity severity, OutputMessage messsage, Rule rule, IEnumerable<Dependency> dependencies)
     : base(type, severity, messsage, dependencies)
 {
     Rule = rule;
 }
 public DependencyRuleMatch(bool allowed, string type, Severity severity, OutputMessage messsage, Rule rule, IEnumerable<Dependency> deps,
     IEnumerable<ProcessedField> processedFields)
     : base(type, severity, messsage, rule, null, deps.ToList(), processedFields)
 {
     Allowed = allowed;
 }
 public CircularDependencyRuleMatch(Severity severity, OutputMessage messsage, Rule rule, IEnumerable<Dependency> deps)
     : base("Circular dependency", severity, messsage, rule, deps)
 {
 }
 public UniqueDependencyOutputEntry(Severity severity, OutputMessage messsage, Rule rule, IEnumerable<Dependency> deps)
     : base("Non unique dependency", severity, messsage, rule, deps.ToList())
 {
 }
        private static void LoadProjects(List<string> paths, DependencyGraphBuilder builder, List<OutputEntry> warnings, string filenamePattern,
            params string[] defaultLanguage)
        {
            var csprojsFiles =
                new HashSet<string>(paths.SelectMany(folder => Directory.GetFiles(folder, filenamePattern, SearchOption.AllDirectories))
                    .Select(Path.GetFullPath));

            List<VSProjReader> csprojs = csprojsFiles.Select(f => new VSProjReader(f))
                .OrderBy(n => n.Filename, StringComparer.CurrentCultureIgnoreCase)
                .ToList();
            foreach (VSProjReader csproj in csprojs)
            {
                object proj = builder.AddProject(csproj.Name, csproj.AssemblyName, csproj.ProjectGuid, csproj.Filename, defaultLanguage);

                foreach (VSProjReader.ProjectReference csref in csproj.ProjectReferences)
                    builder.AddProjectReference(proj, csref.Name, null, csref.ProjectGuid, csref.Include, new Location(csproj.Filename, csref.LineNumber),
                        defaultLanguage);

                foreach (VSProjReader.Reference csref in csproj.References)
                {
                    IEnumerable<string> language;
                    if (csref.HintPath == null && csref.Include.GetPublicKey() == null)
                        // A system lib
                        language = defaultLanguage;
                    else
                        language = null;

                    builder.AddLibraryReference(proj, null, csref.Include.Name, null, csref.HintPath, new Location(csproj.Filename, csref.LineNumber),
                        language);
                }

                foreach (VSProjReader.COMReference csref in csproj.COMReferences)
                    builder.AddLibraryReference(proj, null, csref.Include, csref.Guid, null, new Location(csproj.Filename, csref.LineNumber), null);
            }

            var externalCsprojFiles = csprojs.SelectMany(p => p.ProjectReferences)
                .Select(r => r.Include)
                .Distinct()
                .Where(f => !csprojsFiles.Contains(f))
                .OrderBy(n => n, StringComparer.CurrentCultureIgnoreCase);
            foreach (string externalCsprojFile in externalCsprojFiles)
            {
                if (paths.Any(p => externalCsprojFile.StartsWith(p + Path.DirectorySeparatorChar)))
                {
                    OutputMessage msg = new OutputMessage().Append("Failed to load a referenced project: ")
                        .Append(externalCsprojFile);
                    warnings.Add(new LoadingOutputEntry("Referenced project not found", msg));
                    continue;
                }

                try
                {
                    var csproj = new VSProjReader(externalCsprojFile);
                    builder.AddProject(csproj.Name, csproj.AssemblyName, csproj.ProjectGuid, csproj.Filename, defaultLanguage);
                }
                catch (IOException)
                {
                    OutputMessage msg = new OutputMessage().Append("Failed to load a project outside of input folders: ")
                        .Append(externalCsprojFile);
                    warnings.Add(new LoadingOutputEntry("External project not found", msg));
                }
            }
        }
        private Project CreateFakeProject(Project proj, Dependency dep, TempReference reference)
        {
            var result = new Project(reference.ReferenceName ?? reference.ReferenceLibraryName,
                reference.ReferenceLibraryName ?? reference.ReferenceName, reference.ReferenceGuid ?? Guid.NewGuid(), reference.ReferenceFilename, null);

            if (Ignore(result))
                return null;

            if (reference.ReferenceName == null || reference.ReferenceLibraryName == null)
            {
                var guessed = reference.ReferenceName == null ? "project name" : "library name";
                var used = reference.ReferenceName == null ? "library name" : "project name";

                var msg = new OutputMessage().Append("The project ")
                    .Append(proj, OutputMessage.ProjInfo.Name)
                    .Append(" references the project ")
                    .Append(reference.ReferenceFilename ?? reference.ReferenceName ?? reference.ReferenceLibraryName)
                    .Append(" but it could not be loaded. Guessing the ")
                    .Append(guessed)
                    .Append(" to be the same as the ")
                    .Append(used)
                    .Append(".");

                warnings.Add(new LoadingOutputEntry("Project not found", msg, dep.WithTarget(result)));
            }

            AddLibrary(result);

            return result;
        }