aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/public/issue/yql_issue_utils.cpp
blob: 2be0b8e57bb0a1241dc4b772d23e524d5db7bcf3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "yql_issue_utils.h"

#include <util/system/yassert.h>

#include <tuple>
#include <list>
#include <algorithm>
#include <deque>

namespace NYql {

TIssue TruncateIssueLevels(const TIssue& topIssue, TTruncateIssueOpts opts) {
    // [issue, level, parent, visibleParent]
    std::list<std::tuple<const TIssue*, ui32, size_t, size_t>> issueQueue;
    // [issue, targetIssue, level, parent, visible, visibleParent, targetSkipIssue]
    std::deque<std::tuple<const TIssue*, TIssue*, ui32, size_t, bool, size_t, TIssue*>> issues;
    // [depth from bottom, position]
    std::list<size_t> leafs;

    const auto depthBeforeLeaf = std::max(opts.KeepTailLevels, ui32(1)) - 1;
    const auto maxLevels = std::max(opts.MaxLevels - std::min(opts.MaxLevels, depthBeforeLeaf + 1), ui32(1));

    issueQueue.emplace_front(&topIssue, 0, 0, 0);
    while (!issueQueue.empty()) {
        const auto issue = std::get<0>(issueQueue.back());
        const auto level = std::get<1>(issueQueue.back());
        const auto parent = std::get<2>(issueQueue.back());
        const auto visibleParent = std::get<3>(issueQueue.back());
        issueQueue.pop_back();

        const bool visible = issue->GetSubIssues().empty() || level < maxLevels;
        const auto pos = issues.size();
        issues.emplace_back(issue, nullptr, level, parent, visible, visibleParent, nullptr);
        if (issue->GetSubIssues().empty()) {
            if (level != 0) {
                leafs.push_back(pos);
            }
        } else {
            for (auto subIssue : issue->GetSubIssues()) {
                issueQueue.emplace_front(subIssue.Get(), level + 1, pos, visible ? pos : visibleParent);
            }
        }
    }

    if (depthBeforeLeaf && !leafs.empty()) {
        for (size_t pos: leafs) {
            ui32 depth = depthBeforeLeaf;
            auto parent = std::get<3>(issues.at(pos));
            while (depth && parent) {
                auto& visible = std::get<4>(issues.at(parent));
                auto& visibleParent = std::get<5>(issues.at(pos));
                if (!visible || visibleParent != parent) {
                    visible = true;
                    visibleParent = parent; // Update visible parent
                    --depth;
                    pos = parent;
                    parent = std::get<3>(issues.at(parent));
                } else {
                    break;
                }
            }
        }
    }
    leafs.clear();

    TIssue result;
    for (auto& i: issues) {
        const auto srcIssue = std::get<0>(i);
        auto& targetIssue = std::get<1>(i);
        const auto level = std::get<2>(i);
        const auto parent = std::get<3>(i);
        const auto visible = std::get<4>(i);
        const auto visibleParent = std::get<5>(i);

        if (0 == level) {
            targetIssue = &result;
            targetIssue->CopyWithoutSubIssues(*srcIssue);
        } else if (visible) {
            auto& parentRec = issues.at(visibleParent);
            auto& parentTargetIssue = std::get<1>(parentRec);
            if (parent != visibleParent) {
                auto& parentSkipIssue = std::get<6>(parentRec);
                if (!parentSkipIssue) {
                    const auto parentIssue = std::get<0>(parentRec);
                    auto newIssue = MakeIntrusive<TIssue>("(skipped levels)");
                    newIssue->SetCode(parentIssue->GetCode(), parentIssue->GetSeverity());
                    parentTargetIssue->AddSubIssue(newIssue);
                    parentSkipIssue = newIssue.Get();
                }
                auto newIssue = MakeIntrusive<TIssue>(TString{});
                newIssue->CopyWithoutSubIssues(*srcIssue);
                parentSkipIssue->AddSubIssue(newIssue);
                targetIssue = newIssue.Get();
            } else {
                auto newIssue = MakeIntrusive<TIssue>(TString{});
                newIssue->CopyWithoutSubIssues(*srcIssue);
                parentTargetIssue->AddSubIssue(newIssue);
                targetIssue = newIssue.Get();
            }
        }
    }
    return result;
}

} // namspace NYql