1 | /* |
---|
2 | Copyright 2007-2009 David Nolden <david.nolden.kdevelop@art-master.de> |
---|
3 | |
---|
4 | This library is free software; you can redistribute it and/or |
---|
5 | modify it under the terms of the GNU Library General Public |
---|
6 | License version 2 as published by the Free Software Foundation. |
---|
7 | |
---|
8 | This library is distributed in the hope that it will be useful, |
---|
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
11 | Library General Public License for more details. |
---|
12 | |
---|
13 | You should have received a copy of the GNU Library General Public License |
---|
14 | along with this library; see the file COPYING.LIB. If not, write to |
---|
15 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
---|
16 | Boston, MA 02110-1301, USA. |
---|
17 | */ |
---|
18 | |
---|
19 | #include "context.h" |
---|
20 | #include <ktexteditor/view.h> |
---|
21 | #include <ktexteditor/document.h> |
---|
22 | #include <klocalizedstring.h> |
---|
23 | |
---|
24 | #include <iterator> |
---|
25 | |
---|
26 | #include <interfaces/idocumentcontroller.h> |
---|
27 | |
---|
28 | #include <language/interfaces/ilanguagesupport.h> |
---|
29 | #include <language/duchain/ducontext.h> |
---|
30 | #include <language/duchain/duchain.h> |
---|
31 | #include <language/duchain/duchainutils.h> |
---|
32 | #include <language/duchain/namespacealiasdeclaration.h> |
---|
33 | #include <language/duchain/classfunctiondeclaration.h> |
---|
34 | #include <language/duchain/functiondefinition.h> |
---|
35 | #include <language/duchain/duchainlock.h> |
---|
36 | #include <language/duchain/stringhelpers.h> |
---|
37 | #include <language/duchain/safetycounter.h> |
---|
38 | #include <language/interfaces/iproblem.h> |
---|
39 | #include <util/pushvalue.h> |
---|
40 | |
---|
41 | #include "../cppduchain/cppduchain.h" |
---|
42 | #include "../cppduchain/typeutils.h" |
---|
43 | #include "../cppduchain/overloadresolution.h" |
---|
44 | #include "../cppduchain/viablefunctions.h" |
---|
45 | #include "../cppduchain/environmentmanager.h" |
---|
46 | #include "../cppduchain/cpptypes.h" |
---|
47 | #include "../cppduchain/templatedeclaration.h" |
---|
48 | #include "../cpplanguagesupport.h" |
---|
49 | #include "../cpputils.h" |
---|
50 | #include "../cppduchain/environmentmanager.h" |
---|
51 | #include "../cppduchain/cppduchain.h" |
---|
52 | |
---|
53 | #include "cppdebughelper.h" |
---|
54 | #include "missingincludeitem.h" |
---|
55 | #include "implementationhelperitem.h" |
---|
56 | #include <qtfunctiondeclaration.h> |
---|
57 | #include "missingincludemodel.h" |
---|
58 | #include <templateparameterdeclaration.h> |
---|
59 | #include <language/duchain/classdeclaration.h> |
---|
60 | #include "qpropertydeclaration.h" |
---|
61 | #include "model.h" |
---|
62 | |
---|
63 | // #define ifDebug(x) x |
---|
64 | |
---|
65 | #define LOCKDUCHAIN DUChainReadLocker lock(DUChain::lock()) |
---|
66 | #include <cpputils.h> |
---|
67 | #include <interfaces/ilanguage.h> |
---|
68 | #include <interfaces/foregroundlock.h> |
---|
69 | |
---|
70 | ///Created statically as this object must be a child of the main thread |
---|
71 | CppUtils::ReplaceCurrentAccess accessReplacer; |
---|
72 | |
---|
73 | ///If this is enabled, no chain of useless argument-hints for binary operators is created. |
---|
74 | const bool NO_MULTIPLE_BINARY_OPERATORS = true; |
---|
75 | ///Whether only items that are allowed to be accessed should be shown |
---|
76 | const bool DO_ACCESS_FILTERING = true; |
---|
77 | ///Lines of text to keep for processing each context |
---|
78 | const int CONTEXT_LINES = 20; |
---|
79 | ///Maximum number of parent contexts |
---|
80 | const int MAX_DEPTH = 10; |
---|
81 | |
---|
82 | /** |
---|
83 | * ACCESS_STRINGS are used to determine the special properties of the context. |
---|
84 | * Any alphanum_ word not appearing in ACCESS_STRINGS will be considered an expression. |
---|
85 | * Expressions that fail evaluation invalidate their context and have no completions. |
---|
86 | * Don't list a keyword in ACCESS_STRINGS if: |
---|
87 | * * it should invalidate the context, ie ("break", "continue"). |
---|
88 | * * it should invalidate parent-only contexts, ie "if" will correctly invalidate a function ctxt |
---|
89 | * Do list a keyword in ACCESS_STRINGS if: |
---|
90 | * * it can be used to limit valid completions (see m_onlyShow, SHOW_TYPES_ACCESS_STRINGS) |
---|
91 | * * if it should be ignored (ie, "else", "throw") |
---|
92 | * * if it should be passed to a parent context for special processing (ie, "return", "(") |
---|
93 | * UNARY_OPERATORS are not ACCESS_STRINGS, but are stripped away after counting ptr depth |
---|
94 | **/ |
---|
95 | const QSet<QString> BINARY_ARITHMETIC_OPERATORS = QString("+ - * / % ^ & | < >").split(' ').toSet(); |
---|
96 | const QSet<QString> ARITHMETIC_COMPARISON_OPERATORS = QString("!= <= >= < >").split(' ').toSet(); |
---|
97 | //technically ".", "->", ".*", "->*", "::" are also binary operators, but they're handled differently |
---|
98 | const QSet<QString> BINARY_OPERATORS = |
---|
99 | QString("+= -= *= /= %= ^= &= |= ~= << >> >>= <<= == && || [ =").split(' ').toSet() + |
---|
100 | BINARY_ARITHMETIC_OPERATORS + ARITHMETIC_COMPARISON_OPERATORS; |
---|
101 | //These will be skipped over to find parent contexts |
---|
102 | const QSet<QString> UNARY_OPERATORS = QString("++ -- ! ~ + - & *").split(' ').toSet(); |
---|
103 | const QSet<QString> KEYWORD_ACCESS_STRINGS = QString("const_cast< static_cast< dynamic_cast< reinterpret_cast< const typedef public public: protected protected: private private: virtual return else throw emit Q_EMIT case delete delete[] new friend class").split(' ').toSet(); |
---|
104 | //When these appear as access strings, only show types |
---|
105 | const QSet<QString> SHOW_TYPES_ACCESS_STRINGS = QString("const_cast< static_cast< dynamic_cast< reinterpret_cast< const typedef public protected private virtual new friend class").split(' ').toSet(); |
---|
106 | //A parent context is created for these access strings |
---|
107 | //TODO: delete, case and possibly also xxx_cast< should open a parent context and get specialized handling |
---|
108 | const QSet<QString> PARENT_ACCESS_STRINGS = BINARY_OPERATORS + QString("< , ( : return case").split(' ').toSet(); |
---|
109 | //TODO: support ".*" and "->*" as MEMBER_ACCESS_STRINGS |
---|
110 | const QSet<QString> MEMBER_ACCESS_STRINGS = QString(". -> ::").split(' ').toSet(); |
---|
111 | const QSet<QString> ACCESS_STRINGS = KEYWORD_ACCESS_STRINGS + PARENT_ACCESS_STRINGS + MEMBER_ACCESS_STRINGS; |
---|
112 | |
---|
113 | ///Pass these to getEndingFromSet in order to specify longest valid match for above sets |
---|
114 | const int ACCESS_STR_MATCH = 17; //reinterpret_cast< |
---|
115 | const int MEMBER_ACCESS_STR_MATCH = 2; //:: |
---|
116 | const int PARENT_ACCESS_STR_MATCH = 6; //return |
---|
117 | const int BINARY_OPERATOR_MATCH = 3; //>>= |
---|
118 | const int UNARY_OPERATOR_MATCH = 2; //++ |
---|
119 | |
---|
120 | //Whether identifiers starting with "__" or "_Uppercase" and that are not declared in the current file should be excluded from the code completion |
---|
121 | const bool excludeReservedIdentifiers = true; |
---|
122 | |
---|
123 | using namespace KDevelop; |
---|
124 | |
---|
125 | namespace Cpp { |
---|
126 | |
---|
127 | typedef QPair<Declaration*, int> DeclarationDepthPair; |
---|
128 | |
---|
129 | IndexedType switchExpressionType(DUContextPointer caseContext) |
---|
130 | { |
---|
131 | #ifndef TEST_COMPLETION |
---|
132 | //Test thread has DUChain locked |
---|
133 | ENSURE_CHAIN_NOT_LOCKED; |
---|
134 | #endif |
---|
135 | ForegroundLock foregroundLock; |
---|
136 | LOCKDUCHAIN; |
---|
137 | if (!caseContext) |
---|
138 | return IndexedType(); |
---|
139 | DUContext* switchContext = 0; |
---|
140 | if (caseContext->importedParentContexts().size() == 1) |
---|
141 | switchContext = caseContext->importedParentContexts().first().context(caseContext->topContext()); |
---|
142 | if (!switchContext) |
---|
143 | return IndexedType(); |
---|
144 | QString switchExpression = switchContext->createRangeMoving()->text(); |
---|
145 | ExpressionParser expressionParser; |
---|
146 | return expressionParser.evaluateType(switchExpression.toUtf8(), DUContextPointer(switchContext)).type; |
---|
147 | } |
---|
148 | |
---|
149 | //Search for a copy-constructor within class |
---|
150 | //*DUChain must be locked* |
---|
151 | bool hasCopyConstructor(CppClassType::Ptr classType, TopDUContext* topContext) |
---|
152 | { |
---|
153 | if(!classType) |
---|
154 | return false; |
---|
155 | Declaration* decl = classType->declaration(topContext); |
---|
156 | if(!decl) |
---|
157 | return false; |
---|
158 | DUContext* ctx = decl->internalContext(); |
---|
159 | if(!ctx) |
---|
160 | return false; |
---|
161 | |
---|
162 | AbstractType::Ptr constClassType = classType->indexed().abstractType(); |
---|
163 | constClassType->setModifiers(AbstractType::ConstModifier); |
---|
164 | ReferenceType::Ptr argumentType(new ReferenceType); |
---|
165 | argumentType->setBaseType(constClassType); |
---|
166 | |
---|
167 | QList<Declaration*> constructors = ctx->findLocalDeclarations(decl->identifier()); |
---|
168 | foreach(Declaration* constructor, constructors) { |
---|
169 | FunctionType::Ptr funType = constructor->type<FunctionType>(); |
---|
170 | if(funType && !funType->returnType() && funType->arguments().size() == 1) { |
---|
171 | if(funType->arguments()[0]->equals(argumentType.constData())) |
---|
172 | return true; |
---|
173 | } |
---|
174 | } |
---|
175 | |
---|
176 | return false; |
---|
177 | } |
---|
178 | |
---|
179 | ///@todo move these together with those from expressionvisitor into an own file, or make them unnecessary |
---|
180 | QList<Declaration*> declIdsToDeclPtrs( const QList<DeclarationId>& decls, uint count, TopDUContext* top ) { |
---|
181 | |
---|
182 | QList<Declaration*> ret; |
---|
183 | for(uint a = 0; a < count; ++a) { |
---|
184 | Declaration* d = decls[a].getDeclaration(top); |
---|
185 | if(d) |
---|
186 | ret << d; |
---|
187 | } |
---|
188 | |
---|
189 | return ret; |
---|
190 | } |
---|
191 | |
---|
192 | bool isLegalIdentifier( const QChar &theChar ) { |
---|
193 | return theChar.isLetterOrNumber() || theChar == '_'; |
---|
194 | } |
---|
195 | |
---|
196 | ///Gets the longest str from @param list which matches the ending of @param str |
---|
197 | QString getEndingFromSet( const QString &str, const QSet<QString> &set, int maxMatchLen) { |
---|
198 | QString end; |
---|
199 | for ( int i = qMin(str.length(), maxMatchLen); i > 0; --i ) { |
---|
200 | end = str.right( i ); |
---|
201 | if ( i + i < str.length() && |
---|
202 | isLegalIdentifier( end[0] ) && |
---|
203 | isLegalIdentifier( str[str.length()-i-1] ) ) |
---|
204 | continue; //don't match ie, "varnamedelete[]" |
---|
205 | |
---|
206 | if ( set.contains( end ) ) |
---|
207 | return end; |
---|
208 | } |
---|
209 | |
---|
210 | return QString(); |
---|
211 | } |
---|
212 | |
---|
213 | QString getEndFunctionOperator( const QString &str ) { |
---|
214 | QString ret = getEndingFromSet( str, BINARY_OPERATORS, BINARY_OPERATOR_MATCH ); |
---|
215 | return ret == "[" ? "[]" : str; |
---|
216 | } |
---|
217 | |
---|
218 | //Gets rid of uneeded whitespace following a legal identifier |
---|
219 | //"int i = " into "int i=" or "delete [ ] " into "delete[]" |
---|
220 | void compressEndingWhitespace( QString &str ) { |
---|
221 | for (int i = str.length() - 1; i >= 0; --i) { |
---|
222 | if ( isLegalIdentifier( str[i] ) ) |
---|
223 | return; |
---|
224 | if ( str[i].isSpace() ) |
---|
225 | str.remove(i, 1); |
---|
226 | } |
---|
227 | } |
---|
228 | |
---|
229 | QString whitespaceFree(const QString &orig) |
---|
230 | { |
---|
231 | QString ret = orig; |
---|
232 | for (int i = 0; i < ret.length(); ++i) { |
---|
233 | if ( ret[i].isSpace() ) |
---|
234 | ret.remove(i, 1); |
---|
235 | } |
---|
236 | return ret; |
---|
237 | } |
---|
238 | |
---|
239 | bool isSignal( const QString &str ) |
---|
240 | { |
---|
241 | return str == "SIGNAL" || str == "Q_SIGNAL"; |
---|
242 | } |
---|
243 | bool isSlot( const QString &str ) |
---|
244 | { |
---|
245 | return str == "SLOT" || str == "Q_SLOT"; |
---|
246 | } |
---|
247 | |
---|
248 | QString lastNLines( const QString& str, int n ) { |
---|
249 | int curNewLine = str.lastIndexOf( '\n' ); |
---|
250 | int nthLine = curNewLine; |
---|
251 | |
---|
252 | for ( int i = 0; i < n; ++i ) |
---|
253 | { |
---|
254 | if ( curNewLine == -1 ) |
---|
255 | break; |
---|
256 | else |
---|
257 | nthLine = curNewLine; |
---|
258 | |
---|
259 | curNewLine = str.lastIndexOf( '\n', curNewLine - 1 ); |
---|
260 | } |
---|
261 | |
---|
262 | //return the position after the newline, or whole str if no newline |
---|
263 | return str.mid( nthLine + 1 ); |
---|
264 | } |
---|
265 | |
---|
266 | bool skipToOpening( const QString& text, int &index) |
---|
267 | { |
---|
268 | QChar closing = text[ index ]; |
---|
269 | QChar opening; |
---|
270 | if ( closing == ')' ) |
---|
271 | opening = '('; |
---|
272 | else if ( closing == '>' ) |
---|
273 | opening = '<'; |
---|
274 | else if ( closing == ']' ) |
---|
275 | opening = '['; |
---|
276 | |
---|
277 | int count = 0; |
---|
278 | int start = index; |
---|
279 | while ( index >= 0 ) { |
---|
280 | QChar ch = text[ index ]; |
---|
281 | --index; |
---|
282 | |
---|
283 | if ( ch == opening ) |
---|
284 | ++count; |
---|
285 | else if ( ch == closing ) |
---|
286 | --count; |
---|
287 | |
---|
288 | if ( count == 0 ) |
---|
289 | return true; |
---|
290 | } |
---|
291 | |
---|
292 | index = start; |
---|
293 | return false; |
---|
294 | } |
---|
295 | |
---|
296 | /** |
---|
297 | * This function should search backwards in \p _text from \p index and return |
---|
298 | * the index where the expression begins (if there is one) |
---|
299 | * An expression is any legal identifier + member accesses + complete brackets |
---|
300 | * Examples (expression begins at "|"): |
---|
301 | * n = |(x + y) |
---|
302 | * n = |x(y, z) |
---|
303 | * n = x(|y |
---|
304 | * n = |x()->y[].x<>:: |
---|
305 | * n = |x("whatever", ++y, x - u) |
---|
306 | * Notes: Doesn't know about keywords |
---|
307 | **/ |
---|
308 | int expressionBefore( const QString& _text, int index ) |
---|
309 | { |
---|
310 | QString text = KDevelop::clearStrings( _text ); |
---|
311 | bool lastWasIdentifier = false; |
---|
312 | |
---|
313 | --index; |
---|
314 | |
---|
315 | while ( index >= 0 ) |
---|
316 | { |
---|
317 | while ( index >= 0 && text[ index ].isSpace() ) |
---|
318 | --index; |
---|
319 | |
---|
320 | if ( index < 0 ) |
---|
321 | break; |
---|
322 | |
---|
323 | QChar ch = text[ index ]; |
---|
324 | QString memberAccess = getEndingFromSet( text.left ( index + 1 ), |
---|
325 | MEMBER_ACCESS_STRINGS, |
---|
326 | MEMBER_ACCESS_STR_MATCH ); |
---|
327 | if ( !memberAccess.isEmpty() ) |
---|
328 | { |
---|
329 | index -= memberAccess.length(); |
---|
330 | lastWasIdentifier = false; |
---|
331 | } |
---|
332 | else if ( !lastWasIdentifier && isLegalIdentifier( ch ) ) |
---|
333 | { |
---|
334 | while ( index >= 0 && isLegalIdentifier( text[ index ] ) ) |
---|
335 | --index; |
---|
336 | lastWasIdentifier = true; |
---|
337 | } |
---|
338 | else if ( !lastWasIdentifier && ( ch == ')' || ch == '>' || ch == ']' ) ) |
---|
339 | { |
---|
340 | if ( skipToOpening ( text, index ) ) |
---|
341 | lastWasIdentifier = false; |
---|
342 | else |
---|
343 | break; |
---|
344 | } |
---|
345 | else |
---|
346 | break; |
---|
347 | } |
---|
348 | |
---|
349 | ++index; |
---|
350 | |
---|
351 | while ( index < text.length() && text[ index ].isSpace() ) |
---|
352 | ++index; |
---|
353 | |
---|
354 | return index; |
---|
355 | } |
---|
356 | |
---|
357 | QString getUnaryOperator(const QString &context) |
---|
358 | { |
---|
359 | QString unOp = getEndingFromSet( context, UNARY_OPERATORS, UNARY_OPERATOR_MATCH ); |
---|
360 | QString binOp = getEndingFromSet( context, BINARY_OPERATORS, BINARY_OPERATOR_MATCH ); |
---|
361 | if (!binOp.isEmpty()) { |
---|
362 | if (binOp == unOp) { |
---|
363 | int exprStart = expressionBefore(context, context.length() - binOp.length()); |
---|
364 | QString exp = context.mid(exprStart, context.length() - exprStart - binOp.length()).trimmed(); |
---|
365 | if ( !exp.isEmpty() && !KEYWORD_ACCESS_STRINGS.contains(exp) ) |
---|
366 | return QString(); |
---|
367 | } |
---|
368 | else if (binOp.contains(unOp)) //ie "&&" |
---|
369 | return QString(); |
---|
370 | } |
---|
371 | return unOp; |
---|
372 | } |
---|
373 | |
---|
374 | CodeCompletionContext:: |
---|
375 | CodeCompletionContext( KDevelop::DUContextPointer context, const QString& text, |
---|
376 | const QString& followingText, const KDevelop::CursorInRevision& position, |
---|
377 | int depth, const QStringList& knownArgumentExpressions, int line ) |
---|
378 | : KDevelop::CodeCompletionContext( context, text, position, depth ), |
---|
379 | m_accessType( NoMemberAccess ), |
---|
380 | m_knownArgumentExpressions( knownArgumentExpressions ), |
---|
381 | m_isConstructorCompletion( false ), |
---|
382 | m_pointerConversionsBeforeMatching( 0 ), |
---|
383 | m_onlyShow( ShowAll ), |
---|
384 | m_expressionIsTypePrefix( false ), |
---|
385 | m_doAccessFiltering( DO_ACCESS_FILTERING ) |
---|
386 | { |
---|
387 | #ifndef TEST_COMPLETION |
---|
388 | MissingIncludeCompletionModel::self().stop(); |
---|
389 | #endif |
---|
390 | if ( doIncludeCompletion() ) |
---|
391 | return; |
---|
392 | //We'll have to get a few expressionResults and do other DUChain processing during construction |
---|
393 | //so lock the DUChain here |
---|
394 | LOCKDUCHAIN; |
---|
395 | |
---|
396 | if( !m_duContext || depth > MAX_DEPTH || !isValidPosition() ) { |
---|
397 | m_valid = false; |
---|
398 | return; |
---|
399 | } |
---|
400 | |
---|
401 | m_followingText = followingText.trimmed(); |
---|
402 | |
---|
403 | if( depth == 0 ) |
---|
404 | preprocessText( line ); |
---|
405 | m_text = lastNLines( m_text, CONTEXT_LINES ); |
---|
406 | compressEndingWhitespace( m_text ); |
---|
407 | |
---|
408 | if( doConstructorCompletion() ) |
---|
409 | return; |
---|
410 | |
---|
411 | skipUnaryOperators( m_text, m_pointerConversionsBeforeMatching ); |
---|
412 | |
---|
413 | QString accessStr = getEndingFromSet( m_text, ACCESS_STRINGS, ACCESS_STR_MATCH ); |
---|
414 | m_accessType = findAccessType( accessStr ); |
---|
415 | if ( m_depth > 0 || !PARENT_ACCESS_STRINGS.contains( accessStr ) ) |
---|
416 | m_text.chop( accessStr.length() ); |
---|
417 | |
---|
418 | QString expressionPrefix; |
---|
419 | findExpressionAndPrefix( m_expression, expressionPrefix, m_expressionIsTypePrefix ); |
---|
420 | skipUnaryOperators( expressionPrefix, m_pointerConversionsBeforeMatching ); |
---|
421 | |
---|
422 | m_localClass = findLocalClass(); |
---|
423 | m_parentContext = getParentContext( expressionPrefix ); |
---|
424 | |
---|
425 | if ( doSignalSlotCompletion() ) |
---|
426 | return; |
---|
427 | |
---|
428 | m_onlyShow = findOnlyShow( accessStr ); |
---|
429 | m_expressionResult = evaluateExpression(); |
---|
430 | |
---|
431 | m_valid = testContextValidity(expressionPrefix, accessStr); |
---|
432 | if (!m_valid) |
---|
433 | return; |
---|
434 | |
---|
435 | if ( m_accessType == TemplateAccess || |
---|
436 | m_accessType == FunctionCallAccess || |
---|
437 | m_accessType == BinaryOpFunctionCallAccess ) |
---|
438 | { |
---|
439 | m_knownArgumentTypes = getKnownArgumentTypes(); |
---|
440 | |
---|
441 | if ( m_accessType == BinaryOpFunctionCallAccess ) |
---|
442 | m_operator = getEndFunctionOperator( accessStr ); |
---|
443 | |
---|
444 | if( !m_expression.isEmpty() && !m_expressionResult.isValid() ) |
---|
445 | m_functionName = m_expression; //set m_functionName for Missing Include Completion |
---|
446 | } |
---|
447 | |
---|
448 | switch( m_accessType ) { |
---|
449 | case ArrowMemberAccess: |
---|
450 | processArrowMemberAccess(); |
---|
451 | //Falls through to processAllMemberAccesses, but only needs the missing include part TODO: refactor |
---|
452 | case MemberChoose: |
---|
453 | case StaticMemberChoose: |
---|
454 | case MemberAccess: |
---|
455 | processAllMemberAccesses(); |
---|
456 | break; |
---|
457 | case BinaryOpFunctionCallAccess: |
---|
458 | case FunctionCallAccess: |
---|
459 | processFunctionCallAccess(); |
---|
460 | break; |
---|
461 | default: |
---|
462 | //Nothing to do for now |
---|
463 | break; |
---|
464 | } |
---|
465 | } |
---|
466 | |
---|
467 | void CodeCompletionContext::processAllMemberAccesses() { |
---|
468 | AbstractType::Ptr type = m_expressionResult.type.abstractType(); |
---|
469 | if(!type) |
---|
470 | return; |
---|
471 | |
---|
472 | if(type.cast<PointerType>()) |
---|
473 | replaceCurrentAccess( ".", "->" ); |
---|
474 | |
---|
475 | #ifndef TEST_COMPLETION // hmzzz ?? :) ///FIXME: manually test for these cases and get rid of comment to the left |
---|
476 | DelayedType::Ptr delayed = type.cast<DelayedType>(); |
---|
477 | if( delayed && delayed->kind() == DelayedType::Unresolved ) { |
---|
478 | eventuallyAddGroup( |
---|
479 | i18n( "Not Included" ), 1000, |
---|
480 | missingIncludeCompletionItems( m_expression, m_followingText + ": ", |
---|
481 | m_expressionResult, m_duContext.data(), 0, true ) |
---|
482 | ); |
---|
483 | } |
---|
484 | #endif |
---|
485 | } |
---|
486 | |
---|
487 | void CodeCompletionContext::processArrowMemberAccess() { |
---|
488 | //Dereference a pointer |
---|
489 | AbstractType::Ptr containerType = m_expressionResult.type.abstractType(); |
---|
490 | PointerType::Ptr pnt = TypeUtils::realType( containerType, m_duContext->topContext() ).cast<PointerType>(); |
---|
491 | if( pnt ) { |
---|
492 | ///@todo what about const in pointer? |
---|
493 | m_expressionResult.type = pnt->baseType()->indexed(); |
---|
494 | m_expressionResult.isInstance = true; |
---|
495 | return; // expression is a pointer |
---|
496 | } |
---|
497 | |
---|
498 | //Look for "->" operator |
---|
499 | AbstractType::Ptr realContainer = TypeUtils::realType( containerType, m_duContext->topContext() ); |
---|
500 | IdentifiedType* idType = dynamic_cast<IdentifiedType*>( realContainer.unsafeData() ); |
---|
501 | if ( !idType ) { |
---|
502 | m_valid = false; |
---|
503 | return; |
---|
504 | } |
---|
505 | |
---|
506 | Declaration* idDecl = idType->declaration(m_duContext->topContext()); |
---|
507 | if( !idDecl || !idDecl->internalContext() ) { |
---|
508 | m_valid = false; |
---|
509 | return; |
---|
510 | } |
---|
511 | |
---|
512 | QList<Declaration*> operatorDeclarations = |
---|
513 | Cpp::findLocalDeclarations( idDecl->internalContext(), |
---|
514 | Identifier( "operator->" ), |
---|
515 | m_duContext->topContext() ); |
---|
516 | if( operatorDeclarations.isEmpty() ) { |
---|
517 | if( idDecl->internalContext()->type() == DUContext::Class ) |
---|
518 | replaceCurrentAccess( "->", "." ); |
---|
519 | m_valid = false; |
---|
520 | return; |
---|
521 | } |
---|
522 | |
---|
523 | // TODO use Cpp::isAccessible on operator functions for more correctness? |
---|
524 | foreach( Declaration* decl, operatorDeclarations ) |
---|
525 | m_expressionResult.allDeclarationsList().append( decl->id() ); |
---|
526 | |
---|
527 | bool declarationIsConst = ( containerType->modifiers() & AbstractType::ConstModifier ) || |
---|
528 | ( idDecl->abstractType()->modifiers() & AbstractType::ConstModifier ); |
---|
529 | FunctionType::Ptr function; |
---|
530 | foreach ( Declaration* decl, operatorDeclarations ) { |
---|
531 | FunctionType::Ptr f2 = decl->abstractType().cast<FunctionType>(); |
---|
532 | const bool operatorIsConst = f2->modifiers() & AbstractType::ConstModifier; |
---|
533 | if ( operatorIsConst == declarationIsConst ) { |
---|
534 | // Best match |
---|
535 | function = f2; |
---|
536 | break; |
---|
537 | } else if ( operatorIsConst && !function ) { |
---|
538 | // Const result where non-const is ok, accept and keep looking |
---|
539 | function = f2; |
---|
540 | } |
---|
541 | } |
---|
542 | |
---|
543 | if ( !function ) { |
---|
544 | m_valid = false; |
---|
545 | return; //const declaration has no non-const "operator->" |
---|
546 | } |
---|
547 | |
---|
548 | m_expressionResult.type = function->returnType()->indexed(); |
---|
549 | m_expressionResult.isInstance = true; |
---|
550 | } |
---|
551 | |
---|
552 | bool CodeCompletionContext::testContextValidity(const QString &expressionPrefix, const QString &accessStr) const { |
---|
553 | if( !m_expression.isEmpty() && !m_expressionResult.isValid() ) { |
---|
554 | //StaticMemberChoose may be an access to a namespace, like "MyNamespace::". |
---|
555 | //"MyNamespace" cannot be evaluated, still we can give some completions |
---|
556 | //FunctionCallAccess & TemplateAccess can still get missing include completion |
---|
557 | if( m_accessType != FunctionCallAccess && |
---|
558 | m_accessType != TemplateAccess && |
---|
559 | m_accessType != StaticMemberChoose ) |
---|
560 | return false; |
---|
561 | } |
---|
562 | //Special case for "class" access str, which should only have completions when it is "friend class ..." |
---|
563 | if (accessStr == "class" && !expressionPrefix.endsWith("friend")) |
---|
564 | return false; |
---|
565 | |
---|
566 | switch ( m_accessType ) |
---|
567 | { |
---|
568 | case NoMemberAccess: |
---|
569 | return m_expression.isEmpty() || isImplementationHelperValid(); |
---|
570 | case BinaryOpFunctionCallAccess: |
---|
571 | return m_expressionResult.isInstance; |
---|
572 | case MemberAccess: |
---|
573 | case MemberChoose: |
---|
574 | case StaticMemberChoose: |
---|
575 | return !m_expression.isEmpty(); |
---|
576 | default: |
---|
577 | return true; |
---|
578 | } |
---|
579 | } |
---|
580 | |
---|
581 | DUContextPointer CodeCompletionContext::findLocalClass() const { |
---|
582 | Declaration* classDecl = Cpp::localClassFromCodeContext( m_duContext.data() ); |
---|
583 | return classDecl ? DUContextPointer( classDecl->internalContext() ) : DUContextPointer(); |
---|
584 | } |
---|
585 | |
---|
586 | KDevelop::CodeCompletionContext::Ptr |
---|
587 | CodeCompletionContext::getParentContext( const QString &expressionPrefix ) const { |
---|
588 | //this is essentially a poor-mans tokenizer, and we want to find out |
---|
589 | //whether the last token is part of PARENT_ACCESS_STRINGS |
---|
590 | //but we must take into account that longer versions exist in ACCESS_STRINGS, |
---|
591 | //esp. for e.g. "parent:", here ":" would be a PARENT_ACCESS_STRINGS but |
---|
592 | //it is actually not. So we first search in the long version and then |
---|
593 | //double-check that it's actually a proper access string |
---|
594 | QString access = getEndingFromSet( expressionPrefix, ACCESS_STRINGS, ACCESS_STR_MATCH ); |
---|
595 | if ( access.isEmpty() || !PARENT_ACCESS_STRINGS.contains(access) ) |
---|
596 | return KDevelop::CodeCompletionContext::Ptr(); |
---|
597 | |
---|
598 | QStringList previousArguments; |
---|
599 | QString parentContextText; |
---|
600 | |
---|
601 | if ( access == "," ) { |
---|
602 | //Get arguments before current position |
---|
603 | int parentContextEnd = expressionPrefix.length(); |
---|
604 | skipFunctionArguments( expressionPrefix, previousArguments, parentContextEnd ); |
---|
605 | parentContextText = expressionPrefix.left( parentContextEnd ); |
---|
606 | } |
---|
607 | else |
---|
608 | parentContextText = expressionPrefix; |
---|
609 | |
---|
610 | if( m_depth == 0 || parentContextText != m_text ) |
---|
611 | return KDevelop::CodeCompletionContext::Ptr( |
---|
612 | new CodeCompletionContext( m_duContext, parentContextText, QString(), |
---|
613 | m_position, m_depth + 1, previousArguments ) ); |
---|
614 | |
---|
615 | return KDevelop::CodeCompletionContext::Ptr(); |
---|
616 | } |
---|
617 | |
---|
618 | void CodeCompletionContext::skipUnaryOperators(QString &str, int &pointerConversions) const { |
---|
619 | ///Eventually take preceding "*" and/or "&" operators and use them for pointer depth conversion of completion items |
---|
620 | if ( str.endsWith("new") ) |
---|
621 | pointerConversions = 1; |
---|
622 | |
---|
623 | QString unOp = getUnaryOperator( str ); |
---|
624 | while ( !unOp.isEmpty() ) { |
---|
625 | unOp = getUnaryOperator( str ); |
---|
626 | |
---|
627 | if ( unOp == "&" ) |
---|
628 | ++pointerConversions; |
---|
629 | else if ( unOp == "*" ) |
---|
630 | --pointerConversions; |
---|
631 | |
---|
632 | str.chop(unOp.length()); |
---|
633 | } |
---|
634 | } |
---|
635 | |
---|
636 | bool CodeCompletionContext::doSignalSlotCompletion() { |
---|
637 | if( m_depth > 0 || !parentContext() || |
---|
638 | parentContext()->accessType() != FunctionCallAccess) |
---|
639 | return false; |
---|
640 | |
---|
641 | //TODO: support "char* sig = SIGNAL(" properly |
---|
642 | if( isSignal( parentContext()->m_expression ) || isSlot( parentContext()->m_expression ) ) { |
---|
643 | m_onlyShow = isSlot(parentContext()->m_expression) ? ShowSlots : ShowSignals; |
---|
644 | //If we are in "SIGNAL(" or "SLOT(" context, skip it |
---|
645 | setParentContext(KDevelop::CodeCompletionContext::Ptr(parentContext()->parentContext())); |
---|
646 | } |
---|
647 | |
---|
648 | if( !parentContext() || !m_expression.isEmpty() || |
---|
649 | parentContext()->accessType() != FunctionCallAccess ) |
---|
650 | return false; |
---|
651 | |
---|
652 | //Check if we're in a connect/disconnect function, and at what param |
---|
653 | foreach( const Cpp::OverloadResolutionFunction &function, parentContext()->functions() ) |
---|
654 | { |
---|
655 | DeclarationPointer decl = function.function.declaration(); |
---|
656 | if( !decl || |
---|
657 | ( decl->qualifiedIdentifier().toString() != "QObject::connect" && |
---|
658 | decl->qualifiedIdentifier().toString() != "QObject::disconnect") ) |
---|
659 | continue; //Not a connect/disconnect function |
---|
660 | |
---|
661 | FunctionType::Ptr funType = decl->type<FunctionType>(); |
---|
662 | if( !funType || funType->arguments().size() <= function.matchedArguments || |
---|
663 | funType->arguments().size() < 3 ) |
---|
664 | continue; //Not a recognized overload |
---|
665 | |
---|
666 | //this is a connect/disconnect, find if at SIGNAL or SLOT param |
---|
667 | if( function.matchedArguments == 1 && parentContext()->m_knownArgumentTypes.size() >= 1 ) { |
---|
668 | //currently at signal param |
---|
669 | m_accessType = SignalAccess; |
---|
670 | } |
---|
671 | else if( funType->arguments()[function.matchedArguments] && |
---|
672 | funType->arguments()[function.matchedArguments]->toString() == "const char*" ) |
---|
673 | { |
---|
674 | //currently at slot param |
---|
675 | m_accessType = SlotAccess; |
---|
676 | |
---|
677 | //get the corresponding signal's identifier and signature |
---|
678 | if( parentContext()->m_knownArgumentExpressions.size() > 1 ) { |
---|
679 | QString connectedSignal = parentContext()->m_knownArgumentExpressions[1]; |
---|
680 | |
---|
681 | int skipSignal = 0; |
---|
682 | if( connectedSignal.startsWith( "SIGNAL(") ) |
---|
683 | skipSignal = 7; |
---|
684 | if( connectedSignal.startsWith( "Q_SIGNAL(") ) |
---|
685 | skipSignal = 9; |
---|
686 | |
---|
687 | if( skipSignal && connectedSignal.endsWith( ")" ) && |
---|
688 | connectedSignal.length() > skipSignal + 1 ) |
---|
689 | { |
---|
690 | connectedSignal = connectedSignal.mid( skipSignal ); |
---|
691 | connectedSignal = connectedSignal.left( connectedSignal.length() - 1 ); |
---|
692 | //Now connectedSignal is something like myFunction(...), and we want the "...". |
---|
693 | QPair<Identifier, QByteArray> signature = Cpp::qtFunctionSignature( connectedSignal.toUtf8() ); |
---|
694 | m_connectedSignalIdentifier = signature.first; |
---|
695 | m_connectedSignalNormalizedSignature = signature.second; |
---|
696 | } |
---|
697 | } |
---|
698 | } |
---|
699 | |
---|
700 | if( m_accessType == SignalAccess || m_accessType == SlotAccess ) { |
---|
701 | if( function.matchedArguments == 2 ) { |
---|
702 | //The function that does not take the target-argument is being used |
---|
703 | if( Declaration* klass = Cpp::localClassFromCodeContext( m_duContext.data() ) ) |
---|
704 | m_expressionResult.type = klass->indexedType(); |
---|
705 | } |
---|
706 | else if( parentContext()->m_knownArgumentTypes.size() >= |
---|
707 | function.matchedArguments && function.matchedArguments != 0 ) |
---|
708 | { |
---|
709 | m_expressionResult = parentContext()->m_knownArgumentTypes[function.matchedArguments-1]; |
---|
710 | m_expressionResult.type = TypeUtils::targetType(TypeUtils::matchingClassPointer(funType->arguments()[function.matchedArguments-1], m_expressionResult.type.abstractType(), m_duContext->topContext()), m_duContext->topContext())->indexed(); |
---|
711 | } |
---|
712 | |
---|
713 | return true; |
---|
714 | } |
---|
715 | } |
---|
716 | |
---|
717 | return false; |
---|
718 | } |
---|
719 | |
---|
720 | ExpressionEvaluationResult CodeCompletionContext::evaluateExpression() const { |
---|
721 | if( m_expression.isEmpty() ) |
---|
722 | return ExpressionEvaluationResult(); |
---|
723 | |
---|
724 | ExpressionParser expressionParser; |
---|
725 | |
---|
726 | if( !m_expressionIsTypePrefix && m_accessType != NoMemberAccess ) |
---|
727 | return expressionParser.evaluateExpression( m_expression.toUtf8(), m_duContext ); |
---|
728 | |
---|
729 | ExpressionEvaluationResult res = expressionParser.evaluateType( m_expression.toUtf8(), m_duContext ); |
---|
730 | res.isInstance = true; |
---|
731 | return res; |
---|
732 | } |
---|
733 | |
---|
734 | bool CodeCompletionContext::doConstructorCompletion() { |
---|
735 | QString text = m_text.trimmed(); |
---|
736 | |
---|
737 | QStringList hadItems; |
---|
738 | |
---|
739 | ifDebug( kDebug() << "text:" << text; ) |
---|
740 | |
---|
741 | //Jump over all initializers |
---|
742 | while(!text.isEmpty() && text.endsWith(',')) { |
---|
743 | text = text.left(text.length()-1).trimmed(); |
---|
744 | //Skip initializer expression |
---|
745 | int start_expr = expressionBefore( text, text.length() ); |
---|
746 | QString skip = text.mid(start_expr, text.length() - start_expr); |
---|
747 | |
---|
748 | if(skip.contains('(')) |
---|
749 | hadItems << skip.left(skip.indexOf('(')).trimmed(); |
---|
750 | |
---|
751 | text = text.left(start_expr).trimmed(); |
---|
752 | } |
---|
753 | |
---|
754 | if(!text.trimmed().endsWith(':')) |
---|
755 | return false; |
---|
756 | |
---|
757 | text = text.left(text.length()-1).trimmed(); |
---|
758 | //Now we have the declaration in text |
---|
759 | ifDebug( kDebug() << "should be decl.:" << text; ) |
---|
760 | if(!text.endsWith(')')) |
---|
761 | return false; |
---|
762 | |
---|
763 | int argumentsStart = text.length()-1; |
---|
764 | QStringList arguments; |
---|
765 | skipFunctionArguments(text, arguments, argumentsStart); |
---|
766 | if(argumentsStart <= 0) |
---|
767 | return false; |
---|
768 | |
---|
769 | int identifierStart = expressionBefore( text, argumentsStart-1 ); |
---|
770 | if(identifierStart < 0 || identifierStart == argumentsStart) |
---|
771 | return false; |
---|
772 | |
---|
773 | m_text = QString(); |
---|
774 | |
---|
775 | QualifiedIdentifier id(text.mid(identifierStart, argumentsStart-1-identifierStart)); |
---|
776 | if(id.isEmpty()) |
---|
777 | return false; |
---|
778 | id = id.left(id.count()-1); |
---|
779 | |
---|
780 | DUContext* container = 0; |
---|
781 | |
---|
782 | if(!id.isEmpty()) { |
---|
783 | //Find the class |
---|
784 | QList< KDevelop::Declaration* > decls = m_duContext->findDeclarations(id); |
---|
785 | if(decls.isEmpty()) { |
---|
786 | ifDebug( kDebug() << "did not find class declaration for" << id.toString(); ) |
---|
787 | return false; |
---|
788 | } |
---|
789 | container = decls[0]->logicalInternalContext(m_duContext->topContext()); |
---|
790 | }else if(m_duContext->parentContext() && m_duContext->parentContext()->type() == DUContext::Class && m_duContext->parentContext()->owner()) { |
---|
791 | container = m_duContext->parentContext(); |
---|
792 | } |
---|
793 | |
---|
794 | if(!container) |
---|
795 | return false; |
---|
796 | |
---|
797 | m_onlyShow = ShowVariables; |
---|
798 | m_isConstructorCompletion = true; |
---|
799 | m_accessType = MemberAccess; |
---|
800 | m_doAccessFiltering = false; |
---|
801 | |
---|
802 | QSet<QString> hadItemsSet = hadItems.toSet(); |
---|
803 | |
---|
804 | QList<CompletionTreeItemPointer> items; |
---|
805 | |
---|
806 | int pos = 1000; |
---|
807 | bool initializedNormalItems = false; |
---|
808 | |
---|
809 | //Pre-compute the items |
---|
810 | foreach(Declaration* decl, container->localDeclarations(m_duContext->topContext())) { |
---|
811 | ClassMemberDeclaration* classMem = dynamic_cast<ClassMemberDeclaration*>(decl); |
---|
812 | |
---|
813 | if(decl->kind() == Declaration::Instance && !decl->isFunctionDeclaration() && classMem && !classMem->isStatic()) { |
---|
814 | if(!hadItemsSet.contains(decl->identifier().toString())) { |
---|
815 | items << CompletionTreeItemPointer(new NormalDeclarationCompletionItem( DeclarationPointer(decl), KDevelop::CodeCompletionContext::Ptr(this), pos )); |
---|
816 | ++pos; |
---|
817 | }else{ |
---|
818 | initializedNormalItems = true; |
---|
819 | } |
---|
820 | } |
---|
821 | } |
---|
822 | |
---|
823 | if(!initializedNormalItems) { |
---|
824 | //Only offer constructor initializations before variables were initialized |
---|
825 | pos = 0; |
---|
826 | foreach(const DUContext::Import& import, container->importedParentContexts()) { |
---|
827 | DUContext* ctx = import.context(m_duContext->topContext()); |
---|
828 | if(ctx && ctx->type() == DUContext::Class && ctx->owner()) { |
---|
829 | items.insert(pos, CompletionTreeItemPointer(new NormalDeclarationCompletionItem( DeclarationPointer(ctx->owner()), KDevelop::CodeCompletionContext::Ptr(this), pos ))); |
---|
830 | ++pos; |
---|
831 | } |
---|
832 | } |
---|
833 | } |
---|
834 | |
---|
835 | |
---|
836 | eventuallyAddGroup(i18n("Initialize"), 0, items); |
---|
837 | |
---|
838 | return true; |
---|
839 | ///Step 1: Skip to the ':', to find the back of the function declaration. On the way, all expressions need to be constructor decls. |
---|
840 | } |
---|
841 | |
---|
842 | CodeCompletionContext::AccessType CodeCompletionContext::findAccessType( const QString &accessStr ) const { |
---|
843 | if( accessStr == "." ) |
---|
844 | return MemberAccess; |
---|
845 | |
---|
846 | if( accessStr == "->" ) |
---|
847 | return ArrowMemberAccess; |
---|
848 | |
---|
849 | //TODO: add support for MemberChoose |
---|
850 | if( accessStr == "::" ) |
---|
851 | return StaticMemberChoose; |
---|
852 | |
---|
853 | if ( m_depth > 0 ) |
---|
854 | { |
---|
855 | if( accessStr == "(" ) |
---|
856 | return FunctionCallAccess; |
---|
857 | |
---|
858 | if (accessStr == "<" ) { |
---|
859 | //We need to check here whether this really is a template access, or whether |
---|
860 | //it is a "less than" operator, which is a BinaryOpFunctionCallAccess |
---|
861 | int start_expr = expressionBefore( m_text, m_text.length()-1 ); |
---|
862 | |
---|
863 | QString expr = m_text.mid(start_expr, m_text.length() - start_expr - 1).trimmed(); |
---|
864 | |
---|
865 | ExpressionParser expressionParser; |
---|
866 | Cpp::ExpressionEvaluationResult result = |
---|
867 | expressionParser.evaluateExpression(expr.toUtf8(), m_duContext); |
---|
868 | if( result.isValid() && |
---|
869 | ( !result.isInstance || result.type.type<FunctionType>() ) && |
---|
870 | !result.type.type<DelayedType>() ) |
---|
871 | return TemplateAccess; |
---|
872 | } |
---|
873 | |
---|
874 | if ( accessStr == "return" ) |
---|
875 | return ReturnAccess; |
---|
876 | |
---|
877 | if ( accessStr == "case" ) |
---|
878 | return CaseAccess; |
---|
879 | |
---|
880 | if( BINARY_OPERATORS.contains( accessStr ) ) |
---|
881 | return BinaryOpFunctionCallAccess; |
---|
882 | } |
---|
883 | |
---|
884 | return NoMemberAccess; |
---|
885 | } |
---|
886 | |
---|
887 | void CodeCompletionContext:: |
---|
888 | findExpressionAndPrefix(QString& expression, QString& expressionPrefix, bool &isTypePrefix) const { |
---|
889 | int start_expr; |
---|
890 | start_expr = expressionBefore( m_text, m_text.length() ); |
---|
891 | expression = m_text.mid( start_expr ).trimmed(); |
---|
892 | |
---|
893 | if ( KEYWORD_ACCESS_STRINGS.contains( expression ) ) { |
---|
894 | expression = QString(); |
---|
895 | start_expr = -1; |
---|
896 | } |
---|
897 | |
---|
898 | expressionPrefix = m_text.left(start_expr).trimmed(); |
---|
899 | compressEndingWhitespace( expressionPrefix ); |
---|
900 | |
---|
901 | if ( expressionPrefix.isEmpty() ) |
---|
902 | return; |
---|
903 | |
---|
904 | ///handle "Type instance(" or "Type instance =". The "Type" part will be in the prefix |
---|
905 | if( expressionPrefix.endsWith('>') || expressionPrefix.endsWith('*') || |
---|
906 | isLegalIdentifier( expressionPrefix[expressionPrefix.length()-1] ) ) { |
---|
907 | |
---|
908 | int ptrs = 0; |
---|
909 | while ( expressionPrefix.endsWith( QString( "*" ).repeated( ptrs + 1 ) ) ) |
---|
910 | ++ptrs; |
---|
911 | int newExpressionStart = expressionBefore(expressionPrefix, expressionPrefix.length() - ptrs); |
---|
912 | QString newExpression = expressionPrefix.mid( newExpressionStart ).trimmed(); |
---|
913 | |
---|
914 | //Make sure it's not picking up something like "if (a < a > b)" |
---|
915 | ExpressionParser expressionParser; |
---|
916 | ExpressionEvaluationResult res = expressionParser.evaluateType( newExpression.toUtf8(), m_duContext ); |
---|
917 | |
---|
918 | //must use toString() comparison because sometimes isInstance is wrong (ie "var*", "new", "") TODO: fix |
---|
919 | if ( res.isValid() && !res.isInstance && whitespaceFree( res.toString() ) == whitespaceFree( newExpression ) ) { |
---|
920 | expressionPrefix = expressionPrefix.left( newExpressionStart ); |
---|
921 | compressEndingWhitespace( expressionPrefix ); |
---|
922 | expression = newExpression; |
---|
923 | isTypePrefix = true; |
---|
924 | return; |
---|
925 | } |
---|
926 | } |
---|
927 | |
---|
928 | //Add reference and dereference operators to expression |
---|
929 | QString op; |
---|
930 | while ( true ) { |
---|
931 | op = getUnaryOperator(expressionPrefix); |
---|
932 | if (op == "*" || op == "&") { |
---|
933 | expression.prepend(op); |
---|
934 | expressionPrefix.chop(op.length()); |
---|
935 | } else |
---|
936 | break; |
---|
937 | } |
---|
938 | } |
---|
939 | |
---|
940 | QList< ExpressionEvaluationResult > CodeCompletionContext::getKnownArgumentTypes() const { |
---|
941 | ExpressionParser expressionParser; |
---|
942 | QList< ExpressionEvaluationResult > expressionResults; |
---|
943 | for( QStringList::const_iterator it = m_knownArgumentExpressions.constBegin(); |
---|
944 | it != m_knownArgumentExpressions.constEnd(); ++it ) { |
---|
945 | expressionResults << expressionParser.evaluateExpression( (*it).toUtf8(), m_duContext ); |
---|
946 | } |
---|
947 | |
---|
948 | return expressionResults; |
---|
949 | } |
---|
950 | |
---|
951 | CodeCompletionContext::OnlyShow CodeCompletionContext::findOnlyShow(const QString &accessStr) const { |
---|
952 | //TODO: ShowSignals/Slots doesn't work at all outside of connect/disconnect, |
---|
953 | //but should be used for ie "const char * x = SIGNAL(" |
---|
954 | //TODO: Should only show types for a SHOW_TYPES_ACCESS_STRINGS in expressionPrefix |
---|
955 | //(at least for StaticMemberChoose) |
---|
956 | |
---|
957 | //Either there's no expression, which means Global completion, |
---|
958 | //or there is an expression, which means implementationhelperitems only |
---|
959 | if ( m_accessType == NoMemberAccess && !m_expression.isEmpty() && |
---|
960 | isImplementationHelperValid() ) |
---|
961 | return ShowImplementationHelpers; |
---|
962 | |
---|
963 | if( SHOW_TYPES_ACCESS_STRINGS.contains( accessStr ) ) |
---|
964 | return ShowTypes; |
---|
965 | |
---|
966 | if ( parentContext() && parentContext()->accessType() == TemplateAccess ) |
---|
967 | return ShowTypes; |
---|
968 | |
---|
969 | //Only ShowTypes in these DUContexts unless initializing a declaration |
---|
970 | //ie, m_expressionIsTypePrefix == true |
---|
971 | if (m_duContext->type() == DUContext::Class || |
---|
972 | m_duContext->type() == DUContext::Namespace || |
---|
973 | m_duContext->type() == DUContext::Global ) |
---|
974 | { |
---|
975 | CodeCompletionContext* ctxt = parentContext(); |
---|
976 | while (ctxt && !ctxt->m_expressionIsTypePrefix) |
---|
977 | ctxt = ctxt->parentContext(); |
---|
978 | |
---|
979 | if ( !ctxt && !m_expressionIsTypePrefix ) |
---|
980 | return ShowTypes; |
---|
981 | } |
---|
982 | |
---|
983 | return ShowAll; |
---|
984 | } |
---|
985 | |
---|
986 | QList< Cpp::ExpressionEvaluationResult > CodeCompletionContext::knownArgumentTypes() const { |
---|
987 | return m_knownArgumentTypes; |
---|
988 | } |
---|
989 | |
---|
990 | bool CodeCompletionContext::isConstructorInitialization() { |
---|
991 | return m_isConstructorCompletion; |
---|
992 | } |
---|
993 | |
---|
994 | void CodeCompletionContext::processFunctionCallAccess() { |
---|
995 | ///Generate a list of all found functions/operators, together with each a list of optional prefixed parameters |
---|
996 | ///All the variable argument-count management in the following code is done to treat global operator-functions equivalently to local ones. Those take an additional first argument. |
---|
997 | |
---|
998 | OverloadResolutionHelper helper( m_duContext, TopDUContextPointer(m_duContext->topContext()) ); |
---|
999 | |
---|
1000 | if( m_accessType == BinaryOpFunctionCallAccess ) { |
---|
1001 | |
---|
1002 | helper.setOperator(OverloadResolver::Parameter(m_expressionResult.type.abstractType(), m_expressionResult.isLValue())); |
---|
1003 | |
---|
1004 | m_functionName = "operator"+m_operator; |
---|
1005 | |
---|
1006 | } else { |
---|
1007 | ///Simply take all the declarations that were found by the expression-parser |
---|
1008 | |
---|
1009 | helper.setFunctions(declIdsToDeclPtrs(m_expressionResult.allDeclarations, m_expressionResult.allDeclarationsSize(), m_duContext->topContext())); |
---|
1010 | |
---|
1011 | if(m_expressionResult.allDeclarationsSize()) { |
---|
1012 | Declaration* decl = m_expressionResult.allDeclarations[0].getDeclaration(m_duContext->topContext()); |
---|
1013 | if(decl) |
---|
1014 | m_functionName = decl->identifier().toString(); |
---|
1015 | } |
---|
1016 | } |
---|
1017 | |
---|
1018 | if( m_accessType == BinaryOpFunctionCallAccess || m_expression == m_functionName ) |
---|
1019 | helper.setFunctionNameForADL( QualifiedIdentifier(m_functionName) ); |
---|
1020 | |
---|
1021 | OverloadResolver::ParameterList knownParameters; |
---|
1022 | foreach( const ExpressionEvaluationResult &result, m_knownArgumentTypes ) |
---|
1023 | knownParameters.parameters << OverloadResolver::Parameter( result.type.abstractType(), result.isLValue() ); |
---|
1024 | |
---|
1025 | helper.setKnownParameters(knownParameters); |
---|
1026 | |
---|
1027 | m_matchingFunctionOverloads = helper.resolveToList(true); |
---|
1028 | |
---|
1029 | if(m_accessType == BinaryOpFunctionCallAccess) { |
---|
1030 | //Filter away all global binary operators that do not have the first argument matched |
---|
1031 | QList< Function > oldFunctions = m_matchingFunctionOverloads; |
---|
1032 | m_matchingFunctionOverloads.clear(); |
---|
1033 | foreach(const Function& f, oldFunctions) { |
---|
1034 | if(f.matchedArguments == 1 && !f.function.isViable()) |
---|
1035 | continue; |
---|
1036 | else |
---|
1037 | m_matchingFunctionOverloads << f; |
---|
1038 | } |
---|
1039 | } |
---|
1040 | } |
---|
1041 | |
---|
1042 | bool CodeCompletionContext::doIncludeCompletion() |
---|
1043 | { |
---|
1044 | QString line = lastNLines(m_text, 1).trimmed(); |
---|
1045 | if(!line.startsWith("#")) |
---|
1046 | return false; |
---|
1047 | |
---|
1048 | if(line.count('"') == 2 || line.endsWith('>')) |
---|
1049 | return true; //We are behind a complete include-directive |
---|
1050 | |
---|
1051 | int endOfInclude = CppUtils::findEndOfInclude(line); |
---|
1052 | if(endOfInclude == -1) |
---|
1053 | return true; |
---|
1054 | |
---|
1055 | //Strip away #include |
---|
1056 | line = line.mid(endOfInclude).trimmed(); |
---|
1057 | |
---|
1058 | kDebug(9007) << "trimmed include line: " << line; |
---|
1059 | |
---|
1060 | if(!line.startsWith('<') && !line.startsWith('"')) |
---|
1061 | return true; //We are not behind the beginning of a path-specification |
---|
1062 | |
---|
1063 | line = line.mid(1); |
---|
1064 | |
---|
1065 | kDebug(9007) << "extract prefix from " << line; |
---|
1066 | //Extract the prefix-path |
---|
1067 | KUrl u(line); |
---|
1068 | |
---|
1069 | QString prefixPath; |
---|
1070 | if(line.contains('/')) { |
---|
1071 | u.setFileName(QString()); |
---|
1072 | prefixPath = u.toLocalFile(); |
---|
1073 | } |
---|
1074 | kDebug(9007) << "extracted prefix " << prefixPath; |
---|
1075 | |
---|
1076 | #ifndef TEST_COMPLETION |
---|
1077 | bool local = line.startsWith('"'); |
---|
1078 | m_includeItems = CppUtils::allFilesInIncludePath(KUrl(m_duContext->url().str()), local, prefixPath); |
---|
1079 | #endif |
---|
1080 | |
---|
1081 | m_accessType = IncludeListAccess; |
---|
1082 | |
---|
1083 | return true; |
---|
1084 | } |
---|
1085 | |
---|
1086 | const CodeCompletionContext::FunctionList& CodeCompletionContext::functions() const { |
---|
1087 | return m_matchingFunctionOverloads; |
---|
1088 | } |
---|
1089 | |
---|
1090 | QString CodeCompletionContext::functionName() const { |
---|
1091 | return m_functionName; |
---|
1092 | } |
---|
1093 | |
---|
1094 | QList<Cpp::IncludeItem> CodeCompletionContext::includeItems() const { |
---|
1095 | return m_includeItems; |
---|
1096 | } |
---|
1097 | |
---|
1098 | ExpressionEvaluationResult CodeCompletionContext::memberAccessContainer() const { |
---|
1099 | return m_expressionResult; |
---|
1100 | } |
---|
1101 | |
---|
1102 | QSet<DUContext*> CodeCompletionContext::memberAccessContainers() const { |
---|
1103 | QSet<DUContext*> ret; |
---|
1104 | |
---|
1105 | if( m_accessType == StaticMemberChoose && m_duContext ) { |
---|
1106 | //Locate all namespace-instances we will be completing from |
---|
1107 | QList< Declaration* > decls = m_duContext->findDeclarations(QualifiedIdentifier(m_expression)); ///@todo respect position |
---|
1108 | |
---|
1109 | // qlist does not provide convenient stable iterators |
---|
1110 | // std::list<Declaration*> worklist(decls.begin(), decls.end()); |
---|
1111 | for (QList<Declaration*>::iterator it = decls.begin(); it != decls.end(); ++it) { |
---|
1112 | Declaration * decl = *it; |
---|
1113 | if((decl->kind() == Declaration::Namespace || dynamic_cast<ClassDeclaration*>(decl)) && decl->internalContext()) |
---|
1114 | ret.insert(decl->internalContext()); |
---|
1115 | else if (decl->kind() == Declaration::NamespaceAlias) { |
---|
1116 | NamespaceAliasDeclaration * aliasDecl = dynamic_cast<NamespaceAliasDeclaration*>(decl); |
---|
1117 | if (aliasDecl) { |
---|
1118 | QList<Declaration*> importedDecls = m_duContext->findDeclarations(aliasDecl->importIdentifier()); ///@todo respect position |
---|
1119 | std::copy(importedDecls.begin(), importedDecls.end(), |
---|
1120 | std::back_inserter(decls)); |
---|
1121 | } |
---|
1122 | } |
---|
1123 | } |
---|
1124 | } |
---|
1125 | |
---|
1126 | if(m_expressionResult.isValid() ) { |
---|
1127 | AbstractType::Ptr expressionTarget = TypeUtils::targetType(m_expressionResult.type.abstractType(), m_duContext->topContext()); |
---|
1128 | const IdentifiedType* idType = dynamic_cast<const IdentifiedType*>( expressionTarget.unsafeData() ); |
---|
1129 | Declaration* idDecl = 0; |
---|
1130 | if( idType && (idDecl = idType->declaration(m_duContext->topContext())) ) { |
---|
1131 | DUContext* ctx = idDecl->logicalInternalContext(m_duContext->topContext()); |
---|
1132 | if( ctx ){ |
---|
1133 | if(ctx->type() != DUContext::Template) //Forward-declared template classes have a template-context assigned. Those should not be searched. |
---|
1134 | ret.insert(ctx); |
---|
1135 | }else { |
---|
1136 | //Print some debug-output |
---|
1137 | kDebug(9007) << "Could not get internal context from" << m_expressionResult.type.abstractType()->toString(); |
---|
1138 | kDebug(9007) << "Declaration" << idDecl->toString() << idDecl->isForwardDeclaration(); |
---|
1139 | if( Cpp::TemplateDeclaration* tempDeclaration = dynamic_cast<Cpp::TemplateDeclaration*>(idDecl) ) { |
---|
1140 | if( tempDeclaration->instantiatedFrom() ) { |
---|
1141 | kDebug(9007) << "instantiated from" << dynamic_cast<Declaration*>(tempDeclaration->instantiatedFrom())->toString() << dynamic_cast<Declaration*>(tempDeclaration->instantiatedFrom())->isForwardDeclaration(); |
---|
1142 | kDebug(9007) << "internal context" << dynamic_cast<Declaration*>(tempDeclaration->instantiatedFrom())->internalContext(); |
---|
1143 | } |
---|
1144 | } |
---|
1145 | |
---|
1146 | } |
---|
1147 | } |
---|
1148 | } |
---|
1149 | |
---|
1150 | // foreach(DUContext* context, ret) { |
---|
1151 | // kDebug() << "member-access container:" << context->url().str() << context->range().textRange() << context->scopeIdentifier(true).toString(); |
---|
1152 | // } |
---|
1153 | |
---|
1154 | return ret; |
---|
1155 | } |
---|
1156 | |
---|
1157 | KDevelop::IndexedType CodeCompletionContext::applyPointerConversionForMatching(KDevelop::IndexedType type, bool fromLValue) const { |
---|
1158 | if(!m_duContext) |
---|
1159 | return KDevelop::IndexedType(); |
---|
1160 | |
---|
1161 | if(m_pointerConversionsBeforeMatching == 0) |
---|
1162 | return type; |
---|
1163 | AbstractType::Ptr t = type.abstractType(); |
---|
1164 | if(!t) |
---|
1165 | return KDevelop::IndexedType(); |
---|
1166 | |
---|
1167 | //Can only take addresses of lvalues |
---|
1168 | if(m_pointerConversionsBeforeMatching > 1 || (m_pointerConversionsBeforeMatching && !fromLValue)) |
---|
1169 | return IndexedType(); |
---|
1170 | |
---|
1171 | if(m_pointerConversionsBeforeMatching > 0) { |
---|
1172 | for(int a = 0; a < m_pointerConversionsBeforeMatching; ++a) { |
---|
1173 | |
---|
1174 | t = TypeUtils::increasePointerDepth(t); |
---|
1175 | if(!t) |
---|
1176 | return IndexedType(); |
---|
1177 | } |
---|
1178 | }else{ |
---|
1179 | for(int a = m_pointerConversionsBeforeMatching; a < 0; ++a) { |
---|
1180 | t = TypeUtils::decreasePointerDepth(t, m_duContext->topContext()); |
---|
1181 | if(!t) |
---|
1182 | return IndexedType(); |
---|
1183 | } |
---|
1184 | } |
---|
1185 | |
---|
1186 | return t->indexed(); |
---|
1187 | } |
---|
1188 | |
---|
1189 | CodeCompletionContext::~CodeCompletionContext() { |
---|
1190 | } |
---|
1191 | |
---|
1192 | bool CodeCompletionContext::isValidPosition() { |
---|
1193 | if( m_text.isEmpty() ) |
---|
1194 | return true; |
---|
1195 | //If we are in a string or comment, we should not complete anything |
---|
1196 | QString markedText = clearComments(m_text, '$'); |
---|
1197 | markedText = clearStrings(markedText,'$'); |
---|
1198 | |
---|
1199 | if( markedText[markedText.length()-1] == '$' ) { |
---|
1200 | //We are within a comment or string |
---|
1201 | kDebug(9007) << "code-completion position is invalid, marked text: \n\"" << markedText << "\"\n unmarked text:\n" << m_text << "\n"; |
---|
1202 | return false; |
---|
1203 | } |
---|
1204 | return true; |
---|
1205 | } |
---|
1206 | |
---|
1207 | |
---|
1208 | bool CodeCompletionContext::isImplementationHelperValid() const |
---|
1209 | { |
---|
1210 | if (m_onlyShow == ShowVariables || m_isConstructorCompletion) |
---|
1211 | return false; |
---|
1212 | if (m_accessType != NoMemberAccess && m_accessType != StaticMemberChoose) |
---|
1213 | return false; |
---|
1214 | |
---|
1215 | LOCKDUCHAIN; |
---|
1216 | if (!m_duContext) |
---|
1217 | return false; |
---|
1218 | |
---|
1219 | return ( !parentContext() && ( m_duContext->type() == DUContext::Namespace || |
---|
1220 | m_duContext->type() == DUContext::Global) ); |
---|
1221 | } |
---|
1222 | |
---|
1223 | static TopDUContext* proxyContextForUrl(KUrl url) |
---|
1224 | { |
---|
1225 | QList< ILanguage* > languages = ICore::self()->languageController()->languagesForUrl(url); |
---|
1226 | foreach(ILanguage* language, languages) |
---|
1227 | { |
---|
1228 | if(language->languageSupport()) |
---|
1229 | return language->languageSupport()->standardContext(url, true); |
---|
1230 | } |
---|
1231 | |
---|
1232 | return 0; |
---|
1233 | } |
---|
1234 | |
---|
1235 | void CodeCompletionContext::preprocessText( int line ) { |
---|
1236 | QSet<IndexedString> disableMacros; |
---|
1237 | disableMacros.insert(IndexedString("SIGNAL")); |
---|
1238 | disableMacros.insert(IndexedString("SLOT")); |
---|
1239 | disableMacros.insert(IndexedString("emit")); |
---|
1240 | disableMacros.insert(IndexedString("Q_EMIT")); |
---|
1241 | disableMacros.insert(IndexedString("Q_SIGNAL")); |
---|
1242 | disableMacros.insert(IndexedString("Q_SLOT")); |
---|
1243 | |
---|
1244 | // Use the proxy-context if possible, because that one contains most of the macros if existent |
---|
1245 | TopDUContext* useTopContext = proxyContextForUrl(m_duContext->url().toUrl()); |
---|
1246 | if(!useTopContext) |
---|
1247 | useTopContext = m_duContext->topContext(); |
---|
1248 | |
---|
1249 | m_text = preprocess( m_text, dynamic_cast<Cpp::EnvironmentFile*>(useTopContext->parsingEnvironmentFile().data()), line, disableMacros ); |
---|
1250 | |
---|
1251 | m_text = clearComments( m_text ); |
---|
1252 | } |
---|
1253 | |
---|
1254 | CodeCompletionContext::AccessType CodeCompletionContext::accessType() const { |
---|
1255 | return m_accessType; |
---|
1256 | } |
---|
1257 | |
---|
1258 | CodeCompletionContext* CodeCompletionContext::parentContext() const { |
---|
1259 | return KSharedPtr<CodeCompletionContext>::staticCast(m_parentContext).data(); |
---|
1260 | } |
---|
1261 | |
---|
1262 | void getOverridable(DUContext* base, DUContext* current, QMap< QPair<IndexedType, IndexedString>, KDevelop::CompletionTreeItemPointer >& overridable, CodeCompletionContext::Ptr completionContext, int depth = 0) { |
---|
1263 | if(!current) |
---|
1264 | return; |
---|
1265 | |
---|
1266 | foreach(Declaration* decl, current->localDeclarations()) { |
---|
1267 | ClassFunctionDeclaration* classFun = dynamic_cast<ClassFunctionDeclaration*>(decl); |
---|
1268 | // one can only override the direct parent's ctor |
---|
1269 | if(classFun && (classFun->isVirtual() || (depth == 0 && classFun->isConstructor()))) { |
---|
1270 | QPair<IndexedType, IndexedString> key = qMakePair(classFun->indexedType(), classFun->identifier().identifier()); |
---|
1271 | if(base->owner()) { |
---|
1272 | if(classFun->isConstructor() || classFun->isDestructor()) |
---|
1273 | key.second = base->owner()->identifier().identifier(); |
---|
1274 | if(classFun->isDestructor()) |
---|
1275 | key.second = IndexedString("~" + key.second.str()); |
---|
1276 | } |
---|
1277 | if(!overridable.contains(key) && base->findLocalDeclarations(KDevelop::Identifier(key.second), CursorInRevision::invalid(), 0, key.first.abstractType(), KDevelop::DUContext::OnlyFunctions).isEmpty()) |
---|
1278 | overridable.insert(key, KDevelop::CompletionTreeItemPointer(new ImplementationHelperItem(ImplementationHelperItem::Override, DeclarationPointer(decl), completionContext, (classFun && classFun->isAbstract()) ? 1 : 2))); |
---|
1279 | } |
---|
1280 | } |
---|
1281 | |
---|
1282 | foreach(const DUContext::Import &import, current->importedParentContexts()) |
---|
1283 | getOverridable(base, import.context(base->topContext()), overridable, completionContext, depth + 1); |
---|
1284 | } |
---|
1285 | |
---|
1286 | // #ifndef TEST_COMPLETION |
---|
1287 | |
---|
1288 | QList< KSharedPtr< KDevelop::CompletionTreeElement > > CodeCompletionContext::ungroupedElements() { |
---|
1289 | return m_storedUngroupedItems; |
---|
1290 | } |
---|
1291 | |
---|
1292 | QList<CompletionTreeItemPointer> CodeCompletionContext::memberAccessCompletionItems( const bool& shouldAbort ) |
---|
1293 | { |
---|
1294 | QList<CompletionTreeItemPointer> items; |
---|
1295 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1296 | |
---|
1297 | if( !memberAccessContainer().isValid() && m_accessType != StaticMemberChoose ) |
---|
1298 | return items; |
---|
1299 | |
---|
1300 | bool typeIsConst = false; |
---|
1301 | AbstractType::Ptr expressionTarget = TypeUtils::targetType(m_expressionResult.type.abstractType(), m_duContext->topContext()); |
---|
1302 | if (expressionTarget && (expressionTarget->modifiers() & AbstractType::ConstModifier)) |
---|
1303 | typeIsConst = true; |
---|
1304 | |
---|
1305 | QSet<DUContext*> containers = memberAccessContainers(); |
---|
1306 | ifDebug( kDebug() << "got" << containers.size() << "member-access containers"; ) |
---|
1307 | if (containers.isEmpty()) |
---|
1308 | { |
---|
1309 | ifDebug( kDebug() << "missing-include completion for" << m_expression << m_expressionResult.toString(); ) |
---|
1310 | eventuallyAddGroup(i18n("Not Included Container"), 700, missingIncludeCompletionItems(m_expression, QString(), m_expressionResult, m_duContext.data(), 0, true )); |
---|
1311 | } |
---|
1312 | |
---|
1313 | //Used to show only one namespace-declaration per namespace |
---|
1314 | QSet<QualifiedIdentifier> hadNamespaceDeclarations; |
---|
1315 | |
---|
1316 | foreach(DUContext* ctx, containers) { |
---|
1317 | if (shouldAbort) |
---|
1318 | return items; |
---|
1319 | ifDebug( kDebug() << "container:" << ctx->scopeIdentifier(true).toString(); ) |
---|
1320 | |
---|
1321 | foreach( const DeclarationDepthPair& decl, |
---|
1322 | Cpp::hideOverloadedDeclarations( |
---|
1323 | ctx->allDeclarations(ctx->range().end, m_duContext->topContext(), false ), |
---|
1324 | typeIsConst ) ) |
---|
1325 | { |
---|
1326 | //If we have StaticMemberChoose, which means A::Bla, show only static members, except if we're within a class that derives from the container |
---|
1327 | ClassMemberDeclaration* classMember = dynamic_cast<ClassMemberDeclaration*>(decl.first); |
---|
1328 | |
---|
1329 | if(classMember && !filterDeclaration(classMember, ctx)) |
---|
1330 | continue; |
---|
1331 | else if(!filterDeclaration(decl.first, ctx)) |
---|
1332 | continue; |
---|
1333 | |
---|
1334 | if (accessType() == MemberAccess || accessType() == ArrowMemberAccess) { |
---|
1335 | // Don't allow constructors to be accessed with . or -> |
---|
1336 | if (ClassFunctionDeclaration* classFun = dynamic_cast<ClassFunctionDeclaration*>(classMember)) |
---|
1337 | if (classFun->isConstructor()) |
---|
1338 | continue; |
---|
1339 | } |
---|
1340 | |
---|
1341 | if(decl.first->kind() == Declaration::Namespace) { |
---|
1342 | QualifiedIdentifier id = decl.first->qualifiedIdentifier(); |
---|
1343 | if(hadNamespaceDeclarations.contains(id)) |
---|
1344 | continue; |
---|
1345 | |
---|
1346 | hadNamespaceDeclarations.insert(id); |
---|
1347 | } |
---|
1348 | |
---|
1349 | if(accessType() != Cpp::CodeCompletionContext::StaticMemberChoose) { |
---|
1350 | if(decl.first->kind() != Declaration::Instance && decl.first->kind() != Declaration::Alias) |
---|
1351 | continue; |
---|
1352 | if(decl.first->abstractType().cast<EnumeratorType>()) |
---|
1353 | continue; //Skip enumerators |
---|
1354 | }else{ |
---|
1355 | ///@todo what NOT to show on static member choose? Actually we cannot hide all non-static functions, because of function-pointers |
---|
1356 | } |
---|
1357 | |
---|
1358 | if(!decl.first->identifier().isEmpty()) |
---|
1359 | items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem( DeclarationPointer(decl.first), KDevelop::CodeCompletionContext::Ptr(this), decl.second ) ); |
---|
1360 | } |
---|
1361 | } |
---|
1362 | |
---|
1363 | return items; |
---|
1364 | } |
---|
1365 | |
---|
1366 | QList<CompletionTreeItemPointer> CodeCompletionContext::returnAccessCompletionItems() |
---|
1367 | { |
---|
1368 | QList<CompletionTreeItemPointer> items; |
---|
1369 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1370 | |
---|
1371 | DUContext* functionContext = m_duContext.data(); |
---|
1372 | while(functionContext && !functionContext->owner()) |
---|
1373 | functionContext = functionContext->parentContext(); |
---|
1374 | if(functionContext && functionContext->owner()) { |
---|
1375 | FunctionType::Ptr funType = functionContext->owner()->type<FunctionType>(); |
---|
1376 | if(funType && funType->returnType()) { |
---|
1377 | items << CompletionTreeItemPointer( new TypeConversionCompletionItem( "return " + funType->returnType()->toString(), funType->returnType()->indexed(), depth(), KSharedPtr <Cpp::CodeCompletionContext >(this) ) ); |
---|
1378 | } |
---|
1379 | } |
---|
1380 | return items; |
---|
1381 | } |
---|
1382 | |
---|
1383 | QList<CompletionTreeItemPointer> CodeCompletionContext::caseAccessCompletionItems() |
---|
1384 | { |
---|
1385 | QList<CompletionTreeItemPointer> items; |
---|
1386 | |
---|
1387 | IndexedType switchExprType = switchExpressionType(m_duContext); |
---|
1388 | |
---|
1389 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1390 | |
---|
1391 | if (switchExprType.abstractType()) |
---|
1392 | items << CompletionTreeItemPointer( new TypeConversionCompletionItem( "case " + switchExprType.abstractType()->toString(), switchExprType, depth(), KSharedPtr <Cpp::CodeCompletionContext >(this) ) ); |
---|
1393 | return items; |
---|
1394 | } |
---|
1395 | |
---|
1396 | QList<CompletionTreeItemPointer> CodeCompletionContext::templateAccessCompletionItems() |
---|
1397 | { |
---|
1398 | QList<CompletionTreeItemPointer> items; |
---|
1399 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1400 | |
---|
1401 | AbstractType::Ptr type = m_expressionResult.type.abstractType(); |
---|
1402 | IdentifiedType* identified = dynamic_cast<IdentifiedType*>(type.unsafeData()); |
---|
1403 | Declaration* decl = 0; |
---|
1404 | if(identified) |
---|
1405 | decl = identified->declaration( m_duContext->topContext()); |
---|
1406 | if(!decl && !m_expressionResult.allDeclarations.isEmpty()) |
---|
1407 | decl = m_expressionResult.allDeclarations[0].getDeclaration(m_duContext->topContext()); |
---|
1408 | if(decl) { |
---|
1409 | NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem( KDevelop::DeclarationPointer(decl), KDevelop::CodeCompletionContext::Ptr(this), 0, 0 ); |
---|
1410 | item->m_isTemplateCompletion = true; |
---|
1411 | items << CompletionTreeItemPointer( item ); |
---|
1412 | }else{ |
---|
1413 | items += missingIncludeCompletionItems(m_expression, QString(), m_expressionResult, m_duContext.data(), depth(), true ); |
---|
1414 | } |
---|
1415 | return items; |
---|
1416 | } |
---|
1417 | |
---|
1418 | QList<CompletionTreeItemPointer> CodeCompletionContext::commonFunctionAccessCompletionItems( bool fullCompletion ) |
---|
1419 | { |
---|
1420 | QList<CompletionTreeItemPointer> items; |
---|
1421 | |
---|
1422 | uint max = MoreArgumentHintsCompletionItem::resetMaxArgumentHints(!fullCompletion); |
---|
1423 | |
---|
1424 | if(functions().isEmpty() && m_accessType != BinaryOpFunctionCallAccess) { |
---|
1425 | items += missingIncludeCompletionItems(m_expression, QString(), m_expressionResult, m_duContext.data(), depth(), true ); |
---|
1426 | return items; |
---|
1427 | } |
---|
1428 | |
---|
1429 | uint num = 0; |
---|
1430 | foreach( const Cpp::CodeCompletionContext::Function &function, functions() ) { |
---|
1431 | if (num == max) { |
---|
1432 | //When there are too many overloaded functions, do not show them all |
---|
1433 | CompletionTreeItemPointer item( new MoreArgumentHintsCompletionItem( KDevelop::CodeCompletionContext::Ptr(this), i18ncp("Here, overload is used as a programming term. This string is used to display how many overloaded versions there are of the function whose name is the second argument.", "1 more overload of %2 (show more)", "%1 more overloads of %2 (show more)", functions().count() - num, functionName()), num ) ); |
---|
1434 | items.push_front(item); |
---|
1435 | break; |
---|
1436 | } |
---|
1437 | |
---|
1438 | items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem( function.function.declaration(), KDevelop::CodeCompletionContext::Ptr(this), 0, num ) ); |
---|
1439 | ++num; |
---|
1440 | } |
---|
1441 | |
---|
1442 | return items; |
---|
1443 | } |
---|
1444 | |
---|
1445 | QList< CompletionTreeItemPointer > CodeCompletionContext::binaryFunctionAccessCompletionItems( bool fullCompletion ) |
---|
1446 | { |
---|
1447 | QList<CompletionTreeItemPointer> items; |
---|
1448 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1449 | |
---|
1450 | items += commonFunctionAccessCompletionItems(fullCompletion); |
---|
1451 | |
---|
1452 | //Argument-hints for builtin operators |
---|
1453 | AbstractType::Ptr type = m_expressionResult.type.abstractType(); |
---|
1454 | if(!m_expressionResult.isValid() || !m_expressionResult.isInstance || !type) |
---|
1455 | return items; |
---|
1456 | |
---|
1457 | IntegralType::Ptr integral = type.cast<IntegralType>(); |
---|
1458 | |
---|
1459 | if(!integral && (ARITHMETIC_COMPARISON_OPERATORS.contains(m_operator) || BINARY_ARITHMETIC_OPERATORS.contains(m_operator))) { |
---|
1460 | ///There is one more chance: If the type can be converted to an integral type, C++ will convert it first, and then |
---|
1461 | ///apply its builtin operators |
---|
1462 | integral = IntegralType::Ptr(new IntegralType(KDevelop::IntegralType::TypeInt)); |
---|
1463 | TypeConversion conv(m_duContext->topContext()); |
---|
1464 | if(!conv.implicitConversion(m_expressionResult.type, integral->indexed())) |
---|
1465 | integral = IntegralType::Ptr(); //No conversion possible |
---|
1466 | } |
---|
1467 | |
---|
1468 | if( m_operator == "[]" && (type.cast<KDevelop::ArrayType>() || type.cast<KDevelop::PointerType>())) { |
---|
1469 | IntegralType::Ptr t(new IntegralType(IntegralType::TypeInt)); |
---|
1470 | t->setModifiers(IntegralType::UnsignedModifier); |
---|
1471 | QString showName = "operator []"; |
---|
1472 | items << CompletionTreeItemPointer( new TypeConversionCompletionItem( showName, t->indexed(), depth(), KSharedPtr <Cpp::CodeCompletionContext >(this) ) ); |
---|
1473 | } |
---|
1474 | |
---|
1475 | if( m_operator == "=" || integral ) { |
---|
1476 | ///Conversion to the left operand-type, builtin operators on integral types |
---|
1477 | IndexedType useType = integral ? integral->indexed() : m_expressionResult.type; |
---|
1478 | QString showName = functionName(); |
---|
1479 | if(useType.abstractType()) |
---|
1480 | showName = useType.abstractType()->toString() + " " + m_operator; |
---|
1481 | |
---|
1482 | if(useType == m_expressionResult.type && m_expressionResult.allDeclarations.size() == 1) { |
---|
1483 | Declaration* decl = m_expressionResult.allDeclarations[0].getDeclaration(m_duContext->topContext()); |
---|
1484 | if(decl) |
---|
1485 | showName = decl->toString() + " " + m_operator; |
---|
1486 | } |
---|
1487 | |
---|
1488 | items << CompletionTreeItemPointer( new TypeConversionCompletionItem( showName, useType, depth(), KSharedPtr <Cpp::CodeCompletionContext >(this) ) ); |
---|
1489 | } |
---|
1490 | |
---|
1491 | return items; |
---|
1492 | } |
---|
1493 | |
---|
1494 | QList<CompletionTreeItemPointer> CodeCompletionContext::functionAccessCompletionItems(bool fullCompletion) |
---|
1495 | { |
---|
1496 | QList<CompletionTreeItemPointer> items; |
---|
1497 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1498 | |
---|
1499 | items += commonFunctionAccessCompletionItems(fullCompletion); |
---|
1500 | |
---|
1501 | if(!m_expressionResult.isValid() || |
---|
1502 | !m_expressionResult.type.abstractType() || |
---|
1503 | (m_expressionResult.isInstance && !m_expressionIsTypePrefix) || |
---|
1504 | m_expressionResult.type.type<FunctionType>()) |
---|
1505 | return items; |
---|
1506 | |
---|
1507 | //Eventually add a builtin copy-constructor if a type is being constructed |
---|
1508 | if(!hasCopyConstructor(m_expressionResult.type.type<CppClassType>(), m_duContext->topContext()) && |
---|
1509 | m_knownArgumentExpressions.isEmpty()) |
---|
1510 | { |
---|
1511 | QString showName = m_expressionResult.type.abstractType()->toString() + "("; |
---|
1512 | items << CompletionTreeItemPointer( new TypeConversionCompletionItem( showName, m_expressionResult.type, depth(), KSharedPtr <Cpp::CodeCompletionContext >(this) ) ); |
---|
1513 | } |
---|
1514 | |
---|
1515 | return items; |
---|
1516 | } |
---|
1517 | |
---|
1518 | QList<CompletionTreeItemPointer> CodeCompletionContext::includeListAccessCompletionItems(const bool& shouldAbort) |
---|
1519 | { |
---|
1520 | QList<CompletionTreeItemPointer> items; |
---|
1521 | |
---|
1522 | QList<KDevelop::IncludeItem> allIncludeItems = includeItems(); |
---|
1523 | foreach(const KDevelop::IncludeItem& includeItem, allIncludeItems) { |
---|
1524 | if (shouldAbort) |
---|
1525 | return items; |
---|
1526 | |
---|
1527 | items << CompletionTreeItemPointer( new IncludeFileCompletionItem(includeItem) ); |
---|
1528 | } |
---|
1529 | |
---|
1530 | return items; |
---|
1531 | } |
---|
1532 | |
---|
1533 | QList<CompletionTreeItemPointer> CodeCompletionContext::signalSlotAccessCompletionItems() |
---|
1534 | { |
---|
1535 | QList<CompletionTreeItemPointer> items; |
---|
1536 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1537 | |
---|
1538 | KDevelop::IndexedDeclaration connectedSignal; |
---|
1539 | if(!m_connectedSignalIdentifier.isEmpty()) { |
---|
1540 | ///Create an additional argument-hint context that shows information about the signal we connect to |
---|
1541 | if(parentContext() && parentContext()->m_knownArgumentTypes.count() > 1 && parentContext()->m_knownArgumentTypes[0].type.isValid()) { |
---|
1542 | StructureType::Ptr signalContainerType = TypeUtils::targetType(parentContext()->m_knownArgumentTypes[0].type.abstractType(), m_duContext->topContext()).cast<StructureType>(); |
---|
1543 | if(signalContainerType) { |
---|
1544 | // kDebug() << "searching signal in container" << signalContainerType->toString() << m_connectedSignalIdentifier.toString(); |
---|
1545 | Declaration* signalContainer = signalContainerType->declaration(m_duContext->topContext()); |
---|
1546 | if(signalContainer && signalContainer->internalContext()) { |
---|
1547 | IndexedString signature(m_connectedSignalNormalizedSignature); |
---|
1548 | foreach(const DeclarationDepthPair &decl, signalContainer->internalContext()->allDeclarations( CursorInRevision::invalid(), m_duContext->topContext(), false )) { |
---|
1549 | if(decl.first->identifier() == m_connectedSignalIdentifier) { |
---|
1550 | if(QtFunctionDeclaration* classFun = dynamic_cast<QtFunctionDeclaration*>(decl.first)) { |
---|
1551 | if(classFun->isSignal() && classFun->normalizedSignature() == signature) { |
---|
1552 | //Match |
---|
1553 | NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem( DeclarationPointer(decl.first), KDevelop::CodeCompletionContext::Ptr(parentContext()), decl.second + 50); |
---|
1554 | item->useAlternativeText = true; |
---|
1555 | m_connectedSignal = IndexedDeclaration(decl.first); |
---|
1556 | item->alternativeText = i18n("Connect to %1 (%2)", decl.first->qualifiedIdentifier().toString(), QString::fromUtf8(m_connectedSignalNormalizedSignature) ); |
---|
1557 | item->m_isQtSignalSlotCompletion = true; |
---|
1558 | items << CompletionTreeItemPointer(item); |
---|
1559 | connectedSignal = IndexedDeclaration(decl.first); |
---|
1560 | } |
---|
1561 | } |
---|
1562 | } |
---|
1563 | } |
---|
1564 | } |
---|
1565 | } |
---|
1566 | } |
---|
1567 | } |
---|
1568 | if( memberAccessContainer().isValid() ) { |
---|
1569 | QList<CompletionTreeItemPointer> signalSlots; |
---|
1570 | ///Collect all slots/signals to show |
---|
1571 | AbstractType::Ptr type = memberAccessContainer().type.abstractType(); |
---|
1572 | IdentifiedType* identified = dynamic_cast<IdentifiedType*>(type.unsafeData()); |
---|
1573 | if(identified) { |
---|
1574 | Declaration* decl = identified->declaration(m_duContext->topContext()); |
---|
1575 | if(decl && decl->internalContext() /*&& Cpp::findLocalDeclarations(decl->internalContext(), Identifier("QObject"), m_duContext->topContext()).count()*/) { //hacky test whether it's a QObject |
---|
1576 | ///@todo Always allow this when the class is within one of the open projects. Problem: The project lookup is not threadsafe |
---|
1577 | if(connectedSignal.isValid() && m_localClass.data() == decl->internalContext()) { ///Create implementation-helper to add a slot |
---|
1578 | signalSlots << CompletionTreeItemPointer(new ImplementationHelperItem(ImplementationHelperItem::CreateSignalSlot, DeclarationPointer(connectedSignal.data()), CodeCompletionContext::Ptr(this))); |
---|
1579 | } |
---|
1580 | |
---|
1581 | foreach(const DeclarationDepthPair &candidate, decl->internalContext()->allDeclarations(CursorInRevision::invalid(), m_duContext->topContext(), false) ) { |
---|
1582 | if(QtFunctionDeclaration* classFun = dynamic_cast<QtFunctionDeclaration*>(candidate.first)) { |
---|
1583 | if((classFun->isSignal() && m_onlyShow != ShowSlots) || (accessType() == SlotAccess && classFun->isSlot() && filterDeclaration(classFun))) { |
---|
1584 | NormalDeclarationCompletionItem* item = new NormalDeclarationCompletionItem( DeclarationPointer(candidate.first), KDevelop::CodeCompletionContext::Ptr(this), candidate.second ); |
---|
1585 | item->m_isQtSignalSlotCompletion = true; |
---|
1586 | if(!m_connectedSignalIdentifier.isEmpty()) { |
---|
1587 | item->m_fixedMatchQuality = 0; |
---|
1588 | //Compute a match-quality, by comparing the strings |
---|
1589 | QByteArray thisSignature = classFun->normalizedSignature().byteArray(); |
---|
1590 | if(m_connectedSignalNormalizedSignature.startsWith(thisSignature) || (m_connectedSignalNormalizedSignature.isEmpty() && thisSignature.isEmpty())) { |
---|
1591 | QByteArray remaining = m_connectedSignalNormalizedSignature.mid(thisSignature.length()); |
---|
1592 | int remainingElements = remaining.split(',').count(); |
---|
1593 | if(remaining.isEmpty()) |
---|
1594 | item->m_fixedMatchQuality = 10; |
---|
1595 | else if(remainingElements < 4) |
---|
1596 | item->m_fixedMatchQuality = 6 - remainingElements; |
---|
1597 | else |
---|
1598 | item->m_fixedMatchQuality = 2; |
---|
1599 | } |
---|
1600 | }else{ |
---|
1601 | item->m_fixedMatchQuality = 10; |
---|
1602 | } |
---|
1603 | signalSlots << CompletionTreeItemPointer( item ); |
---|
1604 | } |
---|
1605 | } |
---|
1606 | } |
---|
1607 | |
---|
1608 | eventuallyAddGroup(i18n("Signals/Slots"), 10, signalSlots); |
---|
1609 | } |
---|
1610 | } |
---|
1611 | } |
---|
1612 | return items; |
---|
1613 | } |
---|
1614 | |
---|
1615 | QList< CompletionTreeItemPointer > CodeCompletionContext::standardAccessCompletionItems() { |
---|
1616 | QList<CompletionTreeItemPointer> items; |
---|
1617 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1618 | //Normal case: Show all visible declarations |
---|
1619 | QSet<QualifiedIdentifier> hadNamespaceDeclarations; |
---|
1620 | |
---|
1621 | bool typeIsConst = false; |
---|
1622 | if (Declaration* func = Cpp::localFunctionFromCodeContext(m_duContext.data())) { |
---|
1623 | if (func->abstractType() && (func->abstractType()->modifiers() & AbstractType::ConstModifier)) |
---|
1624 | typeIsConst = true; |
---|
1625 | } |
---|
1626 | |
---|
1627 | QList<DeclarationDepthPair> decls = m_duContext->allDeclarations(m_duContext->type() == DUContext::Class ? m_duContext->range().end : m_position, m_duContext->topContext()); |
---|
1628 | |
---|
1629 | //Collect the contents of unnamed namespaces |
---|
1630 | QList<Declaration*> unnamed = m_duContext->findDeclarations(QualifiedIdentifier(unnamedNamespaceIdentifier().identifier()), m_position); |
---|
1631 | foreach(Declaration* ns, unnamed) |
---|
1632 | if(ns->kind() == Declaration::Namespace && ns->internalContext()) |
---|
1633 | decls += ns->internalContext()->allDeclarations(m_position, m_duContext->topContext(), false); |
---|
1634 | |
---|
1635 | //Collect the Declarations from all "using namespace" imported contexts |
---|
1636 | QList<Declaration*> imports = m_duContext->findDeclarations( globalImportIdentifier(), m_position, 0, DUContext::NoFiltering ); |
---|
1637 | |
---|
1638 | QSet<QualifiedIdentifier> ids; |
---|
1639 | foreach(Declaration* importDecl, imports) { |
---|
1640 | NamespaceAliasDeclaration* aliasDecl = dynamic_cast<NamespaceAliasDeclaration*>(importDecl); |
---|
1641 | if(aliasDecl) { |
---|
1642 | ids.insert(aliasDecl->importIdentifier()); |
---|
1643 | }else{ |
---|
1644 | kDebug() << "Import is not based on NamespaceAliasDeclaration"; |
---|
1645 | } |
---|
1646 | } |
---|
1647 | |
---|
1648 | QualifiedIdentifier ownNamespaceScope = Cpp::namespaceScopeComponentFromContext(m_duContext->scopeIdentifier(true), m_duContext.data(), m_duContext->topContext()); |
---|
1649 | if(!ownNamespaceScope.isEmpty()) |
---|
1650 | for(int a = 1; a <= ownNamespaceScope.count(); ++a) |
---|
1651 | ids += ownNamespaceScope.left(a); |
---|
1652 | |
---|
1653 | foreach(const QualifiedIdentifier &id, ids) { |
---|
1654 | QList<Declaration*> importedContextDecls = m_duContext->findDeclarations( id ); |
---|
1655 | foreach(Declaration* contextDecl, importedContextDecls) { |
---|
1656 | if(contextDecl->kind() != Declaration::Namespace || !contextDecl->internalContext()) |
---|
1657 | continue; |
---|
1658 | DUContext* context = contextDecl->internalContext(); |
---|
1659 | |
---|
1660 | if(context->range().contains(m_duContext->range()) && context->url() == m_duContext->url()) |
---|
1661 | continue; //If the context surrounds the current one, the declarations are visible through allDeclarations(..). |
---|
1662 | foreach(Declaration* decl, context->localDeclarations()) { |
---|
1663 | if(filterDeclaration(decl)) |
---|
1664 | decls << qMakePair(decl, 1200); |
---|
1665 | } |
---|
1666 | } |
---|
1667 | } |
---|
1668 | |
---|
1669 | QList<DeclarationDepthPair> oldDecls = decls; |
---|
1670 | decls.clear(); |
---|
1671 | |
---|
1672 | //Remove pure function-definitions before doing overload-resolution, so they don't hide their own declarations. |
---|
1673 | foreach( const DeclarationDepthPair& decl, oldDecls ) |
---|
1674 | if(!dynamic_cast<FunctionDefinition*>(decl.first) || !static_cast<FunctionDefinition*>(decl.first)->hasDeclaration()) { |
---|
1675 | if(decl.first->kind() == Declaration::Namespace) { |
---|
1676 | QualifiedIdentifier id = decl.first->qualifiedIdentifier(); |
---|
1677 | if(hadNamespaceDeclarations.contains(id)) |
---|
1678 | continue; |
---|
1679 | |
---|
1680 | hadNamespaceDeclarations.insert(id); |
---|
1681 | } |
---|
1682 | |
---|
1683 | if(filterDeclaration(decl.first, 0, true)) { |
---|
1684 | decls << decl; |
---|
1685 | } |
---|
1686 | } |
---|
1687 | |
---|
1688 | decls = Cpp::hideOverloadedDeclarations(decls, typeIsConst); |
---|
1689 | |
---|
1690 | foreach( const DeclarationDepthPair& decl, decls ) |
---|
1691 | items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(DeclarationPointer(decl.first), KDevelop::CodeCompletionContext::Ptr(this), decl.second ) ); |
---|
1692 | |
---|
1693 | ///Eventually show additional specificly known items for the matched argument-type, like for example enumerators for enum types |
---|
1694 | CodeCompletionContext* parent = parentContext(); |
---|
1695 | if(parent) { |
---|
1696 | if(parent->accessType() == FunctionCallAccess) { |
---|
1697 | foreach(const Cpp::OverloadResolutionFunction& function, parent->functions()) { |
---|
1698 | if(function.function.isValid() && function.function.isViable() && function.function.declaration()) { |
---|
1699 | //uint parameterNumber = parent->m_knownArgumentExpressions.size() + function.matchedArguments; |
---|
1700 | Declaration* functionDecl = function.function.declaration().data(); |
---|
1701 | if(functionDecl->type<FunctionType>()->arguments().count() > function.matchedArguments) { |
---|
1702 | items += specialItemsForArgumentType(functionDecl->type<FunctionType>()->arguments()[function.matchedArguments]); |
---|
1703 | } |
---|
1704 | } |
---|
1705 | } |
---|
1706 | } |
---|
1707 | else if (parent->accessType() == BinaryOpFunctionCallAccess) |
---|
1708 | { |
---|
1709 | items += specialItemsForArgumentType(parent->m_expressionResult.type.abstractType()); |
---|
1710 | } |
---|
1711 | } |
---|
1712 | |
---|
1713 | return items; |
---|
1714 | } |
---|
1715 | |
---|
1716 | void CodeCompletionContext::addOverridableItems() |
---|
1717 | { |
---|
1718 | if(m_duContext->type() != DUContext::Class) |
---|
1719 | return; |
---|
1720 | |
---|
1721 | //Show override helper items |
---|
1722 | QMap< QPair<IndexedType, IndexedString>, KDevelop::CompletionTreeItemPointer > overridable; |
---|
1723 | foreach(const DUContext::Import &import, m_duContext->importedParentContexts()) |
---|
1724 | { |
---|
1725 | DUContext* ctx = import.context(m_duContext->topContext()); |
---|
1726 | if(ctx) |
---|
1727 | getOverridable(m_duContext.data(), ctx, overridable, Ptr(this)); |
---|
1728 | } |
---|
1729 | |
---|
1730 | if(!overridable.isEmpty()) |
---|
1731 | eventuallyAddGroup(i18n("Virtual Override"), 0, overridable.values()); |
---|
1732 | } |
---|
1733 | |
---|
1734 | void CodeCompletionContext::addImplementationHelpers() |
---|
1735 | { |
---|
1736 | QList<CompletionTreeItemPointer> helpers = getImplementationHelpers(); |
---|
1737 | if(!helpers.isEmpty()) { |
---|
1738 | eventuallyAddGroup(i18n("Implement Function"), 0, helpers); |
---|
1739 | } |
---|
1740 | } |
---|
1741 | |
---|
1742 | void CodeCompletionContext::addCPPBuiltin() |
---|
1743 | { |
---|
1744 | ///Eventually add a "this" item |
---|
1745 | DUContext* functionContext = m_duContext.data(); |
---|
1746 | if(m_onlyShow != ShowSignals && m_onlyShow != ShowSlots && m_onlyShow != ShowTypes) { |
---|
1747 | while(functionContext && functionContext->type() == DUContext::Other && functionContext->parentContext() && functionContext->parentContext()->type() == DUContext::Other) |
---|
1748 | functionContext = functionContext->parentContext(); |
---|
1749 | } |
---|
1750 | |
---|
1751 | ClassFunctionDeclaration* classFun = dynamic_cast<ClassFunctionDeclaration*>(DUChainUtils::declarationForDefinition(functionContext->owner(), m_duContext->topContext())); |
---|
1752 | |
---|
1753 | if(classFun && !classFun->isStatic() && classFun->context()->owner() |
---|
1754 | && m_onlyShow != ShowSignals && m_onlyShow != ShowSlots && m_onlyShow != ShowTypes) |
---|
1755 | { |
---|
1756 | AbstractType::Ptr classType = classFun->context()->owner()->abstractType(); |
---|
1757 | if(classFun->abstractType()->modifiers() & AbstractType::ConstModifier) |
---|
1758 | classType->setModifiers((AbstractType::CommonModifiers)(classType->modifiers() | AbstractType::ConstModifier)); |
---|
1759 | PointerType::Ptr thisPointer(new PointerType()); |
---|
1760 | thisPointer->setModifiers(AbstractType::ConstModifier); |
---|
1761 | thisPointer->setBaseType(classType); |
---|
1762 | KSharedPtr<TypeConversionCompletionItem> item( new TypeConversionCompletionItem("this", thisPointer->indexed(), 0, KSharedPtr <Cpp::CodeCompletionContext >(this)) ); |
---|
1763 | item->setPrefix(thisPointer->toString()); |
---|
1764 | QList<CompletionTreeItemPointer> lst; |
---|
1765 | lst += CompletionTreeItemPointer(item.data()); |
---|
1766 | eventuallyAddGroup(i18n("C++ Builtin"), 800, lst); |
---|
1767 | } |
---|
1768 | eventuallyAddGroup(i18n("C++ Builtin"), 800, keywordCompletionItems()); |
---|
1769 | } |
---|
1770 | |
---|
1771 | bool CodeCompletionContext::shouldAddParentItems(bool fullCompletion) |
---|
1772 | { |
---|
1773 | if (!m_parentContext) |
---|
1774 | return false; |
---|
1775 | |
---|
1776 | if ( !fullCompletion && (!Cpp::useArgumentHintInAutomaticCompletion() || depth() != 0) ) |
---|
1777 | return false; |
---|
1778 | |
---|
1779 | if ( NO_MULTIPLE_BINARY_OPERATORS && m_accessType == BinaryOpFunctionCallAccess && |
---|
1780 | parentContext()->m_accessType == BinaryOpFunctionCallAccess ) |
---|
1781 | return false; |
---|
1782 | |
---|
1783 | return true; |
---|
1784 | } |
---|
1785 | |
---|
1786 | QList<CompletionTreeItemPointer> CodeCompletionContext::completionItems(bool& shouldAbort, bool fullCompletion) { |
---|
1787 | QList<CompletionTreeItemPointer> items; |
---|
1788 | if(!m_valid) |
---|
1789 | return items; |
---|
1790 | |
---|
1791 | switch(m_accessType) { |
---|
1792 | case MemberAccess: |
---|
1793 | case ArrowMemberAccess: |
---|
1794 | case StaticMemberChoose: |
---|
1795 | case MemberChoose: |
---|
1796 | items += memberAccessCompletionItems(shouldAbort); |
---|
1797 | break; |
---|
1798 | case ReturnAccess: |
---|
1799 | items += returnAccessCompletionItems(); |
---|
1800 | break; |
---|
1801 | case CaseAccess: |
---|
1802 | items += caseAccessCompletionItems(); |
---|
1803 | break; |
---|
1804 | case TemplateAccess: |
---|
1805 | items += templateAccessCompletionItems(); |
---|
1806 | break; |
---|
1807 | case FunctionCallAccess: |
---|
1808 | items += functionAccessCompletionItems(fullCompletion); |
---|
1809 | break; |
---|
1810 | case BinaryOpFunctionCallAccess: |
---|
1811 | items += binaryFunctionAccessCompletionItems(fullCompletion); |
---|
1812 | break; |
---|
1813 | case IncludeListAccess: |
---|
1814 | items += includeListAccessCompletionItems(shouldAbort); |
---|
1815 | break; |
---|
1816 | case SignalAccess: |
---|
1817 | case SlotAccess: |
---|
1818 | items += signalSlotAccessCompletionItems(); |
---|
1819 | //Since there is 2 connect() functions, the third argument may be a slot as well as a QObject*, so also |
---|
1820 | //give normal completion items |
---|
1821 | if(parentContext() && parentContext()->m_knownArgumentExpressions.size() != 2) |
---|
1822 | break; |
---|
1823 | default: |
---|
1824 | if(depth() == 0 && (m_onlyShow == ShowAll || m_onlyShow == ShowTypes)) |
---|
1825 | { |
---|
1826 | items += standardAccessCompletionItems(); |
---|
1827 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1828 | #ifndef TEST_COMPLETION |
---|
1829 | MissingIncludeCompletionModel::self().startWithExpression(m_duContext, QString(), m_followingText); |
---|
1830 | #endif |
---|
1831 | addCPPBuiltin(); |
---|
1832 | } |
---|
1833 | break; |
---|
1834 | } |
---|
1835 | |
---|
1836 | if(shouldAddParentItems(fullCompletion)) |
---|
1837 | items = parentContext()->completionItems( shouldAbort, fullCompletion ) + items; |
---|
1838 | |
---|
1839 | if(depth() == 0) |
---|
1840 | { |
---|
1841 | LOCKDUCHAIN; if (!m_duContext) return items; |
---|
1842 | //Eventually add missing include-completion in cases like SomeNamespace::NotIncludedClass| |
---|
1843 | if(m_accessType == StaticMemberChoose) { |
---|
1844 | #ifndef TEST_COMPLETION |
---|
1845 | MissingIncludeCompletionModel::self().startWithExpression(m_duContext, m_expression + "::", m_followingText); |
---|
1846 | #endif |
---|
1847 | } |
---|
1848 | |
---|
1849 | if (!parentContext()) |
---|
1850 | addOverridableItems(); |
---|
1851 | if (isImplementationHelperValid()) |
---|
1852 | addImplementationHelpers(); |
---|
1853 | } |
---|
1854 | |
---|
1855 | return items; |
---|
1856 | } |
---|
1857 | |
---|
1858 | QList<CompletionTreeItemPointer> CodeCompletionContext::getImplementationHelpers() { |
---|
1859 | QList<CompletionTreeItemPointer> ret; |
---|
1860 | TopDUContext* searchInContext = m_duContext->topContext(); |
---|
1861 | |
---|
1862 | if(searchInContext) |
---|
1863 | ret += getImplementationHelpersInternal(m_duContext->scopeIdentifier(true), searchInContext); |
---|
1864 | |
---|
1865 | if(!CppUtils::isHeader( searchInContext->url().toUrl() )) { |
---|
1866 | KUrl headerUrl = CppUtils::sourceOrHeaderCandidate( searchInContext->url().toUrl(), true ); |
---|
1867 | searchInContext = ICore::self()->languageController()->language("C++")->languageSupport()->standardContext(headerUrl); |
---|
1868 | if(searchInContext) |
---|
1869 | ret += getImplementationHelpersInternal(m_duContext->scopeIdentifier(true), searchInContext); |
---|
1870 | } |
---|
1871 | |
---|
1872 | return ret; |
---|
1873 | } |
---|
1874 | |
---|
1875 | QList<CompletionTreeItemPointer> CodeCompletionContext::getImplementationHelpersInternal(const QualifiedIdentifier& minimumScope, DUContext* context) |
---|
1876 | { |
---|
1877 | QList<CompletionTreeItemPointer> ret; |
---|
1878 | |
---|
1879 | foreach(Declaration* decl, context->localDeclarations()) { |
---|
1880 | if (decl->range().isEmpty() || decl->isDefinition() || FunctionDefinition::definition(decl)) { |
---|
1881 | continue; |
---|
1882 | } |
---|
1883 | if (!decl->qualifiedIdentifier().toString().startsWith(minimumScope.toString())) { |
---|
1884 | continue; |
---|
1885 | } |
---|
1886 | AbstractFunctionDeclaration* funDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl); |
---|
1887 | if (!funDecl) { |
---|
1888 | continue; |
---|
1889 | } |
---|
1890 | ClassFunctionDeclaration* classFun = dynamic_cast<ClassFunctionDeclaration*>(decl); |
---|
1891 | if (classFun && (classFun->isAbstract() || classFun->isSignal())) { |
---|
1892 | continue; |
---|
1893 | } |
---|
1894 | ret << KDevelop::CompletionTreeItemPointer( |
---|
1895 | new ImplementationHelperItem( ImplementationHelperItem::CreateDefinition, |
---|
1896 | DeclarationPointer(decl), |
---|
1897 | KSharedPtr<CodeCompletionContext>(this))); |
---|
1898 | } |
---|
1899 | |
---|
1900 | foreach(DUContext* child, context->childContexts()) { |
---|
1901 | if(child->type() == DUContext::Namespace |
---|
1902 | || child->type() == DUContext::Class |
---|
1903 | || child->type() == DUContext::Helper) |
---|
1904 | { |
---|
1905 | ret += getImplementationHelpersInternal(minimumScope, child); |
---|
1906 | } |
---|
1907 | } |
---|
1908 | |
---|
1909 | return ret; |
---|
1910 | } |
---|
1911 | |
---|
1912 | QualifiedIdentifier CodeCompletionContext::requiredPrefix(Declaration* decl) const { |
---|
1913 | QualifiedIdentifier worstCase = decl->context()->scopeIdentifier(true); |
---|
1914 | if(!m_duContext) |
---|
1915 | return worstCase; |
---|
1916 | QualifiedIdentifier currentPrefix; |
---|
1917 | |
---|
1918 | while(1) { |
---|
1919 | QList<Declaration*> found = m_duContext->findDeclarations( currentPrefix + decl->identifier() ); |
---|
1920 | if(found.contains(decl)) |
---|
1921 | return currentPrefix; |
---|
1922 | |
---|
1923 | if(currentPrefix.count() >= worstCase.count()) { |
---|
1924 | return worstCase; |
---|
1925 | }else { |
---|
1926 | currentPrefix.push(worstCase.at(currentPrefix.count())); |
---|
1927 | } |
---|
1928 | } |
---|
1929 | } |
---|
1930 | |
---|
1931 | QList< KSharedPtr< KDevelop::CompletionTreeItem > > CodeCompletionContext::specialItemsForArgumentType(TypePtr< KDevelop::AbstractType > type) { |
---|
1932 | QList< KSharedPtr< KDevelop::CompletionTreeItem > > items; |
---|
1933 | if(EnumerationType::Ptr enumeration = TypeUtils::realType(type, m_duContext->topContext()).cast<EnumerationType>()) { |
---|
1934 | Declaration* enumDecl = enumeration->declaration(m_duContext->topContext()); |
---|
1935 | if(enumDecl && enumDecl->internalContext()) { |
---|
1936 | |
---|
1937 | QualifiedIdentifier prefix = requiredPrefix(enumDecl); |
---|
1938 | |
---|
1939 | DUContext* enumInternal = enumDecl->internalContext(); |
---|
1940 | foreach(Declaration* enumerator, enumInternal->localDeclarations()) { |
---|
1941 | QualifiedIdentifier id = prefix + enumerator->identifier(); |
---|
1942 | items << CompletionTreeItemPointer(new NormalDeclarationCompletionItem( DeclarationPointer(enumerator), KDevelop::CodeCompletionContext::Ptr(this), 0 )); |
---|
1943 | static_cast<NormalDeclarationCompletionItem*>(items.back().data())->alternativeText = id.toString(); |
---|
1944 | static_cast<NormalDeclarationCompletionItem*>(items.back().data())->useAlternativeText = true; |
---|
1945 | } |
---|
1946 | } |
---|
1947 | } |
---|
1948 | return items; |
---|
1949 | } |
---|
1950 | |
---|
1951 | bool CodeCompletionContext::visibleFromWithin(KDevelop::Declaration* decl, DUContext* currentContext) { |
---|
1952 | if(!decl || !currentContext) |
---|
1953 | return false; |
---|
1954 | if(currentContext->imports(decl->context())) |
---|
1955 | return true; |
---|
1956 | |
---|
1957 | return visibleFromWithin(decl, currentContext->parentContext()); |
---|
1958 | } |
---|
1959 | |
---|
1960 | /** |
---|
1961 | * see @p type as function type and try to get it's return type as IntegralType data type. |
---|
1962 | */ |
---|
1963 | static inline int getIntegralReturnType(const AbstractType::Ptr& type) |
---|
1964 | { |
---|
1965 | if (!type) |
---|
1966 | return -1; |
---|
1967 | const FunctionType::Ptr funcType = type.cast<FunctionType>(); |
---|
1968 | if (!funcType || !funcType->returnType()) |
---|
1969 | return -1; |
---|
1970 | const IntegralType::Ptr intType = funcType->returnType().cast<IntegralType>(); |
---|
1971 | if (!intType) |
---|
1972 | return -1; |
---|
1973 | return intType->dataType(); |
---|
1974 | } |
---|
1975 | |
---|
1976 | bool CodeCompletionContext::filterDeclaration(Declaration* decl, DUContext* declarationContext, bool dynamic) { |
---|
1977 | if(!decl) |
---|
1978 | return true; |
---|
1979 | |
---|
1980 | if(dynamic_cast<TemplateParameterDeclaration*>(decl) && !visibleFromWithin(decl, m_duContext.data())) |
---|
1981 | return false; |
---|
1982 | |
---|
1983 | static IndexedIdentifier friendIdentifier(Identifier("friend")); |
---|
1984 | static IndexedIdentifier globalImport(globalImportIdentifier()); |
---|
1985 | |
---|
1986 | if(decl->indexedIdentifier().isEmpty()) //Filter out nameless declarations |
---|
1987 | return false; |
---|
1988 | |
---|
1989 | if(decl->indexedIdentifier() == friendIdentifier || decl->indexedIdentifier() == Cpp::unnamedNamespaceIdentifier() |
---|
1990 | || decl->indexedIdentifier() == globalImport) |
---|
1991 | return false; |
---|
1992 | |
---|
1993 | if(excludeReservedIdentifiers) |
---|
1994 | { |
---|
1995 | //Exclude identifiers starting with "__" or "_Uppercase" |
---|
1996 | IndexedString str = decl->indexedIdentifier().identifier().identifier(); |
---|
1997 | const char* cstr = str.c_str(); |
---|
1998 | if(str.length() > 2 && cstr[0] == '_' && (cstr[1] == '_' || QChar(cstr[1]).isUpper()) && decl->url() != m_duContext->url()) |
---|
1999 | return false; |
---|
2000 | } |
---|
2001 | |
---|
2002 | if(ClassDeclaration* cDecl = dynamic_cast<ClassDeclaration*>(decl)) { |
---|
2003 | ///TODO: indexedIdentifier().isEmpty() should be fixed for this case... |
---|
2004 | if (cDecl->classType() == ClassDeclarationData::Struct && cDecl->identifier().toString().isEmpty()) { |
---|
2005 | // filter anonymous structs |
---|
2006 | return false; |
---|
2007 | } |
---|
2008 | } |
---|
2009 | |
---|
2010 | if(m_onlyShow == ShowTypes && decl->kind() != Declaration::Type && decl->kind() != Declaration::Namespace |
---|
2011 | && decl->kind() != Declaration::NamespaceAlias ) |
---|
2012 | return false; |
---|
2013 | |
---|
2014 | if(m_onlyShow == ShowVariables && (decl->kind() != Declaration::Instance || decl->isFunctionDeclaration())) |
---|
2015 | return false; |
---|
2016 | |
---|
2017 | if(m_onlyShow == ShowImplementationHelpers) |
---|
2018 | return false; //Implementation helpers don't come here |
---|
2019 | |
---|
2020 | if(m_onlyShow == ShowSignals || m_onlyShow == ShowSlots) { |
---|
2021 | Cpp::QtFunctionDeclaration* qtFunction = dynamic_cast<Cpp::QtFunctionDeclaration*>(decl); |
---|
2022 | if(!qtFunction || (m_onlyShow == ShowSignals && !qtFunction->isSignal()) |
---|
2023 | || (m_onlyShow == ShowSlots && !qtFunction->isSlot())) |
---|
2024 | return false; |
---|
2025 | } |
---|
2026 | |
---|
2027 | if(dynamic && decl->context()->type() == DUContext::Class) { |
---|
2028 | ClassMemberDeclaration* classMember = dynamic_cast<ClassMemberDeclaration*>(decl); |
---|
2029 | if(classMember) |
---|
2030 | return filterDeclaration(classMember, declarationContext); |
---|
2031 | } |
---|
2032 | |
---|
2033 | // https://bugs.kde.org/show_bug.cgi?id=206376 |
---|
2034 | // hide void functions in expressions but don't hide signals / slots with void return type |
---|
2035 | if (m_onlyShow != ShowSignals && m_onlyShow != ShowSlots |
---|
2036 | && m_parentContext && decl->isFunctionDeclaration() |
---|
2037 | && getIntegralReturnType(decl->abstractType()) == IntegralType::TypeVoid) |
---|
2038 | { |
---|
2039 | const ExpressionEvaluationResult& result = |
---|
2040 | static_cast<CodeCompletionContext*>(m_parentContext.data())->m_expressionResult; |
---|
2041 | // for now only hide in non-lvalue expressions so we don't get problems in sig/slot connections e.g. |
---|
2042 | if (result.type.isValid() && !result.isLValue()) |
---|
2043 | return false; |
---|
2044 | } |
---|
2045 | |
---|
2046 | return true; |
---|
2047 | } |
---|
2048 | |
---|
2049 | bool CodeCompletionContext::filterDeclaration(ClassMemberDeclaration* decl, DUContext* declarationContext) { |
---|
2050 | if(m_doAccessFiltering && decl) { |
---|
2051 | if(!Cpp::isAccessible(m_localClass ? m_localClass.data() : m_duContext.data(), decl, m_duContext->topContext(), declarationContext)) |
---|
2052 | return false; |
---|
2053 | } |
---|
2054 | // filter properties from code completion, they mostly have to be accessed via their getter/setters |
---|
2055 | if (dynamic_cast<QPropertyDeclaration*>(decl)) { |
---|
2056 | return false; |
---|
2057 | } |
---|
2058 | return filterDeclaration((Declaration*)decl, declarationContext, false); |
---|
2059 | } |
---|
2060 | |
---|
2061 | void CodeCompletionContext::replaceCurrentAccess(QString old, QString _new) |
---|
2062 | { |
---|
2063 | //We must not change the document from within the background, so we use a queued connection to an object created in the foregroud |
---|
2064 | QMetaObject::invokeMethod(&accessReplacer, "exec", Qt::QueuedConnection, Q_ARG(KUrl, m_duContext->url().toUrl()), Q_ARG(QString, old), Q_ARG(QString, _new)); |
---|
2065 | } |
---|
2066 | |
---|
2067 | int CodeCompletionContext::matchPosition() const { |
---|
2068 | return m_knownArgumentExpressions.count(); |
---|
2069 | } |
---|
2070 | |
---|
2071 | void CodeCompletionContext::eventuallyAddGroup(QString name, int priority, QList< KSharedPtr< KDevelop::CompletionTreeItem > > items) { |
---|
2072 | if(items.isEmpty()) |
---|
2073 | return; |
---|
2074 | KDevelop::CompletionCustomGroupNode* node = new KDevelop::CompletionCustomGroupNode(name, priority); |
---|
2075 | node->appendChildren(items); |
---|
2076 | m_storedUngroupedItems << CompletionTreeElementPointer(node); |
---|
2077 | } |
---|
2078 | |
---|
2079 | QList< KSharedPtr< KDevelop::CompletionTreeItem > > CodeCompletionContext::keywordCompletionItems() { |
---|
2080 | QList<CompletionTreeItemPointer> ret; |
---|
2081 | #ifdef TEST_COMPLETION |
---|
2082 | return ret; |
---|
2083 | #endif |
---|
2084 | #define ADD_TYPED_TOKEN_S(X, type) ret << CompletionTreeItemPointer( new TypeConversionCompletionItem(X, type, 0, KSharedPtr<Cpp::CodeCompletionContext>(this)) ) |
---|
2085 | #define ADD_TYPED_TOKEN(X, type) ADD_TYPED_TOKEN_S(#X, type) |
---|
2086 | |
---|
2087 | #define ADD_TOKEN(X) ADD_TYPED_TOKEN(X, KDevelop::IndexedType()) |
---|
2088 | #define ADD_TOKEN_S(X) ADD_TYPED_TOKEN_S(X, KDevelop::IndexedType()) |
---|
2089 | |
---|
2090 | bool restrictedItems = (m_onlyShow == ShowSignals) || |
---|
2091 | (m_onlyShow == ShowSlots) || |
---|
2092 | (m_onlyShow == ShowTypes) || |
---|
2093 | (m_onlyShow == ShowImplementationHelpers); |
---|
2094 | |
---|
2095 | if(!restrictedItems || m_onlyShow == ShowTypes) { |
---|
2096 | ADD_TOKEN(bool); |
---|
2097 | ADD_TOKEN(char); |
---|
2098 | ADD_TOKEN(char16_t); |
---|
2099 | ADD_TOKEN(char32_t); |
---|
2100 | ADD_TOKEN(const); |
---|
2101 | ADD_TOKEN(double); |
---|
2102 | ADD_TOKEN(enum); |
---|
2103 | ADD_TOKEN(float); |
---|
2104 | ADD_TOKEN(int); |
---|
2105 | ADD_TOKEN(long); |
---|
2106 | ADD_TOKEN(mutable); |
---|
2107 | ADD_TOKEN(register); |
---|
2108 | ADD_TOKEN(short); |
---|
2109 | ADD_TOKEN(signed); |
---|
2110 | ADD_TOKEN(struct); |
---|
2111 | ADD_TOKEN(template); |
---|
2112 | ADD_TOKEN(typename); |
---|
2113 | ADD_TOKEN(union); |
---|
2114 | ADD_TOKEN(unsigned); |
---|
2115 | ADD_TOKEN(void); |
---|
2116 | ADD_TOKEN(volatile); |
---|
2117 | ADD_TOKEN(wchar_t); |
---|
2118 | } |
---|
2119 | |
---|
2120 | if(restrictedItems && (m_duContext->type() == DUContext::Other || m_duContext->type() == DUContext::Function)) |
---|
2121 | return ret; |
---|
2122 | |
---|
2123 | if(m_duContext->type() == DUContext::Class) { |
---|
2124 | ADD_TOKEN_S("Q_OBJECT"); |
---|
2125 | ADD_TOKEN(private); |
---|
2126 | ADD_TOKEN(protected); |
---|
2127 | ADD_TOKEN(public); |
---|
2128 | ADD_TOKEN_S("signals"); |
---|
2129 | ADD_TOKEN_S("slots"); |
---|
2130 | ADD_TOKEN(virtual); |
---|
2131 | ADD_TOKEN(friend); |
---|
2132 | ADD_TOKEN(explicit); |
---|
2133 | } |
---|
2134 | |
---|
2135 | if(m_duContext->type() == DUContext::Other) { |
---|
2136 | ADD_TOKEN(break); |
---|
2137 | ADD_TOKEN(case); |
---|
2138 | ADD_TOKEN(and); |
---|
2139 | ADD_TOKEN(and_eq); |
---|
2140 | ADD_TOKEN(asm); |
---|
2141 | ADD_TOKEN(bitand); |
---|
2142 | ADD_TOKEN(bitor); |
---|
2143 | ADD_TOKEN(catch); |
---|
2144 | ADD_TOKEN(const_cast); |
---|
2145 | ADD_TOKEN(default); |
---|
2146 | ADD_TOKEN(delete); |
---|
2147 | ADD_TOKEN(do); |
---|
2148 | ADD_TOKEN(dynamic_cast); |
---|
2149 | ADD_TOKEN(else); |
---|
2150 | ADD_TOKEN_S("emit"); |
---|
2151 | ADD_TOKEN(for); |
---|
2152 | ADD_TOKEN(goto); |
---|
2153 | ADD_TOKEN(if); |
---|
2154 | ADD_TOKEN(incr); |
---|
2155 | ADD_TOKEN(new); |
---|
2156 | ADD_TOKEN(not); |
---|
2157 | ADD_TOKEN(not_eq); |
---|
2158 | ADD_TOKEN(nullptr); |
---|
2159 | ADD_TOKEN(or); |
---|
2160 | ADD_TOKEN(or_eq); |
---|
2161 | ADD_TOKEN(reinterpret_cast); |
---|
2162 | ADD_TOKEN(return); |
---|
2163 | ADD_TOKEN(static_cast); |
---|
2164 | ADD_TOKEN(switch); |
---|
2165 | ADD_TOKEN(try); |
---|
2166 | ADD_TOKEN(typeid); |
---|
2167 | ADD_TOKEN(while); |
---|
2168 | ADD_TOKEN(xor); |
---|
2169 | ADD_TOKEN(xor_eq); |
---|
2170 | ADD_TOKEN(continue); |
---|
2171 | }else{ |
---|
2172 | ADD_TOKEN(inline); |
---|
2173 | } |
---|
2174 | |
---|
2175 | if(m_duContext->type() == DUContext::Global) { |
---|
2176 | ADD_TOKEN(export); |
---|
2177 | ADD_TOKEN(extern); |
---|
2178 | ADD_TOKEN(namespace); |
---|
2179 | } |
---|
2180 | |
---|
2181 | ADD_TOKEN(auto); |
---|
2182 | ADD_TOKEN(class); |
---|
2183 | ADD_TOKEN(operator); |
---|
2184 | ADD_TOKEN(sizeof); |
---|
2185 | ADD_TOKEN(static); |
---|
2186 | ADD_TOKEN(throw); |
---|
2187 | ADD_TOKEN(typedef); |
---|
2188 | ADD_TOKEN(using); |
---|
2189 | |
---|
2190 | ConstantIntegralType::Ptr trueType(new ConstantIntegralType(IntegralType::TypeBoolean)); |
---|
2191 | trueType->setValue<bool>(true); |
---|
2192 | |
---|
2193 | ADD_TYPED_TOKEN(true, trueType->indexed()); |
---|
2194 | |
---|
2195 | ConstantIntegralType::Ptr falseType(new ConstantIntegralType(IntegralType::TypeBoolean)); |
---|
2196 | falseType->setValue<bool>(false); |
---|
2197 | |
---|
2198 | ADD_TYPED_TOKEN(false, falseType->indexed()); |
---|
2199 | |
---|
2200 | return ret; |
---|
2201 | } |
---|
2202 | |
---|
2203 | QString CodeCompletionContext::followingText() const { |
---|
2204 | return m_followingText; |
---|
2205 | } |
---|
2206 | |
---|
2207 | void CodeCompletionContext::setFollowingText(QString str) { |
---|
2208 | m_followingText = str.trimmed(); |
---|
2209 | } |
---|
2210 | |
---|
2211 | |
---|
2212 | } |
---|