summaryrefslogtreecommitdiff
path: root/src/plugins/cpptools/cpppointerdeclarationformatter.cpp
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@digia.com>2013-02-07 09:02:56 +0100
committerNikolai Kosjar <nikolai.kosjar@digia.com>2013-02-12 11:49:07 +0100
commitaafbf2eaf041c9afd518db6dddc7ea702b05c599 (patch)
tree7d715a5af2a3ee0b430f2c4eb71da19d0984187d /src/plugins/cpptools/cpppointerdeclarationformatter.cpp
parentbd7dfeee921474975268abcea62fa7c90bd31953 (diff)
downloadqt-creator-aafbf2eaf041c9afd518db6dddc7ea702b05c599.tar.gz
C++: Make pointer declaration formatter more robust
- Abort on expanded tokens - Abort on simple declarations starting with "class"/"struct"/"enum" - Abort if rewritten declaration does not contain '*'/'&' Change-Id: Ifddb6f20d6bc5c0afc3fcd1d742615198515a04c Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
Diffstat (limited to 'src/plugins/cpptools/cpppointerdeclarationformatter.cpp')
-rw-r--r--src/plugins/cpptools/cpppointerdeclarationformatter.cpp102
1 files changed, 82 insertions, 20 deletions
diff --git a/src/plugins/cpptools/cpppointerdeclarationformatter.cpp b/src/plugins/cpptools/cpppointerdeclarationformatter.cpp
index ba0fa4c60f..a40316f290 100644
--- a/src/plugins/cpptools/cpppointerdeclarationformatter.cpp
+++ b/src/plugins/cpptools/cpppointerdeclarationformatter.cpp
@@ -32,12 +32,24 @@
#include <AST.h>
+#include <QtGlobal>
#include <QTextCursor>
#define DEBUG_OUTPUT 0
-#define CHECK_RV(cond, err, r) if (!(cond)) { if (DEBUG_OUTPUT) qDebug() << (err); return r; }
-#define CHECK_R(cond, err) if (!(cond)) { if (DEBUG_OUTPUT) qDebug() << (err); return; }
-#define CHECK_C(cond, err) if (!(cond)) { if (DEBUG_OUTPUT) qDebug() << (err); continue; }
+
+#if DEBUG_OUTPUT
+# include <typeinfo>
+# ifdef __GNUC__
+# include <cxxabi.h>
+# endif
+#endif
+
+#define CHECK_RV(cond, err, r) \
+ if (!(cond)) { if (DEBUG_OUTPUT) qDebug() << "Discarded:" << (err); return r; }
+#define CHECK_R(cond, err) \
+ if (!(cond)) { if (DEBUG_OUTPUT) qDebug() << "Discarded:" << (err); return; }
+#define CHECK_C(cond, err) \
+ if (!(cond)) { if (DEBUG_OUTPUT) qDebug() << "Discarded:" << (err); continue; }
using namespace CppTools;
@@ -122,6 +134,11 @@ PointerDeclarationFormatter::PointerDeclarationFormatter(
bool PointerDeclarationFormatter::visit(SimpleDeclarationAST *ast)
{
CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
+
+ const unsigned tokenKind = tokenAt(ast->firstToken()).kind();
+ const bool astIsOk = tokenKind != T_CLASS && tokenKind != T_STRUCT && tokenKind != T_ENUM;
+ CHECK_RV(astIsOk, "Nothing to do for class/struct/enum", true);
DeclaratorListAST *declaratorList = ast->declarator_list;
CHECK_RV(declaratorList, "No declarator list", true);
@@ -151,7 +168,7 @@ bool PointerDeclarationFormatter::visit(SimpleDeclarationAST *ast)
// Specify activation range
int lastActivationToken = 0;
- Range range;
+ TokenRange range;
// (2) Handle function declaration's return type
if (symbol->type()->asFunctionType()) {
PostfixDeclaratorListAST *pfDeclaratorList = declarator->postfix_declarator_list;
@@ -179,7 +196,7 @@ bool PointerDeclarationFormatter::visit(SimpleDeclarationAST *ast)
firstActivationToken = declarator->firstToken();
}
- range.start = m_cppRefactoringFile->startOf(firstActivationToken);
+ range.start = firstActivationToken;
// (1) Handle 'normal' declarations.
} else {
@@ -191,15 +208,16 @@ bool PointerDeclarationFormatter::visit(SimpleDeclarationAST *ast)
declarator->firstToken(),
&foundBegin);
CHECK_RV(foundBegin, "Declaration without attributes not supported", true);
- range.start = m_cppRefactoringFile->startOf(firstActivationToken);
+ range.start = firstActivationToken;
} else {
- range.start = m_cppRefactoringFile->startOf(declarator);
+ range.start = declarator->firstToken();
}
lastActivationToken = declarator->equal_token
? declarator->equal_token - 1
: declarator->lastToken() - 1;
}
- range.end = m_cppRefactoringFile->endOf(lastActivationToken);
+
+ range.end = lastActivationToken;
checkAndRewrite(symbol, range, charactersToRemove);
}
@@ -209,6 +227,9 @@ bool PointerDeclarationFormatter::visit(SimpleDeclarationAST *ast)
/*! Handle return types of function definitions */
bool PointerDeclarationFormatter::visit(FunctionDefinitionAST *ast)
{
+ CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
+
DeclaratorAST *declarator = ast->declarator;
CHECK_RV(declarator, "No declarator", true);
CHECK_RV(declarator->ptr_operator_list, "No Pointer or references", true);
@@ -230,8 +251,7 @@ bool PointerDeclarationFormatter::visit(FunctionDefinitionAST *ast)
lastActivationToken,
&foundBegin);
CHECK_RV(foundBegin, "Declaration without attributes not supported", true);
- Range range(m_cppRefactoringFile->startOf(firstActivationToken),
- m_cppRefactoringFile->endOf(lastActivationToken));
+ TokenRange range(firstActivationToken, lastActivationToken);
checkAndRewrite(symbol, range);
return true;
@@ -240,6 +260,9 @@ bool PointerDeclarationFormatter::visit(FunctionDefinitionAST *ast)
/*! Handle parameters in function declarations and definitions */
bool PointerDeclarationFormatter::visit(ParameterDeclarationAST *ast)
{
+ CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
+
DeclaratorAST *declarator = ast->declarator;
CHECK_RV(declarator, "No declarator", true);
CHECK_RV(declarator->ptr_operator_list, "No Pointer or references", true);
@@ -249,8 +272,7 @@ bool PointerDeclarationFormatter::visit(ParameterDeclarationAST *ast)
const int lastActivationToken = ast->equal_token
? ast->equal_token - 1
: ast->lastToken() - 1;
- Range range(m_cppRefactoringFile->startOf(ast),
- m_cppRefactoringFile->endOf(lastActivationToken));
+ TokenRange range(ast->firstToken(), lastActivationToken);
checkAndRewrite(symbol, range);
return true;
@@ -259,6 +281,9 @@ bool PointerDeclarationFormatter::visit(ParameterDeclarationAST *ast)
/*! Handle declaration in foreach statement */
bool PointerDeclarationFormatter::visit(ForeachStatementAST *ast)
{
+ CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
+
DeclaratorAST *declarator = ast->declarator;
CHECK_RV(declarator, "No declarator", true);
CHECK_RV(declarator->ptr_operator_list, "No Pointer or references", true);
@@ -272,8 +297,7 @@ bool PointerDeclarationFormatter::visit(ForeachStatementAST *ast)
const int lastActivationToken = declarator->equal_token
? declarator->equal_token - 1
: declarator->lastToken() - 1;
- Range range(m_cppRefactoringFile->startOf(firstSpecifier),
- m_cppRefactoringFile->endOf(lastActivationToken));
+ TokenRange range(firstSpecifier->firstToken(), lastActivationToken);
checkAndRewrite(symbol, range);
return true;
@@ -281,18 +305,24 @@ bool PointerDeclarationFormatter::visit(ForeachStatementAST *ast)
bool PointerDeclarationFormatter::visit(IfStatementAST *ast)
{
+ CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
processIfWhileForStatement(ast->condition, ast->symbol);
return true;
}
bool PointerDeclarationFormatter::visit(WhileStatementAST *ast)
{
+ CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
processIfWhileForStatement(ast->condition, ast->symbol);
return true;
}
bool PointerDeclarationFormatter::visit(ForStatementAST *ast)
{
+ CHECK_RV(ast, "Invalid AST", true);
+ printCandidate(ast);
processIfWhileForStatement(ast->condition, ast->symbol);
return true;
}
@@ -330,8 +360,7 @@ void PointerDeclarationFormatter::processIfWhileForStatement(ExpressionAST *expr
}
// Specify activation range
- Range range(m_cppRefactoringFile->startOf(condition),
- m_cppRefactoringFile->endOf(declarator->equal_token - 1));
+ TokenRange range(condition->firstToken(), declarator->equal_token - 1);
checkAndRewrite(symbol, range);
}
@@ -343,13 +372,23 @@ void PointerDeclarationFormatter::processIfWhileForStatement(ExpressionAST *expr
\param symbol the symbol to be rewritten
\param range the substitution range in the file
*/
-void PointerDeclarationFormatter::checkAndRewrite(Symbol *symbol, Range range,
+void PointerDeclarationFormatter::checkAndRewrite(Symbol *symbol, TokenRange tokenRange,
unsigned charactersToRemove)
{
- CHECK_R(range.start >= 0 && range.end > 0, "Range invalid");
- CHECK_R(range.start < range.end, "Range invalid");
+ CHECK_R(tokenRange.end > 0, "TokenRange invalid1");
+ CHECK_R(tokenRange.start < tokenRange.end, "TokenRange invalid2");
CHECK_R(symbol, "No symbol");
+ // Check for expanded tokens
+ for (unsigned token = tokenRange.start; token <= tokenRange.end; ++token)
+ CHECK_R(! tokenAt(token).expanded(), "Token is expanded");
+
+ Range range(m_cppRefactoringFile->startOf(tokenRange.start),
+ m_cppRefactoringFile->endOf(tokenRange.end));
+
+ CHECK_R(range.start >= 0 && range.end > 0, "ChangeRange invalid1");
+ CHECK_R(range.start < range.end, "ChangeRange invalid2");
+
// Check range with respect to cursor position / selection
if (m_cursorHandling == RespectCursor) {
const QTextCursor cursor = m_cppRefactoringFile->cursor();
@@ -374,10 +413,14 @@ void PointerDeclarationFormatter::checkAndRewrite(Symbol *symbol, Range range,
// Does the rewritten declaration (part) differs from the original source (part)?
QString rewrittenDeclaration = rewriteDeclaration(type, symbol->name());
rewrittenDeclaration.remove(0, charactersToRemove);
+
CHECK_R(originalDeclaration != rewrittenDeclaration, "Rewritten is same as original");
+ CHECK_R(rewrittenDeclaration.contains(QLatin1Char('&'))
+ || rewrittenDeclaration.contains(QLatin1Char('*')),
+ "No pointer or references in rewritten declaration");
if (DEBUG_OUTPUT) {
- qDebug("Rewritten: \"%s\" --> \"%s\"", originalDeclaration.toLatin1().constData(),
+ qDebug("==> Rewritten: \"%s\" --> \"%s\"", originalDeclaration.toLatin1().constData(),
rewrittenDeclaration.toLatin1().constData());
}
@@ -415,3 +458,22 @@ QString PointerDeclarationFormatter::rewriteDeclaration(FullySpecifiedType type,
return m_overview.prettyType(type, QLatin1String(identifier));
}
+
+void PointerDeclarationFormatter::printCandidate(AST *ast)
+{
+#if DEBUG_OUTPUT
+ QString tokens;
+ for (unsigned token = ast->firstToken(); token < ast->lastToken(); token++)
+ tokens += QString::fromLatin1(tokenAt(token).spell()) + QLatin1Char(' ');
+
+# ifdef __GNUC__
+ QByteArray name = abi::__cxa_demangle(typeid(*ast).name(), 0, 0, 0) + 11;
+ name.truncate(name.length() - 3);
+# else
+ QByteArray name = typeid(*ast).name();
+# endif
+ qDebug("--> Candidate: %s: %s", name.constData(), qPrintable(tokens));
+#else
+ Q_UNUSED(ast)
+#endif // DEBUG_OUTPUT
+}