| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | /**************************************************************************
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-03-05 11:25:49 +01:00
										 |  |  | ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-06-17 00:01:27 +10:00
										 |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** Commercial Usage | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** Licensees holding valid Qt Commercial licenses may use this file in | 
					
						
							|  |  |  | ** accordance with the Qt Commercial License Agreement provided with the | 
					
						
							|  |  |  | ** Software or, alternatively, in accordance with the terms contained in | 
					
						
							|  |  |  | ** a written agreement between you and Nokia. | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** GNU Lesser General Public License Usage | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
					
						
							|  |  |  | ** General Public License version 2.1 as published by the Free Software | 
					
						
							|  |  |  | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
					
						
							|  |  |  | ** packaging of this file.  Please review the following information to | 
					
						
							|  |  |  | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
					
						
							|  |  |  | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** If you are unsure which license is appropriate for your use, please | 
					
						
							| 
									
										
										
										
											2009-08-14 09:30:56 +02:00
										 |  |  | ** contact the sales department at http://qt.nokia.com/contact.
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | **************************************************************************/ | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "ExpressionUnderCursor.h"
 | 
					
						
							|  |  |  | #include "SimpleLexer.h"
 | 
					
						
							| 
									
										
										
										
											2009-09-17 12:29:06 +02:00
										 |  |  | #include "BackwardsScanner.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <Token.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <QTextCursor>
 | 
					
						
							|  |  |  | #include <QTextBlock>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CPlusPlus; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-04 12:37:26 +02:00
										 |  |  | ExpressionUnderCursor::ExpressionUnderCursor() | 
					
						
							|  |  |  |     : _jumpedComma(false) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ExpressionUnderCursor::~ExpressionUnderCursor() | 
					
						
							|  |  |  | { } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-27 14:32:09 +02:00
										 |  |  | int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-12-07 15:31:46 +01:00
										 |  |  |     if (tk[index - 1].is(T_GREATER)) { | 
					
						
							|  |  |  |         const int matchingBraceIndex = tk.startOfMatchingBrace(index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (tk[matchingBraceIndex - 1].is(T_IDENTIFIER)) | 
					
						
							|  |  |  |             index = matchingBraceIndex - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-08 14:50:30 +02:00
										 |  |  |     index = startOfExpression_helper(tk, index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (_jumpedComma) { | 
					
						
							|  |  |  |         const SimpleToken &tok = tk[index - 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (tok.kind()) { | 
					
						
							| 
									
										
										
										
											2009-10-12 12:25:22 +02:00
										 |  |  |         case T_COMMA: | 
					
						
							| 
									
										
										
										
											2009-10-08 14:50:30 +02:00
										 |  |  |         case T_LPAREN: | 
					
						
							|  |  |  |         case T_LBRACKET: | 
					
						
							|  |  |  |         case T_LBRACE: | 
					
						
							|  |  |  |         case T_SEMICOLON: | 
					
						
							|  |  |  |         case T_COLON: | 
					
						
							|  |  |  |         case T_QUESTION: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             if (tok.isOperator()) | 
					
						
							|  |  |  |                 return startOfExpression(tk, index - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ExpressionUnderCursor::startOfExpression_helper(BackwardsScanner &tk, int index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     if (tk[index - 1].isLiteral()) { | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_THIS)) { | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_TYPEID)) { | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_SIGNAL)) { | 
					
						
							|  |  |  |         if (tk[index - 2].is(T_COMMA) && !_jumpedComma) { | 
					
						
							|  |  |  |             _jumpedComma = true; | 
					
						
							|  |  |  |             return startOfExpression(tk, index - 2); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_SLOT)) { | 
					
						
							|  |  |  |         if (tk[index - 2].is(T_COMMA) && !_jumpedComma) { | 
					
						
							|  |  |  |             _jumpedComma = true; | 
					
						
							|  |  |  |             return startOfExpression(tk, index - 2); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_IDENTIFIER)) { | 
					
						
							|  |  |  |         if (tk[index - 2].is(T_TILDE)) { | 
					
						
							|  |  |  |             if (tk[index - 3].is(T_COLON_COLON)) { | 
					
						
							|  |  |  |                 return startOfExpression(tk, index - 3); | 
					
						
							|  |  |  |             } else if (tk[index - 3].is(T_DOT) || tk[index - 3].is(T_ARROW)) { | 
					
						
							|  |  |  |                 return startOfExpression(tk, index - 3); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return index - 2; | 
					
						
							|  |  |  |         } else if (tk[index - 2].is(T_COLON_COLON)) { | 
					
						
							|  |  |  |             return startOfExpression(tk, index - 1); | 
					
						
							|  |  |  |         } else if (tk[index - 2].is(T_DOT) || tk[index - 2].is(T_ARROW)) { | 
					
						
							|  |  |  |             return startOfExpression(tk, index - 2); | 
					
						
							|  |  |  |         } else if (tk[index - 2].is(T_DOT_STAR) || tk[index - 2].is(T_ARROW_STAR)) { | 
					
						
							|  |  |  |             return startOfExpression(tk, index - 2); | 
					
						
							| 
									
										
										
										
											2009-11-11 09:35:42 +01:00
										 |  |  |         } else if (tk[index - 2].is(T_LBRACKET)) { | 
					
						
							|  |  |  |             // array subscription:
 | 
					
						
							|  |  |  |             //     array[i
 | 
					
						
							|  |  |  |             return index - 1; | 
					
						
							|  |  |  |         } else if (tk[index - 2].is(T_COLON)) { | 
					
						
							|  |  |  |             // either of:
 | 
					
						
							|  |  |  |             //     cond ? expr1 : id
 | 
					
						
							|  |  |  |             // or:
 | 
					
						
							|  |  |  |             //     [receiver messageParam:id
 | 
					
						
							|  |  |  |             // and in both cases, the id (and only the id) is what we want, so:
 | 
					
						
							|  |  |  |             return index - 1; | 
					
						
							|  |  |  |         } else if (tk[index - 2].is(T_IDENTIFIER) && tk[index - 3].is(T_LBRACKET)) { | 
					
						
							|  |  |  |             // Very common Objective-C case:
 | 
					
						
							|  |  |  |             //     [receiver message
 | 
					
						
							|  |  |  |             // which we handle immediately:
 | 
					
						
							|  |  |  |             return index - 3; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2010-05-28 12:15:54 +02:00
										 |  |  | #if 0 // see QTCREATORBUG-1501
 | 
					
						
							| 
									
										
										
										
											2009-11-11 09:35:42 +01:00
										 |  |  |             // See if we are handling an Objective-C messaging expression in the form of:
 | 
					
						
							|  |  |  |             //     [receiver messageParam1:expression messageParam2
 | 
					
						
							|  |  |  |             // or:
 | 
					
						
							|  |  |  |             //     [receiver messageParam1:expression messageParam2:expression messageParam3
 | 
					
						
							|  |  |  |             // ... etc
 | 
					
						
							|  |  |  |             int i = index - 1; | 
					
						
							| 
									
										
										
										
											2010-03-11 18:11:53 +01:00
										 |  |  |             while (i >= 0 && tk[i].isNot(T_EOF_SYMBOL)) { | 
					
						
							| 
									
										
										
										
											2009-11-11 09:35:42 +01:00
										 |  |  |                 if (tk[i].is(T_LBRACKET)) | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 if (tk[i].is(T_LBRACE) || tk[i].is(T_RBRACE)) | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 else if (tk[i].is(T_RBRACKET)) | 
					
						
							|  |  |  |                     i = tk.startOfMatchingBrace(i + 1) - 1; | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     --i; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-12 11:31:14 +01:00
										 |  |  |             if (i >= 0) { | 
					
						
							|  |  |  |                 int j = i; | 
					
						
							|  |  |  |                 while (tk[j].is(T_LBRACKET)) | 
					
						
							|  |  |  |                     ++j; | 
					
						
							|  |  |  |                 if (tk[j].is(T_IDENTIFIER) && tk[j + 1].is(T_IDENTIFIER)) | 
					
						
							|  |  |  |                     return i; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-05-28 12:15:54 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_RPAREN)) { | 
					
						
							| 
									
										
										
										
											2009-12-07 15:31:46 +01:00
										 |  |  |         int matchingBraceIndex = tk.startOfMatchingBrace(index); | 
					
						
							|  |  |  |         if (matchingBraceIndex != index) { | 
					
						
							|  |  |  |             if (tk[matchingBraceIndex - 1].is(T_GREATER)) { | 
					
						
							|  |  |  |                 int lessIndex = tk.startOfMatchingBrace(matchingBraceIndex); | 
					
						
							|  |  |  |                 if (lessIndex != matchingBraceIndex - 1) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     if (tk[lessIndex - 1].is(T_DYNAMIC_CAST)     || | 
					
						
							|  |  |  |                         tk[lessIndex - 1].is(T_STATIC_CAST)      || | 
					
						
							|  |  |  |                         tk[lessIndex - 1].is(T_CONST_CAST)       || | 
					
						
							|  |  |  |                         tk[lessIndex - 1].is(T_REINTERPRET_CAST)) | 
					
						
							|  |  |  |                         return lessIndex - 1; | 
					
						
							|  |  |  |                     else if (tk[lessIndex - 1].is(T_IDENTIFIER)) | 
					
						
							|  |  |  |                         return startOfExpression(tk, lessIndex); | 
					
						
							|  |  |  |                     else if (tk[lessIndex - 1].is(T_SIGNAL)) | 
					
						
							|  |  |  |                         return startOfExpression(tk, lessIndex); | 
					
						
							|  |  |  |                     else if (tk[lessIndex - 1].is(T_SLOT)) | 
					
						
							|  |  |  |                         return startOfExpression(tk, lessIndex); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-12-07 15:31:46 +01:00
										 |  |  |             return startOfExpression(tk, matchingBraceIndex); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         return index; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_RBRACKET)) { | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |         int rbracketIndex = tk.startOfMatchingBrace(index); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         if (rbracketIndex != index) | 
					
						
							|  |  |  |             return startOfExpression(tk, rbracketIndex); | 
					
						
							|  |  |  |         return index; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_COLON_COLON)) { | 
					
						
							|  |  |  |         if (tk[index - 2].is(T_GREATER)) { // ### not exactly
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |             int lessIndex = tk.startOfMatchingBrace(index - 1); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             if (lessIndex != index - 1) | 
					
						
							|  |  |  |                 return startOfExpression(tk, lessIndex); | 
					
						
							|  |  |  |             return index - 1; | 
					
						
							|  |  |  |         } else if (tk[index - 2].is(T_IDENTIFIER)) { | 
					
						
							|  |  |  |             return startOfExpression(tk, index - 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return index - 1; | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_DOT) || tk[index - 1].is(T_ARROW)) { | 
					
						
							|  |  |  |         return startOfExpression(tk, index - 1); | 
					
						
							|  |  |  |     } else if (tk[index - 1].is(T_DOT_STAR) || tk[index - 1].is(T_ARROW_STAR)) { | 
					
						
							|  |  |  |         return startOfExpression(tk, index - 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ExpressionUnderCursor::isAccessToken(const SimpleToken &tk) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (tk.kind()) { | 
					
						
							|  |  |  |     case T_COLON_COLON: | 
					
						
							|  |  |  |     case T_DOT:      case T_ARROW: | 
					
						
							|  |  |  |     case T_DOT_STAR: case T_ARROW_STAR: | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } // switch
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  | QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-04 12:37:26 +02:00
										 |  |  |     BackwardsScanner scanner(cursor); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _jumpedComma = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |     const int initialSize = scanner.startToken(); | 
					
						
							| 
									
										
										
										
											2009-05-27 14:32:09 +02:00
										 |  |  |     const int i = startOfExpression(scanner, initialSize); | 
					
						
							|  |  |  |     if (i == initialSize) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         return QString(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-21 17:38:25 +02:00
										 |  |  |     return scanner.mid(i); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 17:57:17 +02:00
										 |  |  | int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-04 12:37:26 +02:00
										 |  |  |     BackwardsScanner scanner(cursor); | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |     int index = scanner.startToken(); | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     forever { | 
					
						
							| 
									
										
										
										
											2009-05-27 14:32:09 +02:00
										 |  |  |         const SimpleToken &tk = scanner[index - 1]; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (tk.is(T_EOF_SYMBOL)) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         else if (tk.is(T_LPAREN)) | 
					
						
							| 
									
										
										
										
											2009-05-27 14:32:09 +02:00
										 |  |  |             return scanner.startPosition() + tk.position(); | 
					
						
							| 
									
										
										
										
											2009-04-09 11:00:40 +02:00
										 |  |  |         else if (tk.is(T_RPAREN)) { | 
					
						
							| 
									
										
										
										
											2009-09-17 15:44:54 +02:00
										 |  |  |             int matchingBrace = scanner.startOfMatchingBrace(index); | 
					
						
							| 
									
										
										
										
											2009-04-09 11:00:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (matchingBrace == index) // If no matching brace found
 | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             index = matchingBrace; | 
					
						
							|  |  |  |         } else | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |             --index; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } |