1/*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SKSL_ERROR_REPORTER
9#define SKSL_ERROR_REPORTER
10
11#include "include/core/SkStringView.h"
12#include "include/core/SkTypes.h"
13#include "include/private/SkSLString.h"
14
15#include <string>
16#include <vector>
17
18namespace SkSL {
19
20#ifndef __has_builtin
21    #define __has_builtin(x) 0
22#endif
23
24class PositionInfo {
25public:
26    PositionInfo(const char* file = nullptr, int line = -1)
27        : fFile(file)
28        , fLine(line) {}
29
30#if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE)
31    static PositionInfo Capture(const char* file = __builtin_FILE(), int line = __builtin_LINE()) {
32        return PositionInfo(file, line);
33    }
34#else
35    static PositionInfo Capture() { return PositionInfo(); }
36#endif // __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE)
37
38    const char* file_name() const {
39        return fFile;
40    }
41
42    int line() {
43        return fLine;
44    }
45
46private:
47    const char* fFile = nullptr;
48    int32_t fLine = -1;
49};
50
51/**
52 * Class which is notified in the event of an error.
53 */
54class ErrorReporter {
55public:
56    ErrorReporter() {}
57
58    virtual ~ErrorReporter() {
59        SkASSERT(fPendingErrors.empty());
60    }
61
62    void error(skstd::string_view msg, PositionInfo position);
63
64    /**
65     * Reports an error message at the given line of the source text. Errors reported
66     * with a line of -1 will be queued until line number information can be determined.
67     */
68    void error(int line, skstd::string_view msg);
69
70    const char* source() const { return fSource; }
71
72    void setSource(const char* source) { fSource = source; }
73
74    void reportPendingErrors(PositionInfo pos) {
75        for (const String& msg : fPendingErrors) {
76            this->handleError(msg, pos);
77        }
78        fPendingErrors.clear();
79    }
80
81    int errorCount() const {
82        return fErrorCount;
83    }
84
85    void resetErrorCount() {
86        fErrorCount = 0;
87    }
88
89protected:
90    /**
91     * Called when an error is reported.
92     */
93    virtual void handleError(skstd::string_view msg, PositionInfo position) = 0;
94
95private:
96    PositionInfo position(int offset) const;
97
98    const char* fSource = nullptr;
99    std::vector<String> fPendingErrors;
100    int fErrorCount = 0;
101};
102
103/**
104 * Error reporter for tests that need an SkSL context; aborts immediately if an error is reported.
105 */
106class TestingOnly_AbortErrorReporter : public ErrorReporter {
107public:
108    void handleError(skstd::string_view msg, PositionInfo pos) override {
109        SK_ABORT("%.*s", (int)msg.length(), msg.data());
110    }
111};
112
113} // namespace SkSL
114
115#endif
116