HaxeCheckstyle/haxe-checkstyle

View on GitHub
src/checkstyle/reporter/ReporterManager.hx

Summary

Maintainability
Test Coverage
package checkstyle.reporter;

import checkstyle.Message;
import checkstyle.checks.Category;
import checkstyle.utils.Mutex;

class ReporterManager {
    public static var INSTANCE:ReporterManager = new ReporterManager();
    public static var SHOW_PARSE_ERRORS:Bool = false;

    var reporters:Array<IReporter>;
    var delayedMessageCallbacks:Array<DelayedMessageCallback>;
    var lock:Mutex;

    function new() {
        #if (debug || unittest)
        SHOW_PARSE_ERRORS = true;
        #end
        clear();
        lock = new Mutex();
    }

    public function clear() {
        reporters = [];
        delayedMessageCallbacks = [];
    }

    public function addDelayedMessageCallback(callback:DelayedMessageCallback) {
        delayedMessageCallbacks.push(callback);
    }

    public function addReporter(r:IReporter) {
        reporters.push(r);
    }

    public function start() {
        for (reporter in reporters) reporter.start();
    }

    public function finish() {
        for (delayedMessage in delayedMessageCallbacks) {
            addMessages(delayedMessage());
        }
        for (reporter in reporters) reporter.finish();
    }

    public function addFile(f:CheckFile) {
        lock.acquire();
        for (reporter in reporters) reporter.addFile(f);
        lock.release();
    }

    public function addError(f:CheckFile, e:Any, name:String) {
        if (!SHOW_PARSE_ERRORS) return;
        lock.acquire();
        for (reporter in reporters) reporter.addMessage(getErrorMessage(e, f.name, "Check " + name));
        lock.release();
    }

    public function addMessages(messages:Array<Message>) {
        if ((messages == null) || (messages.length <= 0)) return;
        lock.acquire();
        messages = filterDuplicateMessages(messages);
        for (reporter in reporters) for (m in messages) reporter.addMessage(m);
        lock.release();
    }

    function filterDuplicateMessages(messages:Array<Message>):Array<Message> {
        var filteredMessages = [];
        for (message in messages) {
            var anyDuplicates = false;
            for (filteredMessage in filteredMessages) {
                if (areMessagesSame(message, filteredMessage)) {
                    anyDuplicates = true;
                    break;
                }
            }
            if (!anyDuplicates) filteredMessages.push(message);
        }
        return filteredMessages;
    }

    function areMessagesSame(a:Message, b:Message):Bool {
        if (a.message != b.message || a.severity != b.severity || a.moduleName != b.moduleName || !messageLocationSame(a, b)) {
            return false;
        }
        if ((a.code == null && b.code != null) || (a.code != null && b.code == null) || (a.code != b.code)) {
            return false;
        }
        if (a.related == null && b.related == null) {
            return true;
        }
        if (a.related == null || b.related == null) {
            return false;
        }
        if (a.related.length != b.related.length) {
            return false;
        }
        for (index in 0...a.related.length) {
            if (!messageLocationSame(a.related[index], b.related[index])) {
                return false;
            }
        }
        return true;
    }

    function messageLocationSame(a:MessageLocation, b:MessageLocation):Bool {
        return (a.fileName == b.fileName && messageRangeSame(a.range, b.range));
    }

    function messageRangeSame(a:MessageRange, b:MessageRange):Bool {
        return ((a.start.line == b.start.line) && (a.start.column == b.start.column) && (a.end.line == b.end.line) && (a.end.column == b.end.column));
    }

    function getErrorMessage(e:Any, fileName:String, step:String):Message {
        return {
            fileName: fileName,
            range: {
                start: {
                    line: 1,
                    column: 0
                },
                end: {
                    line: 1,
                    column: 0
                }
            },
            severity: ERROR,
            moduleName: "Checker",
            categories: [Category.STYLE],
            points: 1,
            desc: "",
            code: '$e',
            message: '$step failed: $e\nPlease file a github issue at https://github.com/HaxeCheckstyle/haxe-checkstyle/issues',
            related: []
        };
    }
}

typedef DelayedMessageCallback = () -> Array<Message>;