OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / libs / cplusplus / BackwardsScanner.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33 #include "BackwardsScanner.h"
34 #include <Token.h>
35 #include <QtGui/QTextCursor>
36 #include <QTextDocument>
37
38 using namespace CPlusPlus;
39
40 BackwardsScanner::BackwardsScanner(const QTextCursor &cursor,
41                                    int maxBlockCount,
42                                    const QString &suffix,
43                                    bool skipComments)
44     : _offset(0)
45     , _blocksTokenized(0)
46     , _block(cursor.block())
47     , _maxBlockCount(maxBlockCount)
48 {
49     _tokenize.setQtMocRunEnabled(true);
50     _tokenize.setSkipComments(skipComments);
51     _tokenize.setObjCEnabled(true);
52     _text = _block.text().left(cursor.position() - cursor.block().position());
53
54     if (! suffix.isEmpty())
55         _text += suffix;
56
57     _tokens.append(_tokenize(_text, previousBlockState(_block)));
58
59     _startToken = _tokens.size();
60 }
61
62 Token BackwardsScanner::LA(int index) const
63 { return const_cast<BackwardsScanner *>(this)->fetchToken(_startToken - index); }
64
65 Token BackwardsScanner::operator[](int index) const
66 { return const_cast<BackwardsScanner *>(this)->fetchToken(index); }
67
68 const Token &BackwardsScanner::fetchToken(int tokenIndex)
69 {
70     while (_offset + tokenIndex < 0) {
71         _block = _block.previous();
72         if (_blocksTokenized == _maxBlockCount || !_block.isValid()) {
73             ++_offset;
74             _tokens.prepend(Token()); // sentinel
75             break;
76         } else {
77             ++_blocksTokenized;
78
79             QString blockText = _block.text();
80             _text.prepend(QLatin1Char('\n'));
81             _text.prepend(blockText);
82
83             QList<Token> adaptedTokens;
84             for (int i = 0; i < _tokens.size(); ++i) {
85                 Token t = _tokens.at(i);
86                 t.offset += + blockText.length() + 1;
87                 adaptedTokens.append(t);
88             }
89
90             _tokens = _tokenize(blockText, previousBlockState(_block));
91             _offset += _tokens.size();
92             _tokens += adaptedTokens;
93         }
94     }
95
96     return _tokens.at(_offset + tokenIndex);
97 }
98
99 int BackwardsScanner::startToken() const
100 { return _startToken; }
101
102 int BackwardsScanner::startPosition() const
103 { return _block.position(); }
104
105 QString BackwardsScanner::text() const
106 { return _text; }
107
108 QString BackwardsScanner::mid(int index) const
109 {
110     const Token &firstToken = _tokens.at(index + _offset);
111     return _text.mid(firstToken.begin());
112 }
113
114 QString BackwardsScanner::text(int index) const
115 {
116     const Token &firstToken = _tokens.at(index + _offset);
117     return _text.mid(firstToken.begin(), firstToken.length());
118 }
119
120 QStringRef BackwardsScanner::textRef(int index) const
121 {
122     const Token &firstToken = _tokens.at(index + _offset);
123     return _text.midRef(firstToken.begin(), firstToken.length());
124 }
125
126 int BackwardsScanner::size() const
127 {
128     return _tokens.size();
129 }
130
131 int BackwardsScanner::startOfMatchingBrace(int index) const
132 {
133     const BackwardsScanner &tk = *this;
134
135     if (tk[index - 1].is(T_RPAREN)) {
136         int i = index - 1;
137         int count = 0;
138         do {
139             if (tk[i].is(T_LPAREN)) {
140                 if (! ++count)
141                     return i;
142             } else if (tk[i].is(T_RPAREN))
143                 --count;
144             --i;
145         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL));
146     } else if (tk[index - 1].is(T_RBRACKET)) {
147         int i = index - 1;
148         int count = 0;
149         do {
150             if (tk[i].is(T_LBRACKET)) {
151                 if (! ++count)
152                     return i;
153             } else if (tk[i].is(T_RBRACKET))
154                 --count;
155             --i;
156         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL));
157     } else if (tk[index - 1].is(T_RBRACE)) {
158         int i = index - 1;
159         int count = 0;
160         do {
161             if (tk[i].is(T_LBRACE)) {
162                 if (! ++count)
163                     return i;
164             } else if (tk[i].is(T_RBRACE))
165                 --count;
166             --i;
167         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL));
168     } else if (tk[index - 1].is(T_GREATER)) {
169         int i = index - 1;
170         int count = 0;
171         do {
172             if (tk[i].is(T_LESS)) {
173                 if (! ++count)
174                     return i;
175             } else if (tk[i].is(T_GREATER))
176                 --count;
177             --i;
178         } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL));
179     } else {
180         Q_ASSERT(0);
181     }
182
183     return index;
184 }
185
186 int BackwardsScanner::startOfLine(int index) const
187 {
188     const BackwardsScanner tk(*this);
189
190     forever {
191         const Token &tok = tk[index - 1];
192
193         if (tok.is(T_EOF_SYMBOL))
194             break;
195         else if (tok.newline())
196             return index - 1;
197
198         --index;
199     }
200
201     return index;
202 }
203
204 int BackwardsScanner::startOfBlock(int index) const
205 {
206     const BackwardsScanner tk(*this);
207
208     const int start = index;
209
210     forever {
211         Token token = tk[index - 1];
212
213         if (token.is(T_EOF_SYMBOL)) {
214             break;
215
216         } else if (token.is(T_GREATER)) {
217             const int matchingBrace = startOfMatchingBrace(index);
218
219             if (matchingBrace != index && tk[matchingBrace - 1].is(T_TEMPLATE))
220                 index = matchingBrace;
221
222         } else if (token.is(T_RPAREN) || token.is(T_RBRACKET) || token.is(T_RBRACE)) {
223             const int matchingBrace = startOfMatchingBrace(index);
224
225             if (matchingBrace != index)
226                 index = matchingBrace;
227
228         } else if (token.is(T_LPAREN) || token.is(T_LBRACKET)) {
229             break; // unmatched brace
230
231         } else if (token.is(T_LBRACE)) {
232             return index - 1;
233
234         }
235
236         --index;
237     }
238
239     return start;
240 }
241
242 QString BackwardsScanner::indentationString(int index) const
243 {
244     const Token tokenAfterNewline = operator[](startOfLine(index + 1));
245     const int newlinePos = qMax(0, _text.lastIndexOf(QLatin1Char('\n'),
246                                                      tokenAfterNewline.begin()));
247     return _text.mid(newlinePos, tokenAfterNewline.begin() - newlinePos);
248 }
249
250
251 int BackwardsScanner::previousBlockState(const QTextBlock &block)
252 {
253     const QTextBlock prevBlock = block.previous();
254
255     if (prevBlock.isValid()) {
256         int state = prevBlock.userState();
257
258         if (state != -1)
259             return state;
260     }
261
262     return 0;
263 }