Commit 1e7d8214 authored by Olivier de Gaalon's avatar Olivier de Gaalon
Browse files

Create a context for switch expression, add special completion for "case"

BUG: 184185
REVIEW: 101671
parent 089782fa
......@@ -65,6 +65,7 @@
#define LOCKDUCHAIN DUChainReadLocker lock(DUChain::lock())
#include <cpputils.h>
#include <interfaces/ilanguage.h>
#include <interfaces/foregroundlock.h>
///Created statically as this object must be a child of the main thread
CppUtils::ReplaceCurrentAccess accessReplacer;
......@@ -104,7 +105,7 @@ const QSet<QString> KEYWORD_ACCESS_STRINGS = QString("const_cast< static_cast< d
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();
//A parent context is created for these access strings
//TODO: delete, case and possibly also xxx_cast< should open a parent context and get specialized handling
const QSet<QString> PARENT_ACCESS_STRINGS = BINARY_OPERATORS + QString("< , ( : return").split(' ').toSet();
const QSet<QString> PARENT_ACCESS_STRINGS = BINARY_OPERATORS + QString("< , ( : return case").split(' ').toSet();
//TODO: support ".*" and "->*" as MEMBER_ACCESS_STRINGS
const QSet<QString> MEMBER_ACCESS_STRINGS = QString(". -> ::").split(' ').toSet();
const QSet<QString> ACCESS_STRINGS = KEYWORD_ACCESS_STRINGS + PARENT_ACCESS_STRINGS + MEMBER_ACCESS_STRINGS;
......@@ -123,6 +124,22 @@ using namespace KDevelop;
namespace Cpp {
IndexedType switchExpressionType(DUContextPointer caseContext)
{
ForegroundLock foregroundLock;
LOCKDUCHAIN;
if (!caseContext)
return IndexedType();
DUContext* switchContext = 0;
if (caseContext->importedParentContexts().size() == 1)
switchContext = caseContext->importedParentContexts().first().context(caseContext->topContext());
if (!switchContext)
return IndexedType();
QString switchExpression = switchContext->createRangeMoving()->text();
ExpressionParser expressionParser;
return expressionParser.evaluateType(switchExpression.toUtf8(), DUContextPointer(switchContext)).type;
}
///@todo move these together with those from expressionvisitor into an own file, or make them unnecessary
QList<Declaration*> declIdsToDeclPtrs( const QList<DeclarationId>& decls, uint count, TopDUContext* top ) {
......@@ -834,6 +851,9 @@ CodeCompletionContext::AccessType CodeCompletionContext::findAccessType( const Q
if ( accessStr == "return" )
return ReturnAccess;
if ( accessStr == "case" )
return CaseAccess;
if( BINARY_OPERATORS.contains( accessStr ) )
return BinaryOpFunctionCallAccess;
}
......@@ -1357,6 +1377,18 @@ QList<CompletionTreeItemPointer> CodeCompletionContext::completionItems(bool& sh
}
}
break;
case CaseAccess:
{
lock.unlock(); //TODO: reorganize such that this unlock-relock uglyness isn't needed
IndexedType switchExprType = switchExpressionType(m_duContext);
lock.lock();
if (!m_duContext)
return items;
if (switchExprType.abstractType())
items << CompletionTreeItemPointer( new TypeConversionCompletionItem( "case " + switchExprType.abstractType()->toString(), switchExprType, depth(), KSharedPtr <Cpp::CodeCompletionContext >(this) ) );
}
break;
case TemplateAccess:
{
AbstractType::Ptr type = m_expressionResult.type.abstractType();
......
......@@ -87,6 +87,7 @@ namespace Cpp {
BinaryOpFunctionCallAccess, /// "var1 {somebinaryoperator} "
TemplateAccess, /// "bla<."
ReturnAccess, /// "return " -- Takes into account return type
CaseAccess, /// "case " -- Takes into account switch expression type
};
/**
......
......@@ -1003,6 +1003,24 @@ void ContextBuilder::visitIfStatement(IfStatementAST* node)
}
}
void ContextBuilder::visitSwitchStatement(SwitchStatementAST* node)
{
DUContext* secondParentContext = openContext(node->condition, DUContext::Other);
visit(node->condition);
closeContext();
if (node->statement) {
const bool contextNeeded = createContextIfNeeded(node->statement, secondParentContext);
visit(node->statement);
if (contextNeeded)
closeContext();
}
}
void ContextBuilder::visitDoStatement(DoStatementAST *node)
{
if(!node->statement) {
......
......@@ -190,6 +190,7 @@ protected:
virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST*);
virtual void visitForStatement(ForStatementAST*);
virtual void visitIfStatement(IfStatementAST*);
virtual void visitSwitchStatement(SwitchStatementAST*);
virtual void visitDoStatement(DoStatementAST*);
virtual void visitTryBlockStatement(TryBlockStatementAST*);
virtual void visitCatchStatement(CatchStatementAST*);
......
......@@ -429,6 +429,20 @@ void TestCppCodeCompletion::testParentContexts()
CompletionItemTester returnContext(top->childContexts()[ctxt], "return ");
QCOMPARE(returnContext.names, QStringList() << "X" << "a" << "b" << "Templ" << "this");
QCOMPARE(returnContext.completionContext->parentContext()->accessType(), Cpp::CodeCompletionContext::ReturnAccess);
//See also testCaseContext
release(top);
}
void TestCppCodeCompletion::testCaseContext()
{
QByteArray method = "enum testEnum { foo, bar }; void test() { switch( testEnum ) { } }";
TopDUContext* top = parse(method, DumpNone);
int ctxt = 2;
int sctxt = 1;
DUChainWriteLocker lock(DUChain::lock());
CompletionItemTester caseContext(top->childContexts()[ctxt]->childContexts()[sctxt], "case ");
QCOMPARE(caseContext.names, QStringList() << "testEnum" << "test" << "foo" << "bar");
QCOMPARE(caseContext.completionContext->parentContext()->accessType(), Cpp::CodeCompletionContext::CaseAccess);
release(top);
}
......
......@@ -72,6 +72,7 @@ private slots:
void testInvalidContexts();
void testMemberAccess();
void testParentContexts();
void testCaseContext();
void testUnaryOperators();
void testBinaryOperators();
void testDeclarationIsInitialization();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment