1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLJSSOURCELOCATION_P_H
5#define QQMLJSSOURCELOCATION_P_H
6
7#include <QtCore/private/qglobal_p.h>
8#include <QtCore/qhashfunctions.h>
9
10//
11// W A R N I N G
12// -------------
13//
14// This file is not part of the Qt API. It exists purely as an
15// implementation detail. This header file may change from version to
16// version without notice, or even be removed.
17//
18// We mean it.
19//
20
21QT_BEGIN_NAMESPACE
22
23namespace QQmlJS {
24
25class SourceLocation
26{
27public:
28 explicit SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
29 : offset(offset), length(length),
30 startLine(line), startColumn(column)
31 { }
32
33private:
34 struct LocationInfo
35 {
36 quint32 offset;
37 quint32 startLine;
38 quint32 startColumn;
39 };
40
41 template <typename Predicate>
42 static LocationInfo findLocationIf(QStringView text, Predicate &&predicate,
43 const SourceLocation &startHint = SourceLocation{})
44 {
45 quint32 i = startHint.isValid() ? startHint.offset : 0;
46 quint32 endLine = startHint.isValid() ? startHint.startLine : 1;
47 quint32 endColumn = startHint.isValid() ? startHint.startColumn : 1;
48 const quint32 end = quint32(text.size());
49
50 for (; i < end; ++i) {
51 if (predicate(i, endLine, endColumn))
52 return LocationInfo{ .offset: i, .startLine: endLine, .startColumn: endColumn };
53
54 const QChar currentChar = text.at(n: i);
55 const bool isLineFeed = currentChar == u'\n';
56 const bool isCarriageReturn = currentChar == u'\r';
57 // note: process the newline on the "\n" part of "\r\n", and treat "\r" as normal
58 // character
59 const bool isHalfANewline =
60 isCarriageReturn && (i + 1 < end && text.at(n: i + 1) == u'\n');
61
62 if (isHalfANewline || (!isCarriageReturn && !isLineFeed)) {
63 ++endColumn;
64 continue;
65 }
66
67 // catch positions after the end of the line
68 if (predicate(i, endLine, std::numeric_limits<quint32>::max()))
69 return LocationInfo{ .offset: i, .startLine: endLine, .startColumn: endColumn };
70
71 // catch positions after the end of the file and return the last character of the last
72 // line
73 if (i == end - 1) {
74 if (predicate(i, std::numeric_limits<quint32>::max(),
75 std::numeric_limits<quint32>::max())) {
76 return LocationInfo{ .offset: i, .startLine: endLine, .startColumn: endColumn };
77 }
78 }
79
80 ++endLine;
81 endColumn = 1;
82 }
83
84 // not found, return last position
85 return LocationInfo{ .offset: i, .startLine: endLine, .startColumn: endColumn };
86 }
87
88public:
89 static quint32 offsetFrom(QStringView text, quint32 line, quint32 column,
90 const SourceLocation &startHint = SourceLocation{})
91 {
92 // sanity check that hint can actually be used
93 const SourceLocation hint =
94 (startHint.startLine < line
95 || (startHint.startLine == line && startHint.startColumn <= column))
96 ? startHint
97 : SourceLocation{};
98
99 const auto result = findLocationIf(
100 text,
101 predicate: [line, column](quint32, quint32 currentLine, quint32 currentColumn) {
102 return line <= currentLine && column <= currentColumn;
103 },
104 startHint: hint);
105 return result.offset;
106 }
107 static std::pair<quint32, quint32>
108 rowAndColumnFrom(QStringView text, quint32 offset,
109 const SourceLocation &startHint = SourceLocation{})
110 {
111 // sanity check that hint can actually be used
112 const SourceLocation hint = startHint.offset <= offset ? startHint : SourceLocation{};
113
114 const auto result = findLocationIf(
115 text,
116 predicate: [offset](quint32 currentOffset, quint32, quint32) {
117 return offset == currentOffset;
118 },
119 startHint: hint);
120 return std::make_pair(x: result.startLine, y: result.startColumn);
121 }
122
123 bool isValid() const { return *this != SourceLocation(); }
124
125 quint32 begin() const { return offset; }
126 quint32 end() const { return offset + length; }
127
128 // Returns a zero length location at the start of the current one.
129 SourceLocation startZeroLengthLocation() const
130 {
131 return SourceLocation(offset, 0, startLine, startColumn);
132 }
133 // Returns a zero length location at the end of the current one.
134 SourceLocation endZeroLengthLocation(QStringView text) const
135 {
136 auto [row, column] = rowAndColumnFrom(text, offset: offset + length, startHint: *this);
137 return SourceLocation{ offset + length, 0, row, column };
138 }
139
140// attributes
141 // ### encode
142 quint32 offset;
143 quint32 length;
144 quint32 startLine;
145 quint32 startColumn;
146
147 friend size_t qHash(const SourceLocation &location, size_t seed = 0)
148 {
149 return qHashMulti(seed, args: location.offset, args: location.length,
150 args: location.startLine, args: location.startColumn);
151 }
152
153 friend bool operator==(const SourceLocation &a, const SourceLocation &b)
154 {
155 return a.offset == b.offset && a.length == b.length
156 && a.startLine == b.startLine && a.startColumn == b.startColumn;
157 }
158
159 friend bool operator!=(const SourceLocation &a, const SourceLocation &b) { return !(a == b); }
160
161 // Returns a source location starting at the beginning of l1, l2 and ending at the end of them.
162 // Ignores invalid source locations.
163 friend SourceLocation combine(const SourceLocation &l1, const SourceLocation &l2) {
164 quint32 e = qMax(a: l1.end(), b: l2.end());
165 SourceLocation res;
166 if (l1.offset <= l2.offset)
167 res = (l1.isValid() ? l1 : l2);
168 else
169 res = (l2.isValid() ? l2 : l1);
170 res.length = e - res.offset;
171 return res;
172 }
173};
174
175} // namespace QQmlJS
176
177QT_END_NAMESPACE
178
179#endif
180

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qml/common/qqmljssourcelocation_p.h