summaryrefslogtreecommitdiff
path: root/src/libs/cplusplus
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/cplusplus')
-rw-r--r--src/libs/cplusplus/CppDocument.cpp63
-rw-r--r--src/libs/cplusplus/CppDocument.h37
-rw-r--r--src/libs/cplusplus/FastPreprocessor.h4
-rw-r--r--src/libs/cplusplus/PreprocessorClient.cpp38
-rw-r--r--src/libs/cplusplus/PreprocessorClient.h9
-rw-r--r--src/libs/cplusplus/pp-engine.cpp33
-rw-r--r--src/libs/cplusplus/pp-macro-expander.cpp20
-rw-r--r--src/libs/cplusplus/pp-macro-expander.h5
8 files changed, 192 insertions, 17 deletions
diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp
index 9faabe29b1..675cf6edf9 100644
--- a/src/libs/cplusplus/CppDocument.cpp
+++ b/src/libs/cplusplus/CppDocument.cpp
@@ -44,6 +44,11 @@
#include <QtCore/QBitArray>
#include <QtCore/QtDebug>
+/*!
+ \namespace CPlusPlus
+ The namespace for C++ related tools.
+*/
+
using namespace CPlusPlus;
namespace {
@@ -101,6 +106,7 @@ private:
} // anonymous namespace
+
Document::Document(const QString &fileName)
: _fileName(fileName),
_globalNamespace(0),
@@ -166,9 +172,10 @@ void Document::appendMacro(const Macro &macro)
}
void Document::addMacroUse(const Macro &macro, unsigned offset, unsigned length,
- const QVector<MacroArgumentReference> &actuals)
+ const QVector<MacroArgumentReference> &actuals, bool inCondition)
{
MacroUse use(macro, offset, offset + length);
+ use.setInCondition(inCondition);
foreach (const MacroArgumentReference &actual, actuals) {
const Block arg(actual.position(), actual.position() + actual.length());
@@ -179,6 +186,60 @@ void Document::addMacroUse(const Macro &macro, unsigned offset, unsigned length,
_macroUses.append(use);
}
+void Document::addUndefinedMacroUse(const QByteArray &name, unsigned offset)
+{
+ QByteArray copy(name.data(), name.size());
+ UndefinedMacroUse use(copy, offset);
+ _undefinedMacroUses.append(use);
+}
+
+/*!
+ \class Document::MacroUse
+ \brief Represents the usage of a macro in a \l {Document}.
+ \sa Document::UndefinedMacroUse
+*/
+
+/*!
+ \class Document::UndefinedMacroUse
+ \brief Represents a macro that was looked up, but not found.
+
+ Holds data about the reference to a macro in an \tt{#ifdef} or \tt{#ifndef}
+ or argument to the \tt{defined} operator inside an \tt{#if} or \tt{#elif} that does
+ not exist.
+
+ \sa Document::undefinedMacroUses(), Document::MacroUse, Macro
+*/
+
+/*!
+ \fn QByteArray Document::UndefinedMacroUse::name() const
+
+ Returns the name of the macro that was not found.
+*/
+
+/*!
+ \fn QList<UndefinedMacroUse> Document::undefinedMacroUses() const
+
+ Returns a list of referenced but undefined macros.
+
+ \sa Document::macroUses(), Document::definedMacros(), Macro
+*/
+
+/*!
+ \fn QList<MacroUse> Document::macroUses() const
+
+ Returns a list of macros used.
+
+ \sa Document::undefinedMacroUses(), Document::definedMacros(), Macro
+*/
+
+/*!
+ \fn QList<Macro> Document::definedMacros() const
+
+ Returns the list of macros defined.
+
+ \sa Document::macroUses(), Document::undefinedMacroUses()
+*/
+
TranslationUnit *Document::translationUnit() const
{
return _translationUnit;
diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h
index 7308e04e60..ca15bd1986 100644
--- a/src/libs/cplusplus/CppDocument.h
+++ b/src/libs/cplusplus/CppDocument.h
@@ -70,7 +70,8 @@ public:
void appendMacro(const Macro &macro);
void addMacroUse(const Macro &macro, unsigned offset, unsigned length,
- const QVector<MacroArgumentReference> &range);
+ const QVector<MacroArgumentReference> &range, bool inCondition);
+ void addUndefinedMacroUse(const QByteArray &name, unsigned offset);
Control *control() const;
TranslationUnit *translationUnit() const;
@@ -220,13 +221,15 @@ public:
class MacroUse: public Block {
Macro _macro;
QVector<Block> _arguments;
+ bool _inCondition;
public:
inline MacroUse(const Macro &macro,
unsigned begin = 0,
unsigned end = 0)
: Block(begin, end),
- _macro(macro)
+ _macro(macro),
+ _inCondition(false)
{ }
const Macro &macro() const
@@ -238,11 +241,37 @@ public:
QVector<Block> arguments() const
{ return _arguments; }
+ bool isInCondition() const
+ { return _inCondition; }
+
+ private:
void setArguments(const QVector<Block> &arguments)
{ _arguments = arguments; }
void addArgument(const Block &block)
{ _arguments.append(block); }
+
+ void setInCondition(bool set)
+ { _inCondition = set; }
+
+ friend class Document;
+ };
+
+ class UndefinedMacroUse: public Block {
+ QByteArray _name;
+
+ public:
+ inline UndefinedMacroUse(
+ const QByteArray &name,
+ unsigned begin = 0)
+ : Block(begin, begin + name.length()),
+ _name(name)
+ { }
+
+ QByteArray name() const
+ {
+ return _name;
+ }
};
QList<Include> includes() const
@@ -254,6 +283,9 @@ public:
QList<MacroUse> macroUses() const
{ return _macroUses; }
+ QList<UndefinedMacroUse> undefinedMacroUses() const
+ { return _undefinedMacroUses; }
+
private:
Symbol *findSymbolAt(unsigned line, unsigned column, Scope *scope) const;
@@ -267,6 +299,7 @@ private:
QList<Macro> _definedMacros;
QList<Block> _skippedBlocks;
QList<MacroUse> _macroUses;
+ QList<UndefinedMacroUse> _undefinedMacroUses;
QByteArray _source;
unsigned _revision;
diff --git a/src/libs/cplusplus/FastPreprocessor.h b/src/libs/cplusplus/FastPreprocessor.h
index 0d82d54253..36f3685fc1 100644
--- a/src/libs/cplusplus/FastPreprocessor.h
+++ b/src/libs/cplusplus/FastPreprocessor.h
@@ -58,9 +58,13 @@ public:
virtual void macroAdded(const Macro &) {}
+ virtual void passedMacroDefinitionCheck(unsigned, const Macro &) {}
+ virtual void failedMacroDefinitionCheck(unsigned, const QByteArray &) {}
+
virtual void startExpandingMacro(unsigned,
const Macro &,
const QByteArray &,
+ bool,
const QVector<MacroArgumentReference> &) {}
virtual void stopExpandingMacro(unsigned, const Macro &) {}
diff --git a/src/libs/cplusplus/PreprocessorClient.cpp b/src/libs/cplusplus/PreprocessorClient.cpp
index 6fe1b2a75b..5b57baa7b2 100644
--- a/src/libs/cplusplus/PreprocessorClient.cpp
+++ b/src/libs/cplusplus/PreprocessorClient.cpp
@@ -31,6 +31,44 @@
using namespace CPlusPlus;
+/*!
+ \class Client
+ \brief A notification interface for for C++ preprocessor.
+*/
+
+/*!
+ \fn void Client::macroAdded(const Macro &macro)
+
+ Called whenever a new macro is defined.
+*/
+
+/*!
+ \fn void Client::passedMacroDefinitionCheck(unsigned offset, const Macro &macro)
+
+ Called when the preprocessor checks whether a macro is defined or not and the
+ result is positive.
+
+ \sa failedMacroDefinitionCheck()
+*/
+
+/*!
+ \fn void Client::failedMacroDefinitionCheck(unsigned offset, const QByteArray &name)
+
+ Called when the preprocessor checks whether a macro is defined or not and the
+ result is negative.
+
+ \sa passedMacroDefinitionCheck()
+*/
+
+/*!
+ \fn void Client::startExpandingMacro(unsigned offset, const Macro &macro, const QByteArray &originalText, bool inCondition = false, const QVector<MacroArgumentReference> &actuals = QVector<MacroArgumentReference>())
+
+ Called when starting to expand a macro. The parameter \a inCondition indicates whether the
+ expansion is happening inside a preprocessor conditional.
+
+ \sa stopExpandingMacro()
+*/
+
Client::Client()
{ }
diff --git a/src/libs/cplusplus/PreprocessorClient.h b/src/libs/cplusplus/PreprocessorClient.h
index 84cb0b73ac..d89ce71355 100644
--- a/src/libs/cplusplus/PreprocessorClient.h
+++ b/src/libs/cplusplus/PreprocessorClient.h
@@ -75,12 +75,14 @@ public:
virtual ~Client();
virtual void macroAdded(const Macro &macro) = 0;
- virtual void sourceNeeded(QString &fileName, IncludeType mode,
- unsigned line) = 0; // ### FIX the signature.
+
+ virtual void passedMacroDefinitionCheck(unsigned offset, const Macro &macro) = 0;
+ virtual void failedMacroDefinitionCheck(unsigned offset, const QByteArray &name) = 0;
virtual void startExpandingMacro(unsigned offset,
const Macro &macro,
const QByteArray &originalText,
+ bool inCondition = false,
const QVector<MacroArgumentReference> &actuals
= QVector<MacroArgumentReference>()) = 0;
@@ -89,6 +91,9 @@ public:
virtual void startSkippingBlocks(unsigned offset) = 0;
virtual void stopSkippingBlocks(unsigned offset) = 0;
+
+ virtual void sourceNeeded(QString &fileName, IncludeType mode,
+ unsigned line) = 0; // ### FIX the signature.
};
} // namespace CPlusPlus
diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp
index 347f4999d2..dcb6d49322 100644
--- a/src/libs/cplusplus/pp-engine.cpp
+++ b/src/libs/cplusplus/pp-engine.cpp
@@ -138,6 +138,18 @@ using namespace CPlusPlus;
namespace {
+bool isMacroDefined(QByteArray name, unsigned offset, Environment *env, Client *client)
+{
+ Macro *m = env->resolve(name);
+ if (client) {
+ if (m)
+ client->passedMacroDefinitionCheck(offset, *m);
+ else
+ client->failedMacroDefinitionCheck(offset, name);
+ }
+ return m != 0;
+}
+
class RangeLexer
{
const Token *first;
@@ -193,8 +205,8 @@ class ExpressionEvaluator
void operator = (const ExpressionEvaluator &other);
public:
- ExpressionEvaluator(Environment *env)
- : env(env), _lex(0)
+ ExpressionEvaluator(Client *client, Environment *env)
+ : client(client), env(env), _lex(0)
{ }
Value operator()(const Token *firstToken, const Token *lastToken,
@@ -255,13 +267,13 @@ protected:
} else if (isTokenDefined()) {
++(*_lex);
if ((*_lex)->is(T_IDENTIFIER)) {
- _value.set_long(env->resolve(tokenSpell()) != 0);
+ _value.set_long(isMacroDefined(tokenSpell(), (*_lex)->offset, env, client));
++(*_lex);
return true;
} else if ((*_lex)->is(T_LPAREN)) {
++(*_lex);
if ((*_lex)->is(T_IDENTIFIER)) {
- _value.set_long(env->resolve(tokenSpell()) != 0);
+ _value.set_long(isMacroDefined(tokenSpell(), (*_lex)->offset, env, client));
++(*_lex);
if ((*_lex)->is(T_RPAREN)) {
++(*_lex);
@@ -519,6 +531,7 @@ protected:
}
private:
+ Client *client;
Environment *env;
QByteArray source;
RangeLexer *_lex;
@@ -983,7 +996,7 @@ void Preprocessor::expandObjectLikeMacro(TokenIterator identifierToken,
{
if (client)
client->startExpandingMacro(identifierToken->offset,
- *m, spell);
+ *m, spell, false);
m->setHidden(true);
expand(m->definition(), result);
@@ -1007,7 +1020,7 @@ void Preprocessor::expandFunctionLikeMacro(TokenIterator identifierToken,
endOfText - beginOfText);
client->startExpandingMacro(identifierToken->offset,
- *m, text, actuals);
+ *m, text, false, actuals);
}
const bool was = markGeneratedTokens(true, identifierToken);
@@ -1253,7 +1266,7 @@ void Preprocessor::processIf(TokenIterator firstToken, TokenIterator lastToken)
const char *first = startOfToken(*tk);
const char *last = startOfToken(*lastToken);
- MacroExpander expandCondition (env);
+ MacroExpander expandCondition (env, 0, client, tk.dot()->offset);
QByteArray condition;
condition.reserve(256);
expandCondition(first, last, &condition);
@@ -1297,7 +1310,7 @@ void Preprocessor::processElif(TokenIterator firstToken, TokenIterator lastToken
const char *first = startOfToken(*tk);
const char *last = startOfToken(*lastToken);
- MacroExpander expandCondition (env);
+ MacroExpander expandCondition (env, 0, client, tk.dot()->offset);
QByteArray condition;
condition.reserve(256);
expandCondition(first, last, &condition);
@@ -1338,7 +1351,7 @@ void Preprocessor::processIfdef(bool checkUndefined,
if (testIfLevel()) {
if (tk->is(T_IDENTIFIER)) {
const QByteArray macroName = tokenSpell(*tk);
- bool value = env->resolve(macroName) != 0 || env->isBuiltinMacro(macroName);
+ bool value = isMacroDefined(macroName, tk->offset, env, client) || env->isBuiltinMacro(macroName);
if (checkUndefined)
value = ! value;
@@ -1437,7 +1450,7 @@ int Preprocessor::skipping() const
Value Preprocessor::evalExpression(TokenIterator firstToken, TokenIterator lastToken,
const QByteArray &source) const
{
- ExpressionEvaluator eval(env);
+ ExpressionEvaluator eval(client, env);
const Value result = eval(firstToken, lastToken, source);
return result;
}
diff --git a/src/libs/cplusplus/pp-macro-expander.cpp b/src/libs/cplusplus/pp-macro-expander.cpp
index 4902158c76..42be634562 100644
--- a/src/libs/cplusplus/pp-macro-expander.cpp
+++ b/src/libs/cplusplus/pp-macro-expander.cpp
@@ -66,9 +66,11 @@ inline static bool comment_p (const char *__first, const char *__last)
return (*__first == '/' || *__first == '*');
}
-MacroExpander::MacroExpander(Environment *env, pp_frame *frame)
+MacroExpander::MacroExpander(Environment *env, pp_frame *frame, Client *client, unsigned start_offset)
: env(env),
frame(frame),
+ client(client),
+ start_offset(start_offset),
lines(0)
{ }
@@ -97,6 +99,7 @@ const char *MacroExpander::operator()(const char *first, const char *last,
const char *MacroExpander::expand(const char *__first, const char *__last,
QByteArray *__result)
{
+ const char *start = __first;
__first = skip_blanks (__first, __last);
lines = skip_blanks.lines;
@@ -284,6 +287,9 @@ const char *MacroExpander::expand(const char *__first, const char *__last,
if (! macro->definition().isEmpty())
{
+ if (client)
+ client->startExpandingMacro(start_offset + (name_begin-start), *macro, fast_name, true);
+
macro->setHidden(true);
QByteArray __tmp;
@@ -310,6 +316,9 @@ const char *MacroExpander::expand(const char *__first, const char *__last,
}
macro->setHidden(false);
+
+ if (client)
+ client->stopExpandingMacro(start_offset + (name_begin-start), *macro);
}
if (! m)
@@ -330,6 +339,7 @@ const char *MacroExpander::expand(const char *__first, const char *__last,
}
QVector<QByteArray> actuals;
+ QVector<MacroArgumentReference> actuals_ref;
actuals.reserve (5);
++arg_it; // skip '('
@@ -338,6 +348,7 @@ const char *MacroExpander::expand(const char *__first, const char *__last,
const char *arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
if (arg_it != arg_end)
{
+ actuals_ref.append(MacroArgumentReference(start_offset + (arg_it-start), arg_end - arg_it));
const QByteArray actual (arg_it, arg_end - arg_it);
QByteArray expanded;
expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
@@ -350,6 +361,7 @@ const char *MacroExpander::expand(const char *__first, const char *__last,
++arg_it; // skip ','
arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ actuals_ref.append(MacroArgumentReference(start_offset + (arg_it-start), arg_end - arg_it));
const QByteArray actual (arg_it, arg_end - arg_it);
QByteArray expanded;
expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
@@ -363,11 +375,17 @@ const char *MacroExpander::expand(const char *__first, const char *__last,
++arg_it; // skip ')'
__first = arg_it;
+ if (client)
+ client->startExpandingMacro(start_offset + (name_begin-start), *macro, fast_name, true, actuals_ref);
+
pp_frame frame (macro, actuals);
MacroExpander expand_macro (env, &frame);
macro->setHidden(true);
expand_macro (macro->definition(), __result);
macro->setHidden(false);
+
+ if (client)
+ client->stopExpandingMacro(start_offset + (name_begin-start), *macro);
}
else
__result->append(*__first++);
diff --git a/src/libs/cplusplus/pp-macro-expander.h b/src/libs/cplusplus/pp-macro-expander.h
index f566ca809b..4f8730d2db 100644
--- a/src/libs/cplusplus/pp-macro-expander.h
+++ b/src/libs/cplusplus/pp-macro-expander.h
@@ -56,6 +56,7 @@
namespace CPlusPlus {
class Environment;
+class Client;
struct pp_frame;
@@ -63,6 +64,8 @@ class MacroExpander
{
Environment *env;
pp_frame *frame;
+ Client *client;
+ unsigned start_offset;
pp_skip_number skip_number;
pp_skip_identifier skip_identifier;
@@ -76,7 +79,7 @@ class MacroExpander
const QByteArray *resolve_formal(const QByteArray &name);
public:
- MacroExpander(Environment *env, pp_frame *frame = 0);
+ MacroExpander(Environment *env, pp_frame *frame = 0, Client *client = 0, unsigned start_offset = 0);
const char *operator()(const char *first, const char *last,
QByteArray *result);