forked from qt-creator/qt-creator
C++: Core changes in preprocessing
Summary of most relevant items: - Preprocessor output format change. No more gen true/false. Instead a more intuitive and natural expansion (like from a real compiler) is performed directly corresponding to the macro invocation. Notice that information about the generated tokens is not lost, because it's now embedded in the expansion section header (in terms of lines and columns as explained in the code). In addition the location on where the macro expansion happens is also documented for future use. - Fix line control directives and associated token line numbers. This was not detected in tests cases because some of them were actually wrong: Within expansions the line information was being considered as originally computed in the macro definition, while the desired and expected for Creator's reporting mechanism (just like regular compilers) is the line from the expanded version of the tokens. - Do not allow for eager expansion. This was previously being done inside define directives. However, it's not allowed and might lead to incorrect results, since the argument substitution should only happen upon the macro invocation (and following nested ones). At least GCC and clang are consistent with that. See test case tst_Preprocessor:dont_eagerly_expand for a detailed explanation. - Revive the 'expanded' token flag. This is used to mark every token that originates from a macro expansion. Notice, however, that expanded tokens are not necessarily generated tokens (although every generated token is a expanded token). Expanded tokens that are not generated are those which are still considered by our code model features, since they are visible on the editor. The translation unit is smart enough to calculate line/column position for such tokens based on the information from the expansion section header. - How expansions are tracked has also changed. Now, we simply add two surrounding marker tokens to each "top-level" expansion sequence. There is an enumeration that control expansion states. Also, no "previous" token is kept around. - Preprocessor client methods suffered a change in signature so they now receive the line number of the action in question as a paramater. Previously such line could be retrieved by the client implementation by accessing the environment line. However, this is not reliable because we try to avoid synchronization of the output/environment lines in order to avoid unnecessary output, while expanding macros or handling preprocessor directives. - Although macros are not expanded during define directives (as mentioned above) the preprocessor client is now "notified" when it sees a macro. This is to allow usage tracking. - Other small stuff. This is all in one patch because the fixes are a consequence of the change in preprocessing control. Change-Id: I8f4c6e6366f37756ec65d0a93b79f72a3ac4ed50 Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
16
src/libs/3rdparty/cplusplus/Token.h
vendored
16
src/libs/3rdparty/cplusplus/Token.h
vendored
@@ -321,13 +321,29 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
struct Flags {
|
struct Flags {
|
||||||
|
// The token kind.
|
||||||
unsigned kind : 8;
|
unsigned kind : 8;
|
||||||
|
// The token starts a new line.
|
||||||
unsigned newline : 1;
|
unsigned newline : 1;
|
||||||
|
// The token is preceeded by whitespace(s).
|
||||||
unsigned whitespace : 1;
|
unsigned whitespace : 1;
|
||||||
|
// The token is joined with the previous one.
|
||||||
unsigned joined : 1;
|
unsigned joined : 1;
|
||||||
|
// The token originates from a macro expansion.
|
||||||
unsigned expanded : 1;
|
unsigned expanded : 1;
|
||||||
|
// The token originates from a macro expansion and does not correspond to an
|
||||||
|
// argument that went through substitution. Notice the example:
|
||||||
|
//
|
||||||
|
// #define FOO(a, b) a + b;
|
||||||
|
// FOO(1, 2)
|
||||||
|
//
|
||||||
|
// After preprocessing we would expect the following tokens: 1 + 2;
|
||||||
|
// Tokens '1', '+', '2', and ';' are all expanded. However only tokens '+' and ';'
|
||||||
|
// are generated.
|
||||||
unsigned generated : 1;
|
unsigned generated : 1;
|
||||||
|
// Unused...
|
||||||
unsigned pad : 3;
|
unsigned pad : 3;
|
||||||
|
// The token lenght.
|
||||||
unsigned length : 16;
|
unsigned length : 16;
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
|
134
src/libs/3rdparty/cplusplus/TranslationUnit.cpp
vendored
134
src/libs/3rdparty/cplusplus/TranslationUnit.cpp
vendored
@@ -27,8 +27,10 @@
|
|||||||
#include "Literals.h"
|
#include "Literals.h"
|
||||||
#include "DiagnosticClient.h"
|
#include "DiagnosticClient.h"
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define va_copy(dst, src) ((dst) = (src))
|
# define va_copy(dst, src) ((dst) = (src))
|
||||||
@@ -176,27 +178,84 @@ void TranslationUnit::tokenize()
|
|||||||
pushPreprocessorLine(0, 1, fileId());
|
pushPreprocessorLine(0, 1, fileId());
|
||||||
|
|
||||||
const Identifier *lineId = control()->identifier("line");
|
const Identifier *lineId = control()->identifier("line");
|
||||||
const Identifier *genId = control()->identifier("gen");
|
const Identifier *expansionId = control()->identifier("expansion");
|
||||||
|
const Identifier *beginId = control()->identifier("begin");
|
||||||
|
const Identifier *endId = control()->identifier("end");
|
||||||
|
|
||||||
|
// We need to track information about the expanded tokens. A vector with an addition
|
||||||
|
// explicit index control is used instead of queue mainly for performance reasons.
|
||||||
|
std::vector<std::pair<unsigned, unsigned> > lineColumn;
|
||||||
|
unsigned lineColumnIdx = 0;
|
||||||
|
|
||||||
bool generated = false;
|
|
||||||
Token tk;
|
Token tk;
|
||||||
do {
|
do {
|
||||||
lex(&tk);
|
lex(&tk);
|
||||||
|
|
||||||
_Lrecognize:
|
_Lrecognize:
|
||||||
if (tk.is(T_POUND) && tk.newline()) {
|
if (tk.is(T_POUND) && tk.newline()) {
|
||||||
unsigned offset = tk.offset;
|
unsigned offset = tk.offset;
|
||||||
lex(&tk);
|
lex(&tk);
|
||||||
|
|
||||||
if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == genId) {
|
if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == expansionId) {
|
||||||
// it's a gen directive.
|
// It's an expansion mark.
|
||||||
lex(&tk);
|
lex(&tk);
|
||||||
|
|
||||||
if (! tk.f.newline && tk.is(T_TRUE)) {
|
if (!tk.f.newline && tk.is(T_IDENTIFIER)) {
|
||||||
lex(&tk);
|
if (tk.identifier == beginId) {
|
||||||
generated = true;
|
// Start of a macro expansion section.
|
||||||
} else {
|
lex(&tk);
|
||||||
generated = false;
|
|
||||||
|
// Gather where the expansion happens and its length.
|
||||||
|
unsigned macroOffset = static_cast<unsigned>(strtoul(tk.spell(), 0, 0));
|
||||||
|
lex(&tk);
|
||||||
|
lex(&tk); // Skip the separating comma
|
||||||
|
unsigned macroLength = static_cast<unsigned>(strtoul(tk.spell(), 0, 0));
|
||||||
|
lex(&tk);
|
||||||
|
|
||||||
|
// NOTE: We are currently not using the macro offset and length. They
|
||||||
|
// are kept here for now because of future use.
|
||||||
|
Q_UNUSED(macroOffset)
|
||||||
|
Q_UNUSED(macroLength)
|
||||||
|
|
||||||
|
// Now we need to gather the real line and columns from the upcoming
|
||||||
|
// tokens. But notice this is only relevant for tokens which are expanded
|
||||||
|
// but not generated.
|
||||||
|
while (tk.isNot(T_EOF_SYMBOL) && !tk.f.newline) {
|
||||||
|
// When we get a ~ it means there's a number of generated tokens
|
||||||
|
// following. Otherwise, we have actual data.
|
||||||
|
if (tk.is(T_TILDE)) {
|
||||||
|
lex(&tk);
|
||||||
|
|
||||||
|
// Get the total number of generated tokens and specifiy "null"
|
||||||
|
// information for them.
|
||||||
|
unsigned totalGenerated =
|
||||||
|
static_cast<unsigned>(strtoul(tk.spell(), 0, 0));
|
||||||
|
const std::size_t previousSize = lineColumn.size();
|
||||||
|
lineColumn.resize(previousSize + totalGenerated);
|
||||||
|
std::fill(lineColumn.begin() + previousSize,
|
||||||
|
lineColumn.end(),
|
||||||
|
std::make_pair(0, 0));
|
||||||
|
|
||||||
|
lex(&tk);
|
||||||
|
} else if (tk.is(T_NUMERIC_LITERAL)) {
|
||||||
|
unsigned line = static_cast<unsigned>(strtoul(tk.spell(), 0, 0));
|
||||||
|
lex(&tk);
|
||||||
|
lex(&tk); // Skip the separating colon
|
||||||
|
unsigned column = static_cast<unsigned>(strtoul(tk.spell(), 0, 0));
|
||||||
|
|
||||||
|
// Store line and column for this non-generated token.
|
||||||
|
lineColumn.push_back(std::make_pair(line, column));
|
||||||
|
|
||||||
|
lex(&tk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tk.identifier == endId) {
|
||||||
|
// End of a macro expansion.
|
||||||
|
lineColumn.clear();
|
||||||
|
lineColumnIdx = 0;
|
||||||
|
|
||||||
|
lex(&tk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
|
if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
|
||||||
@@ -211,9 +270,9 @@ void TranslationUnit::tokenize()
|
|||||||
lex(&tk);
|
lex(&tk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
while (tk.isNot(T_EOF_SYMBOL) && ! tk.f.newline)
|
||||||
|
lex(&tk);
|
||||||
}
|
}
|
||||||
while (tk.isNot(T_EOF_SYMBOL) && ! tk.f.newline)
|
|
||||||
lex(&tk);
|
|
||||||
goto _Lrecognize;
|
goto _Lrecognize;
|
||||||
} else if (tk.f.kind == T_LBRACE) {
|
} else if (tk.f.kind == T_LBRACE) {
|
||||||
braces.push(_tokens->size());
|
braces.push(_tokens->size());
|
||||||
@@ -225,7 +284,24 @@ void TranslationUnit::tokenize()
|
|||||||
_comments->push_back(tk);
|
_comments->push_back(tk);
|
||||||
continue; // comments are not in the regular token stream
|
continue; // comments are not in the regular token stream
|
||||||
}
|
}
|
||||||
tk.f.generated = generated;
|
|
||||||
|
bool currentExpanded = false;
|
||||||
|
bool currentGenerated = false;
|
||||||
|
|
||||||
|
if (!lineColumn.empty() && lineColumnIdx < lineColumn.size()) {
|
||||||
|
currentExpanded = true;
|
||||||
|
const std::pair<unsigned, unsigned> &p = lineColumn[lineColumnIdx];
|
||||||
|
if (p.first)
|
||||||
|
_expandedLineColumn.insert(std::make_pair(tk.offset, p));
|
||||||
|
else
|
||||||
|
currentGenerated = true;
|
||||||
|
|
||||||
|
++lineColumnIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
tk.f.expanded = currentExpanded;
|
||||||
|
tk.f.generated = currentGenerated;
|
||||||
|
|
||||||
_tokens->push_back(tk);
|
_tokens->push_back(tk);
|
||||||
} while (tk.f.kind);
|
} while (tk.f.kind);
|
||||||
|
|
||||||
@@ -355,12 +431,32 @@ void TranslationUnit::getPosition(unsigned tokenOffset,
|
|||||||
unsigned *column,
|
unsigned *column,
|
||||||
const StringLiteral **fileName) const
|
const StringLiteral **fileName) const
|
||||||
{
|
{
|
||||||
unsigned lineNumber = findLineNumber(tokenOffset);
|
unsigned lineNumber = 0;
|
||||||
unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber);
|
unsigned columnNumber = 0;
|
||||||
const PPLine ppLine = findPreprocessorLine(tokenOffset);
|
const StringLiteral *file = 0;
|
||||||
|
|
||||||
lineNumber -= findLineNumber(ppLine.offset) + 1;
|
// If this token is expanded we already have the information directly from the expansion
|
||||||
lineNumber += ppLine.line;
|
// section header. Otherwise, we need to calculate it.
|
||||||
|
std::map<unsigned, std::pair<unsigned, unsigned> >::const_iterator it =
|
||||||
|
_expandedLineColumn.find(tokenOffset);
|
||||||
|
if (it != _expandedLineColumn.end()) {
|
||||||
|
lineNumber = it->second.first;
|
||||||
|
columnNumber = it->second.second + 1;
|
||||||
|
file = _fileId;
|
||||||
|
} else {
|
||||||
|
// Identify line within the entire translation unit.
|
||||||
|
lineNumber = findLineNumber(tokenOffset);
|
||||||
|
|
||||||
|
// Identify column.
|
||||||
|
columnNumber = findColumnNumber(tokenOffset, lineNumber);
|
||||||
|
|
||||||
|
// Adjust the line in regards to the preprocessing markers.
|
||||||
|
const PPLine ppLine = findPreprocessorLine(tokenOffset);
|
||||||
|
lineNumber -= findLineNumber(ppLine.offset) + 1;
|
||||||
|
lineNumber += ppLine.line;
|
||||||
|
|
||||||
|
file = ppLine.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
if (line)
|
if (line)
|
||||||
*line = lineNumber;
|
*line = lineNumber;
|
||||||
@@ -369,7 +465,7 @@ void TranslationUnit::getPosition(unsigned tokenOffset,
|
|||||||
*column = columnNumber;
|
*column = columnNumber;
|
||||||
|
|
||||||
if (fileName)
|
if (fileName)
|
||||||
*fileName = ppLine.fileName;
|
*fileName = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TranslationUnit::blockErrors(bool block)
|
bool TranslationUnit::blockErrors(bool block)
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
#include "DiagnosticClient.h"
|
#include "DiagnosticClient.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
@@ -170,6 +170,7 @@ private:
|
|||||||
std::vector<Token> *_comments;
|
std::vector<Token> *_comments;
|
||||||
std::vector<unsigned> _lineOffsets;
|
std::vector<unsigned> _lineOffsets;
|
||||||
std::vector<PPLine> _ppLines;
|
std::vector<PPLine> _ppLines;
|
||||||
|
std::map<unsigned, std::pair<unsigned, unsigned> > _expandedLineColumn; // TODO: Replace this for a hash
|
||||||
MemoryPool *_pool;
|
MemoryPool *_pool;
|
||||||
AST *_ast;
|
AST *_ast;
|
||||||
TranslationUnit *_previousTranslationUnit;
|
TranslationUnit *_previousTranslationUnit;
|
||||||
|
@@ -60,7 +60,7 @@ QByteArray FastPreprocessor::run(QString fileName, const QString &source)
|
|||||||
return preprocessed;
|
return preprocessed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastPreprocessor::sourceNeeded(QString &fileName, IncludeType, unsigned)
|
void FastPreprocessor::sourceNeeded(unsigned, QString &fileName, IncludeType)
|
||||||
{ mergeEnvironment(fileName); }
|
{ mergeEnvironment(fileName); }
|
||||||
|
|
||||||
void FastPreprocessor::mergeEnvironment(const QString &fileName)
|
void FastPreprocessor::mergeEnvironment(const QString &fileName)
|
||||||
|
@@ -59,18 +59,19 @@ public:
|
|||||||
QByteArray run(QString fileName, const QString &source);
|
QByteArray run(QString fileName, const QString &source);
|
||||||
|
|
||||||
// CPlusPlus::Client
|
// CPlusPlus::Client
|
||||||
virtual void sourceNeeded(QString &fileName, IncludeType, unsigned);
|
virtual void sourceNeeded(unsigned, QString &fileName, IncludeType);
|
||||||
|
|
||||||
virtual void macroAdded(const Macro &) {}
|
virtual void macroAdded(const Macro &) {}
|
||||||
|
|
||||||
virtual void passedMacroDefinitionCheck(unsigned, const Macro &) {}
|
virtual void passedMacroDefinitionCheck(unsigned, unsigned, const Macro &) {}
|
||||||
virtual void failedMacroDefinitionCheck(unsigned, const ByteArrayRef &) {}
|
virtual void failedMacroDefinitionCheck(unsigned, const ByteArrayRef &) {}
|
||||||
|
|
||||||
virtual void startExpandingMacro(unsigned,
|
virtual void notifyMacroReference(unsigned, unsigned, const Macro &) {}
|
||||||
const Macro &,
|
|
||||||
const ByteArrayRef &,
|
|
||||||
const QVector<MacroArgumentReference> &) {}
|
|
||||||
|
|
||||||
|
virtual void startExpandingMacro(unsigned,
|
||||||
|
unsigned,
|
||||||
|
const Macro &,
|
||||||
|
const QVector<MacroArgumentReference> &) {}
|
||||||
virtual void stopExpandingMacro(unsigned, const Macro &) {}
|
virtual void stopExpandingMacro(unsigned, const Macro &) {}
|
||||||
|
|
||||||
virtual void startSkippingBlocks(unsigned) {}
|
virtual void startSkippingBlocks(unsigned) {}
|
||||||
|
@@ -23,10 +23,10 @@ int ByteArrayRef::count(char ch) const
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Internal::PPToken::squeeze()
|
void Internal::PPToken::squeezeSource()
|
||||||
{
|
{
|
||||||
if (isValid()) {
|
if (hasSource()) {
|
||||||
m_src = m_src.mid(offset, length());
|
m_src = m_src.mid(offset, f.length);
|
||||||
m_src.squeeze();
|
m_src.squeeze();
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
@@ -96,6 +96,11 @@ public:
|
|||||||
const QByteArray &source() const
|
const QByteArray &source() const
|
||||||
{ return m_src; }
|
{ return m_src; }
|
||||||
|
|
||||||
|
bool hasSource() const
|
||||||
|
{ return !m_src.isEmpty(); }
|
||||||
|
|
||||||
|
void squeezeSource();
|
||||||
|
|
||||||
const char *bufferStart() const
|
const char *bufferStart() const
|
||||||
{ return m_src.constData(); }
|
{ return m_src.constData(); }
|
||||||
|
|
||||||
@@ -105,11 +110,6 @@ public:
|
|||||||
ByteArrayRef asByteArrayRef() const
|
ByteArrayRef asByteArrayRef() const
|
||||||
{ return ByteArrayRef(&m_src, offset, length()); }
|
{ return ByteArrayRef(&m_src, offset, length()); }
|
||||||
|
|
||||||
bool isValid() const
|
|
||||||
{ return !m_src.isEmpty(); }
|
|
||||||
|
|
||||||
void squeeze();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_src;
|
QByteArray m_src;
|
||||||
};
|
};
|
||||||
|
@@ -80,24 +80,23 @@ public:
|
|||||||
|
|
||||||
virtual void macroAdded(const Macro ¯o) = 0;
|
virtual void macroAdded(const Macro ¯o) = 0;
|
||||||
|
|
||||||
virtual void passedMacroDefinitionCheck(unsigned offset, const Macro ¯o) = 0;
|
virtual void passedMacroDefinitionCheck(unsigned offset, unsigned line, const Macro ¯o) = 0;
|
||||||
virtual void failedMacroDefinitionCheck(unsigned offset, const ByteArrayRef &name) = 0;
|
virtual void failedMacroDefinitionCheck(unsigned offset, const ByteArrayRef &name) = 0;
|
||||||
|
|
||||||
|
virtual void notifyMacroReference(unsigned offset, unsigned line, const Macro ¯o) = 0;
|
||||||
|
|
||||||
virtual void startExpandingMacro(unsigned offset,
|
virtual void startExpandingMacro(unsigned offset,
|
||||||
|
unsigned line,
|
||||||
const Macro ¯o,
|
const Macro ¯o,
|
||||||
const ByteArrayRef &originalText,
|
|
||||||
const QVector<MacroArgumentReference> &actuals
|
const QVector<MacroArgumentReference> &actuals
|
||||||
= QVector<MacroArgumentReference>()) = 0;
|
= QVector<MacroArgumentReference>()) = 0;
|
||||||
|
virtual void stopExpandingMacro(unsigned offset, const Macro ¯o) = 0;
|
||||||
virtual void stopExpandingMacro(unsigned offset,
|
|
||||||
const Macro ¯o) = 0;
|
|
||||||
|
|
||||||
/// Start skipping from the given offset.
|
/// Start skipping from the given offset.
|
||||||
virtual void startSkippingBlocks(unsigned offset) = 0;
|
virtual void startSkippingBlocks(unsigned offset) = 0;
|
||||||
virtual void stopSkippingBlocks(unsigned offset) = 0;
|
virtual void stopSkippingBlocks(unsigned offset) = 0;
|
||||||
|
|
||||||
virtual void sourceNeeded(QString &fileName, IncludeType mode,
|
virtual void sourceNeeded(unsigned line, QString &fileName, IncludeType mode) = 0;
|
||||||
unsigned line) = 0; // ### FIX the signature.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CPlusPlus
|
} // namespace CPlusPlus
|
||||||
|
@@ -95,6 +95,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
QString currentFile;
|
QString currentFile;
|
||||||
|
QByteArray currentFileUtf8;
|
||||||
unsigned currentLine;
|
unsigned currentLine;
|
||||||
bool hideNext;
|
bool hideNext;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -60,6 +60,7 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QBitArray>
|
#include <QBitArray>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
|
|
||||||
@@ -92,10 +93,17 @@ private:
|
|||||||
void preprocess(const QString &filename,
|
void preprocess(const QString &filename,
|
||||||
const QByteArray &source,
|
const QByteArray &source,
|
||||||
QByteArray *result, bool noLines, bool markGeneratedTokens, bool inCondition,
|
QByteArray *result, bool noLines, bool markGeneratedTokens, bool inCondition,
|
||||||
unsigned offsetRef = 0, unsigned envLineRef = 1);
|
unsigned offsetRef = 0, unsigned lineRef = 1);
|
||||||
|
|
||||||
enum { MAX_LEVEL = 512 };
|
enum { MAX_LEVEL = 512 };
|
||||||
|
|
||||||
|
enum ExpansionStatus {
|
||||||
|
NotExpanding,
|
||||||
|
ReadyForExpansion,
|
||||||
|
Expanding,
|
||||||
|
JustFinishedExpansion
|
||||||
|
};
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
State();
|
State();
|
||||||
|
|
||||||
@@ -114,14 +122,17 @@ private:
|
|||||||
bool m_inPreprocessorDirective;
|
bool m_inPreprocessorDirective;
|
||||||
|
|
||||||
QByteArray *m_result;
|
QByteArray *m_result;
|
||||||
bool m_markGeneratedTokens;
|
bool m_markExpandedTokens;
|
||||||
|
|
||||||
bool m_noLines;
|
bool m_noLines;
|
||||||
bool m_inCondition;
|
bool m_inCondition;
|
||||||
bool m_inDefine;
|
|
||||||
|
|
||||||
unsigned m_offsetRef;
|
unsigned m_offsetRef;
|
||||||
unsigned m_envLineRef;
|
unsigned m_lineRef;
|
||||||
|
|
||||||
|
ExpansionStatus m_expansionStatus;
|
||||||
|
QByteArray m_expansionResult;
|
||||||
|
QVector<QPair<unsigned, unsigned> > m_expandedTokensInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
void handleDefined(PPToken *tk);
|
void handleDefined(PPToken *tk);
|
||||||
@@ -129,9 +140,11 @@ private:
|
|||||||
void lex(PPToken *tk);
|
void lex(PPToken *tk);
|
||||||
void skipPreprocesorDirective(PPToken *tk);
|
void skipPreprocesorDirective(PPToken *tk);
|
||||||
bool handleIdentifier(PPToken *tk);
|
bool handleIdentifier(PPToken *tk);
|
||||||
bool handleFunctionLikeMacro(PPToken *tk, const Macro *macro, QVector<PPToken> &body,
|
bool handleFunctionLikeMacro(PPToken *tk,
|
||||||
bool addWhitespaceMarker,
|
const Macro *macro,
|
||||||
const QVector<QVector<PPToken> > &actuals);
|
QVector<PPToken> &body,
|
||||||
|
const QVector<QVector<PPToken> > &actuals,
|
||||||
|
unsigned lineRef);
|
||||||
|
|
||||||
bool skipping() const
|
bool skipping() const
|
||||||
{ return m_state.m_skipping[m_state.m_ifLevel]; }
|
{ return m_state.m_skipping[m_state.m_ifLevel]; }
|
||||||
@@ -155,30 +168,28 @@ private:
|
|||||||
|
|
||||||
static bool isQtReservedWord(const ByteArrayRef &name);
|
static bool isQtReservedWord(const ByteArrayRef &name);
|
||||||
|
|
||||||
inline bool atStartOfOutputLine() const
|
void trackExpansionCycles(PPToken *tk);
|
||||||
{ return (m_state.m_result && !m_state.m_result->isEmpty()) ? m_state.m_result->end()[-1] == '\n' : true; }
|
|
||||||
|
|
||||||
inline void startNewOutputLine() const
|
template <class T>
|
||||||
{
|
void writeOutput(const T &t);
|
||||||
if (m_state.m_result && !m_state.m_result->isEmpty() && m_state.m_result->end()[-1] != '\n')
|
void writeOutput(const ByteArrayRef &ref);
|
||||||
out('\n');
|
bool atStartOfOutputLine() const;
|
||||||
}
|
void maybeStartOutputLine();
|
||||||
|
void generateOutputLineMarker(unsigned lineno);
|
||||||
|
void synchronizeOutputLines(const PPToken &tk, bool forceLine = false);
|
||||||
|
void removeTrailingOutputLines();
|
||||||
|
|
||||||
void genLine(unsigned lineno, const QByteArray &fileName) const;
|
const QByteArray *currentOutputBuffer() const;
|
||||||
|
QByteArray *currentOutputBuffer();
|
||||||
|
|
||||||
inline void out(const QByteArray &text) const
|
void enforceSpacing(const PPToken &tk, bool forceSpacing = false);
|
||||||
{ if (m_state.m_result) m_state.m_result->append(text); }
|
static std::size_t computeDistance(const PPToken &tk, bool forceTillLine = false);
|
||||||
|
|
||||||
inline void out(char ch) const
|
PPToken generateToken(enum Kind kind,
|
||||||
{ if (m_state.m_result) m_state.m_result->append(ch); }
|
const char *content, int length,
|
||||||
|
unsigned lineno,
|
||||||
inline void out(const char *s) const
|
bool addQuotes,
|
||||||
{ if (m_state.m_result) m_state.m_result->append(s); }
|
bool addToControl = true);
|
||||||
|
|
||||||
inline void out(const ByteArrayRef &ref) const
|
|
||||||
{ if (m_state.m_result) m_state.m_result->append(ref.start(), ref.length()); }
|
|
||||||
|
|
||||||
PPToken generateToken(enum Kind kind, const char *content, int len, unsigned lineno, bool addQuotes);
|
|
||||||
PPToken generateConcatenated(const PPToken &leftTk, const PPToken &rightTk);
|
PPToken generateConcatenated(const PPToken &leftTk, const PPToken &rightTk);
|
||||||
|
|
||||||
void startSkippingBlocks(const PPToken &tk) const;
|
void startSkippingBlocks(const PPToken &tk) const;
|
||||||
|
@@ -340,7 +340,7 @@ public:
|
|||||||
void CppPreprocessor::run(const QString &fileName)
|
void CppPreprocessor::run(const QString &fileName)
|
||||||
{
|
{
|
||||||
QString absoluteFilePath = fileName;
|
QString absoluteFilePath = fileName;
|
||||||
sourceNeeded(absoluteFilePath, IncludeGlobal, /*line = */ 0);
|
sourceNeeded(0, absoluteFilePath, IncludeGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::resetEnvironment()
|
void CppPreprocessor::resetEnvironment()
|
||||||
@@ -499,12 +499,12 @@ void CppPreprocessor::macroAdded(const Macro ¯o)
|
|||||||
m_currentDoc->appendMacro(macro);
|
m_currentDoc->appendMacro(macro);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::passedMacroDefinitionCheck(unsigned offset, const Macro ¯o)
|
void CppPreprocessor::passedMacroDefinitionCheck(unsigned offset, unsigned line, const Macro ¯o)
|
||||||
{
|
{
|
||||||
if (! m_currentDoc)
|
if (! m_currentDoc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_currentDoc->addMacroUse(macro, offset, macro.name().length(), env.currentLine,
|
m_currentDoc->addMacroUse(macro, offset, macro.name().length(), line,
|
||||||
QVector<MacroArgumentReference>());
|
QVector<MacroArgumentReference>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,15 +516,23 @@ void CppPreprocessor::failedMacroDefinitionCheck(unsigned offset, const ByteArra
|
|||||||
m_currentDoc->addUndefinedMacroUse(QByteArray(name.start(), name.size()), offset);
|
m_currentDoc->addUndefinedMacroUse(QByteArray(name.start(), name.size()), offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::startExpandingMacro(unsigned offset,
|
void CppPreprocessor::notifyMacroReference(unsigned offset, unsigned line, const Macro ¯o)
|
||||||
|
{
|
||||||
|
if (! m_currentDoc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_currentDoc->addMacroUse(macro, offset, macro.name().length(), line,
|
||||||
|
QVector<MacroArgumentReference>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppPreprocessor::startExpandingMacro(unsigned offset, unsigned line,
|
||||||
const Macro ¯o,
|
const Macro ¯o,
|
||||||
const ByteArrayRef &originalText,
|
|
||||||
const QVector<MacroArgumentReference> &actuals)
|
const QVector<MacroArgumentReference> &actuals)
|
||||||
{
|
{
|
||||||
if (! m_currentDoc)
|
if (! m_currentDoc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_currentDoc->addMacroUse(macro, offset, originalText.length(), env.currentLine, actuals);
|
m_currentDoc->addMacroUse(macro, offset, macro.name().length(), line, actuals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::stopExpandingMacro(unsigned, const Macro &)
|
void CppPreprocessor::stopExpandingMacro(unsigned, const Macro &)
|
||||||
@@ -573,7 +581,7 @@ void CppPreprocessor::stopSkippingBlocks(unsigned offset)
|
|||||||
m_currentDoc->stopSkippingBlocks(offset);
|
m_currentDoc->stopSkippingBlocks(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type, unsigned line)
|
void CppPreprocessor::sourceNeeded(unsigned line, QString &fileName, IncludeType type)
|
||||||
{
|
{
|
||||||
if (fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return;
|
return;
|
||||||
@@ -590,7 +598,7 @@ void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type, unsigned
|
|||||||
|
|
||||||
Document::DiagnosticMessage d(Document::DiagnosticMessage::Warning,
|
Document::DiagnosticMessage d(Document::DiagnosticMessage::Warning,
|
||||||
m_currentDoc->fileName(),
|
m_currentDoc->fileName(),
|
||||||
env.currentLine, /*column = */ 0,
|
line, /*column = */ 0,
|
||||||
msg);
|
msg);
|
||||||
|
|
||||||
m_currentDoc->addDiagnosticMessage(d);
|
m_currentDoc->addDiagnosticMessage(d);
|
||||||
|
@@ -300,17 +300,19 @@ protected:
|
|||||||
void mergeEnvironment(CPlusPlus::Document::Ptr doc);
|
void mergeEnvironment(CPlusPlus::Document::Ptr doc);
|
||||||
|
|
||||||
virtual void macroAdded(const CPlusPlus::Macro ¯o);
|
virtual void macroAdded(const CPlusPlus::Macro ¯o);
|
||||||
virtual void passedMacroDefinitionCheck(unsigned offset, const CPlusPlus::Macro ¯o);
|
virtual void passedMacroDefinitionCheck(unsigned offset, unsigned line,
|
||||||
|
const CPlusPlus::Macro ¯o);
|
||||||
virtual void failedMacroDefinitionCheck(unsigned offset, const CPlusPlus::ByteArrayRef &name);
|
virtual void failedMacroDefinitionCheck(unsigned offset, const CPlusPlus::ByteArrayRef &name);
|
||||||
|
virtual void notifyMacroReference(unsigned offset, unsigned line,
|
||||||
|
const CPlusPlus::Macro ¯o);
|
||||||
virtual void startExpandingMacro(unsigned offset,
|
virtual void startExpandingMacro(unsigned offset,
|
||||||
|
unsigned line,
|
||||||
const CPlusPlus::Macro ¯o,
|
const CPlusPlus::Macro ¯o,
|
||||||
const CPlusPlus::ByteArrayRef &originalText,
|
|
||||||
const QVector<CPlusPlus::MacroArgumentReference> &actuals);
|
const QVector<CPlusPlus::MacroArgumentReference> &actuals);
|
||||||
virtual void stopExpandingMacro(unsigned offset, const CPlusPlus::Macro ¯o);
|
virtual void stopExpandingMacro(unsigned offset, const CPlusPlus::Macro ¯o);
|
||||||
virtual void startSkippingBlocks(unsigned offset);
|
virtual void startSkippingBlocks(unsigned offset);
|
||||||
virtual void stopSkippingBlocks(unsigned offset);
|
virtual void stopSkippingBlocks(unsigned offset);
|
||||||
virtual void sourceNeeded(QString &fileName, IncludeType type,
|
virtual void sourceNeeded(unsigned line, QString &fileName, IncludeType type);
|
||||||
unsigned line);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef ICHECK_BUILD
|
#ifndef ICHECK_BUILD
|
||||||
|
@@ -1,32 +1,15 @@
|
|||||||
# 1 "data/empty-macro.2.cpp"
|
# 1 "data/empty-macro.2.cpp"
|
||||||
# 6 "data/empty-macro.2.cpp"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
private:
|
private:
|
||||||
Test
|
# expansion begin 182,14 8:19 ~2 8:19 ~3 8:19 ~5 8:19 ~3
|
||||||
#gen true
|
Test(const Test &); Test &operator=(const Test &);
|
||||||
# 3 "data/empty-macro.2.cpp"
|
# expansion end
|
||||||
(const
|
|
||||||
#gen false
|
|
||||||
# 8 "data/empty-macro.2.cpp"
|
|
||||||
Test
|
|
||||||
#gen true
|
|
||||||
# 3 "data/empty-macro.2.cpp"
|
|
||||||
&);
|
|
||||||
#gen false
|
|
||||||
# 8 "data/empty-macro.2.cpp"
|
|
||||||
Test
|
|
||||||
#gen true
|
|
||||||
# 4 "data/empty-macro.2.cpp"
|
|
||||||
&operator=(const
|
|
||||||
#gen false
|
|
||||||
# 8 "data/empty-macro.2.cpp"
|
|
||||||
Test
|
|
||||||
#gen true
|
|
||||||
# 4 "data/empty-macro.2.cpp"
|
|
||||||
&);
|
|
||||||
#gen false
|
|
||||||
# 10 "data/empty-macro.2.cpp"
|
# 10 "data/empty-macro.2.cpp"
|
||||||
public:
|
public:
|
||||||
Test();
|
Test();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -3,3 +3,11 @@
|
|||||||
class EMPTY_MACRO Foo {
|
class EMPTY_MACRO Foo {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EMPTY_MACRO Foo2 {
|
||||||
|
};
|
||||||
|
|
||||||
|
class EMPTY_MACRO Foo3 {
|
||||||
|
};
|
||||||
|
|
||||||
|
class EMPTY_MACRO Foo3 {
|
||||||
|
};
|
||||||
|
@@ -4,3 +4,11 @@
|
|||||||
class Foo {
|
class Foo {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Foo2 {
|
||||||
|
};
|
||||||
|
|
||||||
|
class Foo3 {
|
||||||
|
};
|
||||||
|
|
||||||
|
class Foo3 {
|
||||||
|
};
|
||||||
|
@@ -1,15 +1,18 @@
|
|||||||
# 1 "data/identifier-expansion.1.cpp"
|
# 1 "data/identifier-expansion.1.cpp"
|
||||||
#gen true
|
|
||||||
# 1 "data/identifier-expansion.1.cpp"
|
|
||||||
test test
|
# expansion begin 19,4 ~1
|
||||||
#gen false
|
test
|
||||||
|
# expansion end
|
||||||
|
# expansion begin 24,4 ~1
|
||||||
|
test
|
||||||
|
# expansion end
|
||||||
# 3 "data/identifier-expansion.1.cpp"
|
# 3 "data/identifier-expansion.1.cpp"
|
||||||
;
|
;
|
||||||
|
|
||||||
void
|
void
|
||||||
#gen true
|
# expansion begin 36,4 ~1
|
||||||
# 1 "data/identifier-expansion.1.cpp"
|
|
||||||
test
|
test
|
||||||
#gen false
|
# expansion end
|
||||||
# 5 "data/identifier-expansion.1.cpp"
|
# 5 "data/identifier-expansion.1.cpp"
|
||||||
();
|
();
|
||||||
|
@@ -1,15 +1,19 @@
|
|||||||
# 1 "data/identifier-expansion.2.cpp"
|
# 1 "data/identifier-expansion.2.cpp"
|
||||||
#gen true
|
|
||||||
# 1 "data/identifier-expansion.2.cpp"
|
|
||||||
test test
|
|
||||||
#gen false
|
# expansion begin 45,12 ~1
|
||||||
|
test
|
||||||
|
# expansion end
|
||||||
|
# expansion begin 58,4 ~1
|
||||||
|
test
|
||||||
|
# expansion end
|
||||||
# 4 "data/identifier-expansion.2.cpp"
|
# 4 "data/identifier-expansion.2.cpp"
|
||||||
;
|
;
|
||||||
|
|
||||||
void
|
void
|
||||||
#gen true
|
# expansion begin 70,12 ~1
|
||||||
# 1 "data/identifier-expansion.2.cpp"
|
|
||||||
test
|
test
|
||||||
#gen false
|
# expansion end
|
||||||
# 6 "data/identifier-expansion.2.cpp"
|
# 6 "data/identifier-expansion.2.cpp"
|
||||||
();
|
();
|
||||||
|
@@ -2,13 +2,20 @@
|
|||||||
V(ADD) \
|
V(ADD) \
|
||||||
V(SUB)
|
V(SUB)
|
||||||
|
|
||||||
|
#define OTHER_FOR_EACH(V) \
|
||||||
|
V(DIV) \
|
||||||
|
V(MUL)
|
||||||
|
|
||||||
#define DECLARE_INSTR(op) #op,
|
#define DECLARE_INSTR(op) #op,
|
||||||
#define DECLARE_OP_INSTR(op) op_##op,
|
#define DECLARE_OP_INSTR(op) op_##op,
|
||||||
|
|
||||||
enum op_code {
|
enum op_code {
|
||||||
FOR_EACH_INSTR(DECLARE_OP_INSTR)
|
FOR_EACH_INSTR(DECLARE_OP_INSTR)
|
||||||
|
OTHER_FOR_EACH(DECLARE_OP_INSTR)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const char *names[] = {
|
static const char *names[] = {
|
||||||
FOR_EACH_INSTR(DECLARE_INSTR)
|
FOR_EACH_INSTR(DECLARE_INSTR)
|
||||||
|
OTHER_FOR_EACH(DECLARE_INSTR)
|
||||||
};
|
};
|
||||||
|
@@ -1,24 +1,22 @@
|
|||||||
# 1 "data/identifier-expansion.3.cpp"
|
# 1 "data/identifier-expansion.3.cpp"
|
||||||
# 8 "data/identifier-expansion.3.cpp"
|
# 12 "data/identifier-expansion.3.cpp"
|
||||||
enum op_code {
|
enum op_code {
|
||||||
#gen true
|
# expansion begin 195,14 ~4
|
||||||
# 6 "data/identifier-expansion.3.cpp"
|
|
||||||
op_ADD, op_SUB,
|
op_ADD, op_SUB,
|
||||||
#gen false
|
# expansion end
|
||||||
# 10 "data/identifier-expansion.3.cpp"
|
# expansion begin 232,14 ~4
|
||||||
|
op_DIV, op_MUL,
|
||||||
|
# expansion end
|
||||||
|
# 15 "data/identifier-expansion.3.cpp"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const char *names[] = {
|
static const char *names[] = {
|
||||||
#gen true
|
# expansion begin 301,14 ~4
|
||||||
# 2 "data/identifier-expansion.3.cpp"
|
"ADD", "SUB",
|
||||||
"ADD"
|
# expansion end
|
||||||
|
# expansion begin 331,14 ~4
|
||||||
|
"DIV", "MUL",
|
||||||
,
|
# expansion end
|
||||||
# 3 "data/identifier-expansion.3.cpp"
|
# 21 "data/identifier-expansion.3.cpp"
|
||||||
"SUB"
|
|
||||||
|
|
||||||
,
|
|
||||||
#gen false
|
|
||||||
# 14 "data/identifier-expansion.3.cpp"
|
|
||||||
};
|
};
|
||||||
|
@@ -5,5 +5,9 @@
|
|||||||
void baz()
|
void baz()
|
||||||
{
|
{
|
||||||
int aaa;
|
int aaa;
|
||||||
aaa;
|
# expansion begin 88,4 7:9
|
||||||
|
aaa
|
||||||
|
# expansion end
|
||||||
|
# 7 "data/identifier-expansion.4.cpp"
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
@@ -1,2 +1 @@
|
|||||||
# 1 "data/identifier-expansion.5.cpp"
|
# 1 "data/identifier-expansion.5.cpp"
|
||||||
# 9 "data/identifier-expansion.5.cpp"
|
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
# 1 "data/macro-test.cpp"
|
# 1 "data/macro-test.cpp"
|
||||||
# 7 "data/macro-test.cpp"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void thisFunctionIsEnabled();
|
void thisFunctionIsEnabled();
|
||||||
# 21 "data/macro-test.cpp"
|
# 21 "data/macro-test.cpp"
|
||||||
void thisFunctionIsEnabled2();
|
void thisFunctionIsEnabled2();
|
||||||
# 31 "data/macro-test.cpp"
|
# 31 "data/macro-test.cpp"
|
||||||
void thisFunctionIsEnabled3();
|
void thisFunctionIsEnabled3();
|
||||||
# 37 "data/macro-test.cpp"
|
|
||||||
|
@@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
A:
|
A:
|
||||||
#gen true
|
# expansion begin 32,1 ~1
|
||||||
# 1 "data/macro_expand.c"
|
|
||||||
Y
|
Y
|
||||||
#gen false
|
# expansion end
|
||||||
# 5 "data/macro_expand.c"
|
# 5 "data/macro_expand.c"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
# 1 "data/macro_expand_1.cpp"
|
# 1 "data/macro_expand_1.cpp"
|
||||||
#gen true
|
|
||||||
# 1 "data/macro_expand_1.cpp"
|
# expansion begin 33,13 ~1 2:14
|
||||||
class
|
class QString
|
||||||
#gen false
|
# expansion end
|
||||||
# 2 "data/macro_expand_1.cpp"
|
# 2 "data/macro_expand_1.cpp"
|
||||||
QString;
|
;
|
||||||
|
@@ -63,4 +63,3 @@ Write in C, write in C,
|
|||||||
Write in C, yeah, write in C.
|
Write in C, yeah, write in C.
|
||||||
The government loves ADA,
|
The government loves ADA,
|
||||||
Write in C.
|
Write in C.
|
||||||
|
|
||||||
|
26
tests/auto/cplusplus/preprocessor/data/noPP.2.cpp
Normal file
26
tests/auto/cplusplus/preprocessor/data/noPP.2.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
void hey(int a) {
|
||||||
|
int b = a + 10;
|
||||||
|
b;
|
||||||
|
}
|
||||||
|
|
||||||
|
class hello
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool doit() { return true; }
|
||||||
|
bool dothat();
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool hello::dothat()
|
||||||
|
{
|
||||||
|
bool should = true;
|
||||||
|
if (should) {
|
||||||
|
int i = 10;
|
||||||
|
while (i > 0) {
|
||||||
|
run();
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@@ -1,8 +1,10 @@
|
|||||||
# 1 "data/poundpound.1.cpp"
|
# 1 "data/poundpound.1.cpp"
|
||||||
struct QQ {};
|
struct QQ {};
|
||||||
#gen true
|
|
||||||
# 3 "data/poundpound.1.cpp"
|
|
||||||
|
|
||||||
|
# expansion begin 50,2 ~4
|
||||||
typedef QQ PPCC;
|
typedef QQ PPCC;
|
||||||
#gen false
|
# expansion end
|
||||||
# 7 "data/poundpound.1.cpp"
|
# 7 "data/poundpound.1.cpp"
|
||||||
typedef PPCC RR;
|
typedef PPCC RR;
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
# 1 "data/recursive.1.cpp"
|
# 1 "data/recursive.1.cpp"
|
||||||
#gen true
|
|
||||||
# 1 "data/recursive.1.cpp"
|
|
||||||
|
|
||||||
|
# expansion begin 25,1 ~1
|
||||||
b
|
b
|
||||||
a
|
# expansion end
|
||||||
#gen false
|
# expansion begin 27,1 ~1
|
||||||
|
a
|
||||||
|
# expansion end
|
||||||
# 6 "data/recursive.1.cpp"
|
# 6 "data/recursive.1.cpp"
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
# 1 "data/reserved.1.cpp"
|
# 1 "data/reserved.1.cpp"
|
||||||
# 5 "data/reserved.1.cpp"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int f() {
|
int f() {
|
||||||
foreach (QString &s, QStringList()) {
|
foreach (QString &s, QStringList()) {
|
||||||
doSomething();
|
doSomething();
|
||||||
|
@@ -3,11 +3,19 @@ include(../shared/shared.pri)
|
|||||||
SOURCES += tst_preprocessor.cpp
|
SOURCES += tst_preprocessor.cpp
|
||||||
|
|
||||||
OTHER_FILES = \
|
OTHER_FILES = \
|
||||||
data/noPP.1.cpp data/noPP.1.errors.txt \
|
data/noPP.1.cpp \
|
||||||
data/identifier-expansion.1.cpp data/identifier-expansion.1.out.cpp data/identifier-expansion.1.errors.txt \
|
data/noPP.2.cpp \
|
||||||
data/identifier-expansion.2.cpp data/identifier-expansion.2.out.cpp data/identifier-expansion.2.errors.txt \
|
data/identifier-expansion.1.cpp data/identifier-expansion.1.out.cpp \
|
||||||
data/identifier-expansion.3.cpp data/identifier-expansion.3.out.cpp data/identifier-expansion.3.errors.txt \
|
data/identifier-expansion.2.cpp data/identifier-expansion.2.out.cpp \
|
||||||
data/identifier-expansion.4.cpp data/identifier-expansion.4.out.cpp data/identifier-expansion.4.errors.txt \
|
data/identifier-expansion.3.cpp data/identifier-expansion.3.out.cpp \
|
||||||
data/reserved.1.cpp data/reserved.1.out.cpp data/reserved.1.errors.txt \
|
data/identifier-expansion.4.cpp data/identifier-expansion.4.out.cpp \
|
||||||
data/macro_expand.c data/macro_expand.out.c data/macro_expand.errors.txt \
|
data/identifier-expansion.5.cpp data/identifier-expansion.5.out.cpp \
|
||||||
data/empty-macro.cpp data/empty-macro.out.cpp
|
data/reserved.1.cpp data/reserved.1.out.cpp \
|
||||||
|
data/recursive.1.cpp data/recursive.1.out.cpp \
|
||||||
|
data/macro_expand.c data/macro_expand.out.c \
|
||||||
|
data/macro_expand_1.cpp data/macro_expand_1.out.cpp \
|
||||||
|
data/macro-test.cpp data/macro-test.out.cpp \
|
||||||
|
data/poundpound.1.cpp data/poundpound.1.out.cpp \
|
||||||
|
data/empty-macro.cpp data/empty-macro.out.cpp \
|
||||||
|
data/empty-macro.2.cpp data/empty-macro.2.out.cpp \
|
||||||
|
data/macro_pounder_fn.c
|
||||||
|
@@ -114,18 +114,26 @@ public:
|
|||||||
m_definedMacrosLine.append(macro.line());
|
m_definedMacrosLine.append(macro.line());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void passedMacroDefinitionCheck(unsigned /*offset*/, const Macro &/*macro*/) {}
|
virtual void passedMacroDefinitionCheck(unsigned /*offset*/,
|
||||||
|
unsigned /*line*/,
|
||||||
|
const Macro &/*macro*/) {}
|
||||||
virtual void failedMacroDefinitionCheck(unsigned /*offset*/, const ByteArrayRef &/*name*/) {}
|
virtual void failedMacroDefinitionCheck(unsigned /*offset*/, const ByteArrayRef &/*name*/) {}
|
||||||
|
|
||||||
|
virtual void notifyMacroReference(unsigned offset, unsigned line, const Macro ¯o)
|
||||||
|
{
|
||||||
|
m_macroUsesLine[macro.name()].append(line);
|
||||||
|
m_expandedMacrosOffset.append(offset);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void startExpandingMacro(unsigned offset,
|
virtual void startExpandingMacro(unsigned offset,
|
||||||
|
unsigned line,
|
||||||
const Macro ¯o,
|
const Macro ¯o,
|
||||||
const ByteArrayRef &originalText,
|
|
||||||
const QVector<MacroArgumentReference> &actuals
|
const QVector<MacroArgumentReference> &actuals
|
||||||
= QVector<MacroArgumentReference>())
|
= QVector<MacroArgumentReference>())
|
||||||
{
|
{
|
||||||
m_expandedMacros.append(QByteArray(originalText.start(), originalText.length()));
|
m_expandedMacros.append(macro.name());
|
||||||
m_expandedMacrosOffset.append(offset);
|
m_expandedMacrosOffset.append(offset);
|
||||||
m_macroUsesLine[macro.name()].append(m_env->currentLine);
|
m_macroUsesLine[macro.name()].append(line);
|
||||||
m_macroArgsCount.append(actuals.size());
|
m_macroArgsCount.append(actuals.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,8 +145,7 @@ public:
|
|||||||
virtual void stopSkippingBlocks(unsigned offset)
|
virtual void stopSkippingBlocks(unsigned offset)
|
||||||
{ m_skippedBlocks.last().end = offset; }
|
{ m_skippedBlocks.last().end = offset; }
|
||||||
|
|
||||||
virtual void sourceNeeded(QString &includedFileName, IncludeType mode,
|
virtual void sourceNeeded(unsigned line, QString &includedFileName, IncludeType mode)
|
||||||
unsigned line)
|
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
m_recordedIncludes.append(Include(includedFileName, mode, line));
|
m_recordedIncludes.append(Include(includedFileName, mode, line));
|
||||||
@@ -300,15 +307,14 @@ protected:
|
|||||||
}
|
}
|
||||||
static QString simplified(QByteArray buf);
|
static QString simplified(QByteArray buf);
|
||||||
|
|
||||||
private /* not corrected yet */:
|
private:
|
||||||
void macro_definition_lineno();
|
void compare_input_output();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void defined();
|
|
||||||
void defined_data();
|
|
||||||
|
|
||||||
void va_args();
|
void va_args();
|
||||||
void named_va_args();
|
void named_va_args();
|
||||||
|
void defined();
|
||||||
|
void defined_data();
|
||||||
void empty_macro_args();
|
void empty_macro_args();
|
||||||
void macro_args_count();
|
void macro_args_count();
|
||||||
void invalid_param_count();
|
void invalid_param_count();
|
||||||
@@ -318,14 +324,18 @@ private slots:
|
|||||||
void macro_arguments_notificatin();
|
void macro_arguments_notificatin();
|
||||||
void unfinished_function_like_macro_call();
|
void unfinished_function_like_macro_call();
|
||||||
void nasty_macro_expansion();
|
void nasty_macro_expansion();
|
||||||
void tstst();
|
void glib_attribute();
|
||||||
void test_file_builtin();
|
void builtin__FILE__();
|
||||||
|
|
||||||
void blockSkipping();
|
void blockSkipping();
|
||||||
void includes_1();
|
void includes_1();
|
||||||
|
void dont_eagerly_expand();
|
||||||
|
void dont_eagerly_expand_data();
|
||||||
void comparisons_data();
|
void comparisons_data();
|
||||||
void comparisons();
|
void comparisons();
|
||||||
|
void comments_within();
|
||||||
|
void comments_within_data();
|
||||||
|
void multitokens_argument();
|
||||||
|
void multitokens_argument_data();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove all #... lines, and 'simplify' string, to allow easily comparing the result
|
// Remove all #... lines, and 'simplify' string, to allow easily comparing the result
|
||||||
@@ -534,38 +544,72 @@ void tst_Preprocessor::macro_uses_lines()
|
|||||||
<< buffer.lastIndexOf("ENABLE(LESS)"));
|
<< buffer.lastIndexOf("ENABLE(LESS)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::macro_definition_lineno()
|
void tst_Preprocessor::multitokens_argument_data()
|
||||||
{
|
{
|
||||||
Client *client = 0; // no client.
|
QTest::addColumn<QByteArray>("input");
|
||||||
Environment env;
|
QTest::addColumn<QByteArray>("output");
|
||||||
Preprocessor preprocess(client, &env);
|
|
||||||
QByteArray preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
|
||||||
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
|
||||||
"foo(int a);\n"));
|
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
|
||||||
|
|
||||||
preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
QByteArray original;
|
||||||
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
QByteArray expected;
|
||||||
"foo(int a)\n"
|
|
||||||
";\n"));
|
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
|
||||||
|
|
||||||
preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
original =
|
||||||
QByteArray("#define foo(ARGS) int f(ARGS)\n"
|
"#define foo(ARGS) int f(ARGS)\n"
|
||||||
"foo(int \n"
|
"foo(int a);\n";
|
||||||
" a);\n"));
|
expected =
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 30,3 ~3 2:4 2:8 ~1\n"
|
||||||
|
"int f(int a)\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 2 \"<stdin>\"\n"
|
||||||
|
" ;\n";
|
||||||
|
QTest::newRow("case 1") << original << expected;
|
||||||
|
|
||||||
preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
original =
|
||||||
QByteArray("#define foo int f\n"
|
"#define foo(ARGS) int f(ARGS)\n"
|
||||||
"foo;\n"));
|
"foo(int \n"
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
" a);\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 30,3 ~3 2:4 3:4 ~1\n"
|
||||||
|
"int f(int a)\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 3 \"<stdin>\"\n"
|
||||||
|
" ;\n";
|
||||||
|
QTest::newRow("case 2") << original << expected;
|
||||||
|
|
||||||
preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
original =
|
||||||
QByteArray("#define foo int f\n"
|
"#define foo(ARGS) int f(ARGS)\n"
|
||||||
"foo\n"
|
"foo(int a = 0);\n";
|
||||||
";\n"));
|
expected =
|
||||||
QVERIFY(preprocessed.contains("#gen true\n# 2 \"<stdin>\"\nint f"));
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 30,3 ~3 2:4 2:8 2:10 2:12 ~1\n"
|
||||||
|
"int f(int a = 0)\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 2 \"<stdin>\"\n"
|
||||||
|
" ;\n";
|
||||||
|
QTest::newRow("case 3") << original << expected;
|
||||||
|
|
||||||
|
original =
|
||||||
|
"#define foo(X) int f(X = 0)\n"
|
||||||
|
"foo(int \n"
|
||||||
|
" a);\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 28,3 ~3 2:4 3:4 ~3\n"
|
||||||
|
"int f(int a = 0)\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 3 \"<stdin>\"\n"
|
||||||
|
" ;\n";
|
||||||
|
QTest::newRow("case 4") << original << expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::multitokens_argument()
|
||||||
|
{
|
||||||
|
compare_input_output();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::objmacro_expanding_as_fnmacro_notification()
|
void tst_Preprocessor::objmacro_expanding_as_fnmacro_notification()
|
||||||
@@ -608,9 +652,17 @@ void tst_Preprocessor::unfinished_function_like_macro_call()
|
|||||||
|
|
||||||
Preprocessor preprocess(client, &env);
|
Preprocessor preprocess(client, &env);
|
||||||
QByteArray preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
QByteArray preprocessed = preprocess.run(QLatin1String("<stdin>"),
|
||||||
QByteArray("\n#define foo(a,b) a + b"
|
QByteArray("\n"
|
||||||
"\nfoo(1, 2\n"));
|
"#define foo(a,b) a + b\n"
|
||||||
QByteArray expected__("# 1 \"<stdin>\"\n\n\n 1\n#gen true\n# 2 \"<stdin>\"\n+\n#gen false\n# 3 \"<stdin>\"\n 2\n");
|
"foo(1, 2\n"));
|
||||||
|
QByteArray expected__("# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 24,3 3:4 ~1 3:7\n"
|
||||||
|
"1 + 2\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 4 \"<stdin>\"\n");
|
||||||
|
|
||||||
// DUMP_OUTPUT(preprocessed);
|
// DUMP_OUTPUT(preprocessed);
|
||||||
QCOMPARE(preprocessed, expected__);
|
QCOMPARE(preprocessed, expected__);
|
||||||
}
|
}
|
||||||
@@ -668,12 +720,10 @@ void tst_Preprocessor::nasty_macro_expansion()
|
|||||||
QVERIFY(!preprocessed.contains("FIELD32"));
|
QVERIFY(!preprocessed.contains("FIELD32"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::tstst()
|
void tst_Preprocessor::glib_attribute()
|
||||||
{
|
{
|
||||||
Client *client = 0; // no client.
|
|
||||||
Environment env;
|
Environment env;
|
||||||
|
Preprocessor preprocess(0, &env);
|
||||||
Preprocessor preprocess(client, &env);
|
|
||||||
QByteArray preprocessed = preprocess.run(
|
QByteArray preprocessed = preprocess.run(
|
||||||
QLatin1String("<stdin>"),
|
QLatin1String("<stdin>"),
|
||||||
QByteArray("\n"
|
QByteArray("\n"
|
||||||
@@ -681,15 +731,14 @@ void tst_Preprocessor::tstst()
|
|||||||
"namespace std _GLIBCXX_VISIBILITY(default) {\n"
|
"namespace std _GLIBCXX_VISIBILITY(default) {\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
));
|
));
|
||||||
const QByteArray result____ ="# 1 \"<stdin>\"\n\n\n"
|
const QByteArray result____ =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
"namespace std\n"
|
"namespace std\n"
|
||||||
"#gen true\n"
|
"# expansion begin 85,19 ~9\n"
|
||||||
"# 2 \"<stdin>\"\n"
|
"__attribute__ ((__visibility__ (\"default\")))\n"
|
||||||
"__attribute__ ((__visibility__ (\n"
|
"# expansion end\n"
|
||||||
"\"default\"\n"
|
|
||||||
"# 2 \"<stdin>\"\n"
|
|
||||||
")))\n"
|
|
||||||
"#gen false\n"
|
|
||||||
"# 3 \"<stdin>\"\n"
|
"# 3 \"<stdin>\"\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
@@ -698,7 +747,7 @@ void tst_Preprocessor::tstst()
|
|||||||
QCOMPARE(preprocessed, result____);
|
QCOMPARE(preprocessed, result____);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Preprocessor::test_file_builtin()
|
void tst_Preprocessor::builtin__FILE__()
|
||||||
{
|
{
|
||||||
Client *client = 0; // no client.
|
Client *client = 0; // no client.
|
||||||
Environment env;
|
Environment env;
|
||||||
@@ -710,13 +759,8 @@ void tst_Preprocessor::test_file_builtin()
|
|||||||
));
|
));
|
||||||
const QByteArray result____ =
|
const QByteArray result____ =
|
||||||
"# 1 \"some-file.c\"\n"
|
"# 1 \"some-file.c\"\n"
|
||||||
"const char *f =\n"
|
"const char *f = \"some-file.c\"\n";
|
||||||
"#gen true\n"
|
|
||||||
"# 1 \"some-file.c\"\n"
|
|
||||||
"\"some-file.c\"\n"
|
|
||||||
"#gen false\n"
|
|
||||||
"# 2 \"some-file.c\"\n"
|
|
||||||
;
|
|
||||||
QCOMPARE(preprocessed, result____);
|
QCOMPARE(preprocessed, result____);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,6 +771,7 @@ void tst_Preprocessor::comparisons_data()
|
|||||||
QTest::addColumn<QString>("errorfile");
|
QTest::addColumn<QString>("errorfile");
|
||||||
|
|
||||||
QTest::newRow("do nothing") << "noPP.1.cpp" << "noPP.1.cpp" << "";
|
QTest::newRow("do nothing") << "noPP.1.cpp" << "noPP.1.cpp" << "";
|
||||||
|
QTest::newRow("no PP 2") << "noPP.2.cpp" << "noPP.2.cpp" << "";
|
||||||
QTest::newRow("identifier-expansion 1")
|
QTest::newRow("identifier-expansion 1")
|
||||||
<< "identifier-expansion.1.cpp" << "identifier-expansion.1.out.cpp" << "";
|
<< "identifier-expansion.1.cpp" << "identifier-expansion.1.out.cpp" << "";
|
||||||
QTest::newRow("identifier-expansion 2")
|
QTest::newRow("identifier-expansion 2")
|
||||||
@@ -766,6 +811,7 @@ void tst_Preprocessor::comparisons()
|
|||||||
QByteArray errors;
|
QByteArray errors;
|
||||||
QByteArray preprocessed = preprocess(infile, &errors, infile == outfile);
|
QByteArray preprocessed = preprocess(infile, &errors, infile == outfile);
|
||||||
|
|
||||||
|
|
||||||
// DUMP_OUTPUT(preprocessed);
|
// DUMP_OUTPUT(preprocessed);
|
||||||
|
|
||||||
if (!outfile.isEmpty()) {
|
if (!outfile.isEmpty()) {
|
||||||
@@ -976,6 +1022,176 @@ void tst_Preprocessor::defined_data()
|
|||||||
"#endif\n";
|
"#endif\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::dont_eagerly_expand_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QByteArray>("input");
|
||||||
|
QTest::addColumn<QByteArray>("output");
|
||||||
|
|
||||||
|
QByteArray original;
|
||||||
|
QByteArray expected;
|
||||||
|
|
||||||
|
// Expansion must be processed upon invocation of the macro. Therefore a particular
|
||||||
|
// identifier within a define must not be expanded (in the case it matches an
|
||||||
|
// already known macro) during the processor directive handling, but only when
|
||||||
|
// it's actually "used". Naturally, if it's still not replaced after an invocation
|
||||||
|
// it should then be expanded. This is consistent with clang and gcc for example.
|
||||||
|
|
||||||
|
original = "#define T int\n"
|
||||||
|
"#define FOO(T) T\n"
|
||||||
|
"FOO(double)\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 31,3 3:4\n"
|
||||||
|
"double\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 4 \"<stdin>\"\n";
|
||||||
|
QTest::newRow("case 1") << original << expected;
|
||||||
|
|
||||||
|
original = "#define T int\n"
|
||||||
|
"#define FOO(X) T\n"
|
||||||
|
"FOO(double)\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 31,3 ~1\n"
|
||||||
|
"int\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 4 \"<stdin>\"\n";
|
||||||
|
QTest::newRow("case 2") << original << expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::dont_eagerly_expand()
|
||||||
|
{
|
||||||
|
compare_input_output();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::comments_within()
|
||||||
|
{
|
||||||
|
compare_input_output();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::comments_within_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QByteArray>("input");
|
||||||
|
QTest::addColumn<QByteArray>("output");
|
||||||
|
|
||||||
|
QByteArray original;
|
||||||
|
QByteArray expected;
|
||||||
|
|
||||||
|
original = "#define FOO int x;\n"
|
||||||
|
"\n"
|
||||||
|
" // comment\n"
|
||||||
|
" // comment\n"
|
||||||
|
" // comment\n"
|
||||||
|
" // comment\n"
|
||||||
|
"FOO\n"
|
||||||
|
"x = 10\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 76,3 ~3\n"
|
||||||
|
"int x;\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 8 \"<stdin>\"\n"
|
||||||
|
"x = 10\n";
|
||||||
|
QTest::newRow("case 1") << original << expected;
|
||||||
|
|
||||||
|
|
||||||
|
original = "#define FOO int x;\n"
|
||||||
|
"\n"
|
||||||
|
" /* comment\n"
|
||||||
|
" comment\n"
|
||||||
|
" comment\n"
|
||||||
|
" comment */\n"
|
||||||
|
"FOO\n"
|
||||||
|
"x = 10\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 79,3 ~3\n"
|
||||||
|
"int x;\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 8 \"<stdin>\"\n"
|
||||||
|
"x = 10\n";
|
||||||
|
QTest::newRow("case 2") << original << expected;
|
||||||
|
|
||||||
|
|
||||||
|
original = "#define FOO int x;\n"
|
||||||
|
"\n"
|
||||||
|
" // comment\n"
|
||||||
|
" // comment\n"
|
||||||
|
" // comment\n"
|
||||||
|
" // comment\n"
|
||||||
|
"FOO\n"
|
||||||
|
"// test\n"
|
||||||
|
"// test again\n"
|
||||||
|
"x = 10\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 76,3 ~3\n"
|
||||||
|
"int x;\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 10 \"<stdin>\"\n"
|
||||||
|
"x = 10\n";
|
||||||
|
QTest::newRow("case 3") << original << expected;
|
||||||
|
|
||||||
|
|
||||||
|
original = "#define FOO int x;\n"
|
||||||
|
"\n"
|
||||||
|
" /* comment\n"
|
||||||
|
" comment\n"
|
||||||
|
" comment\n"
|
||||||
|
" comment */\n"
|
||||||
|
"FOO\n"
|
||||||
|
"/* \n"
|
||||||
|
"*/\n"
|
||||||
|
"x = 10\n";
|
||||||
|
expected =
|
||||||
|
"# 1 \"<stdin>\"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"# expansion begin 79,3 ~3\n"
|
||||||
|
"int x;\n"
|
||||||
|
"# expansion end\n"
|
||||||
|
"# 10 \"<stdin>\"\n"
|
||||||
|
"x = 10\n";
|
||||||
|
QTest::newRow("case 4") << original << expected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Preprocessor::compare_input_output()
|
||||||
|
{
|
||||||
|
QFETCH(QByteArray, input);
|
||||||
|
QFETCH(QByteArray, output);
|
||||||
|
|
||||||
|
Environment env;
|
||||||
|
Preprocessor preprocess(0, &env);
|
||||||
|
QByteArray prep = preprocess.run(QLatin1String("<stdin>"), input);
|
||||||
|
QCOMPARE(output, prep);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_APPLESS_MAIN(tst_Preprocessor)
|
QTEST_APPLESS_MAIN(tst_Preprocessor)
|
||||||
|
|
||||||
#include "tst_preprocessor.moc"
|
#include "tst_preprocessor.moc"
|
||||||
|
Reference in New Issue
Block a user