1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "cppcompleteswitch.h"
36 #include <cplusplus/Overview.h>
37 #include <cplusplus/TypeOfExpression.h>
38 #include <cpptools/cpprefactoringchanges.h>
39 #include <utils/changeset.h>
42 #include <ASTVisitor.h>
43 #include <CoreTypes.h>
46 #include <QtGui/QApplication>
48 using namespace CPlusPlus;
49 using namespace CppEditor;
50 using namespace CppEditor::Internal;
51 using namespace CppTools;
52 using namespace Utils;
56 class CaseStatementCollector : public ASTVisitor
59 CaseStatementCollector(Document::Ptr document, const Snapshot &snapshot,
61 : ASTVisitor(document->translationUnit()),
65 typeOfExpression.init(document, snapshot);
68 QStringList operator ()(AST *ast)
71 foundCaseStatementLevel = false;
76 bool preVisit(AST *ast) {
77 if (CaseStatementAST *cs = ast->asCaseStatement()) {
78 foundCaseStatementLevel = true;
79 if (ExpressionAST *expression = cs->expression->asIdExpression()) {
80 QList<LookupItem> candidates = typeOfExpression(expression,
83 if (!candidates .isEmpty() && candidates.first().declaration()) {
84 Symbol *decl = candidates.first().declaration();
85 values << prettyPrint(LookupContext::fullyQualifiedName(decl));
89 } else if (foundCaseStatementLevel) {
96 bool foundCaseStatementLevel;
98 TypeOfExpression typeOfExpression;
99 Document::Ptr document;
103 class Operation: public CppQuickFixOperation
106 Operation(const CppQuickFixState &state, int priority, CompoundStatementAST *compoundStatement, const QStringList &values)
107 : CppQuickFixOperation(state, priority)
108 , compoundStatement(compoundStatement)
111 setDescription(QApplication::translate("CppTools::QuickFix",
112 "Complete Switch Statement"));
116 virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
119 int start = currentFile->endOf(compoundStatement->lbrace_token);
120 changes.insert(start, QLatin1String("\ncase ")
121 + values.join(QLatin1String(":\nbreak;\ncase "))
122 + QLatin1String(":\nbreak;"));
123 currentFile->change(changes);
124 currentFile->indent(currentFile->range(compoundStatement));
127 CompoundStatementAST *compoundStatement;
131 static Enum *findEnum(const QList<LookupItem> &results,
132 const LookupContext &ctxt)
134 foreach (const LookupItem &result, results) {
135 const FullySpecifiedType fst = result.type();
137 Type *type = result.declaration() ? result.declaration()->type().type()
142 if (Enum *e = type->asEnumType())
144 if (const NamedType *namedType = type->asNamedType()) {
145 const QList<LookupItem> candidates =
146 ctxt.lookup(namedType->name(), result.scope());
147 return findEnum(candidates, ctxt);
154 static Enum *conditionEnum(const CppQuickFixState &state,
155 SwitchStatementAST *statement)
157 Block *block = statement->symbol;
158 Scope *scope = state.document()->scopeAt(block->line(), block->column());
159 TypeOfExpression typeOfExpression;
160 typeOfExpression.init(state.document(), state.snapshot());
161 const QList<LookupItem> results = typeOfExpression(statement->condition,
165 return findEnum(results, typeOfExpression.context());
168 } // end of anonymous namespace
170 QList<CppQuickFixOperation::Ptr> CompleteSwitchCaseStatement::match(const CppQuickFixState &state)
172 const QList<AST *> &path = state.path();
175 return noResult(); // nothing to do
177 // look for switch statement
178 for (int depth = path.size() - 1; depth >= 0; --depth) {
179 AST *ast = path.at(depth);
180 SwitchStatementAST *switchStatement = ast->asSwitchStatement();
181 if (switchStatement) {
182 if (!state.isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
184 CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement();
185 if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
187 // look if the condition's type is an enum
188 if (Enum *e = conditionEnum(state, switchStatement)) {
189 // check the possible enum values
191 Overview prettyPrint;
192 for (unsigned i = 0; i < e->memberCount(); ++i) {
193 if (Declaration *decl = e->memberAt(i)->asDeclaration()) {
194 values << prettyPrint(LookupContext::fullyQualifiedName(decl));
197 // Get the used values
198 Block *block = switchStatement->symbol;
199 CaseStatementCollector caseValues(state.document(), state.snapshot(),
200 state.document()->scopeAt(block->line(), block->column()));
201 QStringList usedValues = caseValues(switchStatement);
202 // save the values that would be added
203 foreach (const QString &usedValue, usedValues)
204 values.removeAll(usedValue);
205 if (values.isEmpty())
208 return singleResult(new Operation(state, depth, compoundStatement, values));