Commit 795ae72e authored by con's avatar con
Browse files

Quick fix for completing cases in enum based switch statements.

Reviewed-by: Roberto Raggi
parent 5751f4f1
......@@ -79,11 +79,20 @@ QList<LookupItem> TypeOfExpression::operator()(const QString &expression,
Document::Ptr expressionDoc = documentForExpression(code);
expressionDoc->check();
m_ast = extractExpressionAST(expressionDoc);
return this->operator ()(extractExpressionAST(expressionDoc),
expressionDoc,
scope);
}
QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression,
Document::Ptr document,
Scope *scope)
{
m_ast = expression;
m_scope = scope;
m_lookupContext = LookupContext(expressionDoc, m_thisDocument, m_snapshot);
m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot);
m_lookupContext.setBindings(m_bindings);
ResolveExpression resolve(m_lookupContext);
......
......@@ -82,6 +82,22 @@ public:
Scope *scope,
PreprocessMode mode = NoPreprocess);
/**
* Returns a list of possible fully specified types associated with the
* given expression AST from the given document.
*
* NOTE: The fully specified types only stay valid for as long as this
* expression evaluator instance still exists, and no new call to evaluate
* has been made!
*
* @param expression The expression to evaluate.
* @param document The document in which the expression lives.
* @param scope The scope enclosing the expression.
*/
QList<LookupItem> operator()(ExpressionAST *expression,
Document::Ptr document,
Scope *scope);
QString preprocess(const QString &expression) const;
/**
......
......@@ -34,6 +34,7 @@
#include <cplusplus/CppDocument.h>
#include <cplusplus/ResolveExpression.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <TranslationUnit.h>
#include <ASTVisitor.h>
......@@ -1217,6 +1218,135 @@ public:
};
/*
Adds missing case statements for "switch (enumVariable)"
*/
class CompleteSwitchCaseStatement: public CppQuickFixOperation
{
public:
CompleteSwitchCaseStatement(TextEditor::BaseTextEditor *editor)
: CppQuickFixOperation(editor)
{}
virtual QString description() const
{
return QApplication::translate("CppTools::QuickFix", "Complete Switch Statement");
}
virtual int match(const QList<AST *> &path)
{
if (path.isEmpty())
return -1; // nothing to do
// look for switch statement
for (int depth = path.size()-1; depth >= 0; --depth) {
AST *ast = path.at(depth);
SwitchStatementAST *switchStatement = ast->asSwitchStatement();
if (switchStatement) {
if (!isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
return -1;
compoundStatement = switchStatement->statement->asCompoundStatement();
if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
return -1;
// look if the condition's type is an enum
if (Enum *e = conditionEnum(switchStatement)) {
// check the possible enum values
values.clear();
Overview prettyPrint;
for (unsigned i = 0; i < e->memberCount(); ++i) {
if (Declaration *decl = e->memberAt(i)->asDeclaration()) {
values << prettyPrint(decl->name());
}
}
// Get the used values
CaseStatementCollector caseValues(document()->translationUnit());
QStringList usedValues = caseValues(switchStatement);
// save the values that would be added
foreach (const QString &usedValue, usedValues)
values.removeAll(usedValue);
if (values.isEmpty())
return -1;
return depth;
}
return -1;
}
}
return -1;
}
virtual void createChanges()
{
ChangeSet changes;
int start = endOf(compoundStatement->lbrace_token);
changes.insert(start, QLatin1String("\ncase ")
+ values.join(QLatin1String(":\nbreak;\ncase "))
+ QLatin1String(":\nbreak;"));
refactoringChanges()->changeFile(fileName(), changes);
refactoringChanges()->reindent(fileName(), range(compoundStatement));
}
protected:
Enum *conditionEnum(SwitchStatementAST *statement)
{
Block *block = statement->symbol;
Scope *scope = document()->scopeAt(block->line(), block->column());
TypeOfExpression typeOfExpression;
typeOfExpression.init(document(), snapshot());
const QList<LookupItem> results = typeOfExpression(statement->condition,
document(),
scope);
foreach (LookupItem result, results) {
FullySpecifiedType fst = result.type();
if (Enum *e = result.declaration()->type()->asEnumType())
return e;
if (NamedType *namedType = fst->asNamedType()) {
QList<Symbol *> candidates =
typeOfExpression.context().lookup(namedType->name(), scope);
foreach (Symbol *candidate, candidates) {
if (Enum *e = candidate->asEnum()) {
return e;
}
}
}
}
return 0;
}
class CaseStatementCollector : public ASTVisitor
{
public:
CaseStatementCollector(TranslationUnit *unit) : ASTVisitor(unit) {}
QStringList operator ()(AST *ast)
{
values.clear();
foundCaseStatementLevel = false;
accept(ast);
return values;
}
bool preVisit(AST *ast) {
if (CaseStatementAST *cs = ast->asCaseStatement()) {
foundCaseStatementLevel = true;
if (SimpleNameAST *sm = cs->expression->asSimpleName()) {
Overview prettyPrint;
values << prettyPrint(sm->name);
}
return true;
} else if (foundCaseStatementLevel) {
return false;
}
return true;
}
bool foundCaseStatementLevel;
QStringList values;
};
protected:
CompoundStatementAST *compoundStatement;
QStringList values;
};
} // end of anonymous namespace
......@@ -1415,6 +1545,7 @@ QList<TextEditor::QuickFixOperation::Ptr> CppQuickFixFactory::quickFixOperations
QSharedPointer<ConvertNumericToHex> convertNumericToHex(new ConvertNumericToHex(editor));
QSharedPointer<ConvertNumericToOctal> convertNumericToOctal(new ConvertNumericToOctal(editor));
QSharedPointer<ConvertNumericToDecimal> convertNumericToDecimal(new ConvertNumericToDecimal(editor));
QSharedPointer<CompleteSwitchCaseStatement> completeSwitchCaseStatement(new CompleteSwitchCaseStatement(editor));
quickFixOperations.append(rewriteLogicalAndOp);
quickFixOperations.append(splitIfStatementOp);
......@@ -1429,6 +1560,7 @@ QList<TextEditor::QuickFixOperation::Ptr> CppQuickFixFactory::quickFixOperations
quickFixOperations.append(convertNumericToHex);
quickFixOperations.append(convertNumericToOctal);
quickFixOperations.append(convertNumericToDecimal);
quickFixOperations.append(completeSwitchCaseStatement);
if (editor->mimeType() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
quickFixOperations.append(wrapCString);
......
Markdown is supported
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