1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
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
16 ** GNU Lesser General Public License Usage
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.
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.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "ExpressionUnderCursor.h"
35 #include "SimpleLexer.h"
36 #include "BackwardsScanner.h"
39 #include <QTextCursor>
42 using namespace CPlusPlus;
44 ExpressionUnderCursor::ExpressionUnderCursor()
48 ExpressionUnderCursor::~ExpressionUnderCursor()
51 int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index)
53 if (tk[index - 1].is(T_GREATER)) {
54 const int matchingBraceIndex = tk.startOfMatchingBrace(index);
56 if (tk[matchingBraceIndex - 1].is(T_IDENTIFIER))
57 index = matchingBraceIndex - 1;
60 index = startOfExpression_helper(tk, index);
63 const Token &tok = tk[index - 1];
77 return startOfExpression(tk, index - 1);
86 int ExpressionUnderCursor::startOfExpression_helper(BackwardsScanner &tk, int index)
88 if (tk[index - 1].isLiteral()) {
90 } else if (tk[index - 1].is(T_THIS)) {
92 } else if (tk[index - 1].is(T_TYPEID)) {
94 } else if (tk[index - 1].is(T_SIGNAL)) {
95 if (tk[index - 2].is(T_COMMA) && !_jumpedComma) {
97 return startOfExpression(tk, index - 2);
100 } else if (tk[index - 1].is(T_SLOT)) {
101 if (tk[index - 2].is(T_COMMA) && !_jumpedComma) {
103 return startOfExpression(tk, index - 2);
106 } else if (tk[index - 1].is(T_IDENTIFIER)) {
107 if (tk[index - 2].is(T_TILDE)) {
108 if (tk[index - 3].is(T_COLON_COLON)) {
109 return startOfExpression(tk, index - 3);
110 } else if (tk[index - 3].is(T_DOT) || tk[index - 3].is(T_ARROW)) {
111 return startOfExpression(tk, index - 3);
114 } else if (tk[index - 2].is(T_COLON_COLON)) {
115 return startOfExpression(tk, index - 1);
116 } else if (tk[index - 2].is(T_DOT) || tk[index - 2].is(T_ARROW)) {
117 return startOfExpression(tk, index - 2);
118 } else if (tk[index - 2].is(T_DOT_STAR) || tk[index - 2].is(T_ARROW_STAR)) {
119 return startOfExpression(tk, index - 2);
120 } else if (tk[index - 2].is(T_LBRACKET)) {
121 // array subscription:
124 } else if (tk[index - 2].is(T_COLON)) {
128 // [receiver messageParam:id
129 // and in both cases, the id (and only the id) is what we want, so:
131 } else if (tk[index - 2].is(T_IDENTIFIER) && tk[index - 3].is(T_LBRACKET)) {
132 // Very common Objective-C case:
134 // which we handle immediately:
137 #if 0 // see QTCREATORBUG-1501
138 // See if we are handling an Objective-C messaging expression in the form of:
139 // [receiver messageParam1:expression messageParam2
141 // [receiver messageParam1:expression messageParam2:expression messageParam3
144 while (i >= 0 && tk[i].isNot(T_EOF_SYMBOL)) {
145 if (tk[i].is(T_LBRACKET))
147 if (tk[i].is(T_LBRACE) || tk[i].is(T_RBRACE))
149 else if (tk[i].is(T_RBRACKET))
150 i = tk.startOfMatchingBrace(i + 1) - 1;
157 while (tk[j].is(T_LBRACKET))
159 if (tk[j].is(T_IDENTIFIER) && tk[j + 1].is(T_IDENTIFIER))
165 } else if (tk[index - 1].is(T_RPAREN)) {
166 int matchingBraceIndex = tk.startOfMatchingBrace(index);
167 if (matchingBraceIndex != index) {
168 if (tk[matchingBraceIndex - 1].is(T_GREATER)) {
169 int lessIndex = tk.startOfMatchingBrace(matchingBraceIndex);
170 if (lessIndex != matchingBraceIndex - 1) {
171 if (tk[lessIndex - 1].is(T_DYNAMIC_CAST) ||
172 tk[lessIndex - 1].is(T_STATIC_CAST) ||
173 tk[lessIndex - 1].is(T_CONST_CAST) ||
174 tk[lessIndex - 1].is(T_REINTERPRET_CAST))
175 return lessIndex - 1;
176 else if (tk[lessIndex - 1].is(T_IDENTIFIER))
177 return startOfExpression(tk, lessIndex);
178 else if (tk[lessIndex - 1].is(T_SIGNAL))
179 return startOfExpression(tk, lessIndex);
180 else if (tk[lessIndex - 1].is(T_SLOT))
181 return startOfExpression(tk, lessIndex);
184 return startOfExpression(tk, matchingBraceIndex);
187 } else if (tk[index - 1].is(T_RBRACKET)) {
188 int rbracketIndex = tk.startOfMatchingBrace(index);
189 if (rbracketIndex != index)
190 return startOfExpression(tk, rbracketIndex);
192 } else if (tk[index - 1].is(T_COLON_COLON)) {
193 if (tk[index - 2].is(T_GREATER)) { // ### not exactly
194 int lessIndex = tk.startOfMatchingBrace(index - 1);
195 if (lessIndex != index - 1)
196 return startOfExpression(tk, lessIndex);
198 } else if (tk[index - 2].is(T_IDENTIFIER)) {
199 return startOfExpression(tk, index - 1);
202 } else if (tk[index - 1].is(T_DOT) || tk[index - 1].is(T_ARROW)) {
203 return startOfExpression(tk, index - 1);
204 } else if (tk[index - 1].is(T_DOT_STAR) || tk[index - 1].is(T_ARROW_STAR)) {
205 return startOfExpression(tk, index - 1);
211 bool ExpressionUnderCursor::isAccessToken(const Token &tk)
215 case T_DOT: case T_ARROW:
216 case T_DOT_STAR: case T_ARROW_STAR:
223 QString ExpressionUnderCursor::operator()(const QTextCursor &cursor)
225 BackwardsScanner scanner(cursor);
227 _jumpedComma = false;
229 const int initialSize = scanner.startToken();
230 const int i = startOfExpression(scanner, initialSize);
231 if (i == initialSize)
234 return scanner.mid(i);
237 int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const
239 BackwardsScanner scanner(cursor);
241 int index = scanner.startToken();
244 const Token &tk = scanner[index - 1];
246 if (tk.is(T_EOF_SYMBOL))
248 else if (tk.is(T_LPAREN))
249 return scanner.startPosition() + tk.begin();
250 else if (tk.is(T_RPAREN)) {
251 int matchingBrace = scanner.startOfMatchingBrace(index);
253 if (matchingBrace == index) // If no matching brace found
256 index = matchingBrace;