summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorKevin Ottens <kevin.ottens.qnx@kdab.com>2012-08-01 13:38:03 (GMT)
committerQt by Nokia <qt-info@nokia.com>2012-08-08 16:31:29 (GMT)
commit7904bf24f7a41fbdce1a3febf6171d46b90521d0 (patch)
treed413037ac66dba1ba5954e2af62f212a8a02748b /tools
parent06f0d8a1a9a1d8d46e6f4f3894d76781dfb6638c (diff)
downloadQt-7904bf24f7a41fbdce1a3febf6171d46b90521d0.zip
Qt-7904bf24f7a41fbdce1a3febf6171d46b90521d0.tar.gz
Qt-7904bf24f7a41fbdce1a3febf6171d46b90521d0.tar.bz2
Properly handle include cycles
Currently lupdate is just issuing a warning when it detects an include cycle. Since it's not a full preprocessor, most of those warnings are false positives, but they need special handling, this patch provides that. Now every result is stored as part of a cycle (so in the general case a cycle of one file). When detecting a cycle, instead instead of issuing a warning, we record the presence of the newly detected cycle for later use and merge the other relevant cycles with it. When retrieving results now it's not for a single file anymore but for a complete cycle at once (which can turn out to be a cycle of one file). This is a backport of the commit done in qttools with revision 3b99677b3376924e347ec4aeb0c363438146bfde Task-number: QTBUG-6587 Change-Id: Idc79fbac4f69478ccff1464c1f4278d4afbf9d61 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/linguist/lupdate/cpp.cpp103
1 files changed, 75 insertions, 28 deletions
diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp
index 829a058..d787d26 100644
--- a/tools/linguist/lupdate/cpp.cpp
+++ b/tools/linguist/lupdate/cpp.cpp
@@ -177,21 +177,27 @@ struct ParseResults {
QSet<const ParseResults *> includes;
};
-typedef QHash<QString, const ParseResults *> ParseResultHash;
+struct IncludeCycle {
+ QSet<QString> fileNames;
+ QSet<const ParseResults *> results;
+};
+
+typedef QHash<QString, IncludeCycle *> IncludeCycleHash;
typedef QHash<QString, const Translator *> TranslatorHash;
class CppFiles {
public:
- static const ParseResults *getResults(const QString &cleanFile);
+ static QSet<const ParseResults *> getResults(const QString &cleanFile);
static void setResults(const QString &cleanFile, const ParseResults *results);
static const Translator *getTranslator(const QString &cleanFile);
static void setTranslator(const QString &cleanFile, const Translator *results);
static bool isBlacklisted(const QString &cleanFile);
static void setBlacklisted(const QString &cleanFile);
+ static void addIncludeCycle(const QSet<QString> &fileNames);
private:
- static ParseResultHash &parsedFiles();
+ static IncludeCycleHash &includeCycles();
static TranslatorHash &translatedFiles();
static QSet<QString> &blacklistedFiles();
};
@@ -203,8 +209,8 @@ public:
void setInput(const QString &in);
void setInput(QTextStream &ts, const QString &fileName);
void setTranslator(Translator *_tor) { tor = _tor; }
- void parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions);
- void parseInternal(ConversionData &cd, QSet<QString> &inclusions);
+ void parse(const QString &initialContext, ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions);
+ void parseInternal(ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions);
const ParseResults *recordResults(bool isHeader);
void deleteResults() { delete results; }
@@ -251,7 +257,7 @@ private:
bool utf8, bool plural);
void processInclude(const QString &file, ConversionData &cd,
- QSet<QString> &inclusions);
+ const QStringList &includeStack, QSet<QString> &inclusions);
void saveState(SavedState *state);
void loadState(const SavedState *state);
@@ -1253,11 +1259,11 @@ void CppParser::truncateNamespaces(NamespaceList *namespaces, int length)
Functions for processing include files.
*/
-ParseResultHash &CppFiles::parsedFiles()
+IncludeCycleHash &CppFiles::includeCycles()
{
- static ParseResultHash parsed;
+ static IncludeCycleHash cycles;
- return parsed;
+ return cycles;
}
TranslatorHash &CppFiles::translatedFiles()
@@ -1274,14 +1280,27 @@ QSet<QString> &CppFiles::blacklistedFiles()
return blacklisted;
}
-const ParseResults *CppFiles::getResults(const QString &cleanFile)
+QSet<const ParseResults *> CppFiles::getResults(const QString &cleanFile)
{
- return parsedFiles().value(cleanFile);
+ IncludeCycle * const cycle = includeCycles().value(cleanFile);
+
+ if (cycle)
+ return cycle->results;
+ else
+ return QSet<const ParseResults *>();
}
void CppFiles::setResults(const QString &cleanFile, const ParseResults *results)
{
- parsedFiles().insert(cleanFile, results);
+ IncludeCycle *cycle = includeCycles().value(cleanFile);
+
+ if (!cycle) {
+ cycle = new IncludeCycle;
+ includeCycles().insert(cleanFile, cycle);
+ }
+
+ cycle->fileNames.insert(cleanFile);
+ cycle->results.insert(results);
}
const Translator *CppFiles::getTranslator(const QString &cleanFile)
@@ -1304,19 +1323,42 @@ void CppFiles::setBlacklisted(const QString &cleanFile)
blacklistedFiles().insert(cleanFile);
}
+void CppFiles::addIncludeCycle(const QSet<QString> &fileNames)
+{
+ IncludeCycle * const cycle = new IncludeCycle;
+ cycle->fileNames = fileNames;
+
+ QSet<IncludeCycle *> intersectingCycles;
+ foreach (const QString &fileName, fileNames) {
+ IncludeCycle *intersectingCycle = includeCycles().value(fileName);
+
+ if (intersectingCycle && !intersectingCycles.contains(intersectingCycle)) {
+ intersectingCycles.insert(intersectingCycle);
+
+ cycle->fileNames.unite(intersectingCycle->fileNames);
+ cycle->results.unite(intersectingCycle->results);
+ }
+ }
+ qDeleteAll(intersectingCycles);
+
+ foreach (const QString &fileName, cycle->fileNames)
+ includeCycles().insert(fileName, cycle);
+}
+
static bool isHeader(const QString &name)
{
QString fileExt = QFileInfo(name).suffix();
return fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive);
}
-void CppParser::processInclude(const QString &file, ConversionData &cd,
+void CppParser::processInclude(const QString &file, ConversionData &cd, const QStringList &includeStack,
QSet<QString> &inclusions)
{
QString cleanFile = QDir::cleanPath(file);
- if (inclusions.contains(cleanFile)) {
- yyMsg() << qPrintable(LU::tr("circular inclusion of %1\n").arg(cleanFile));
+ const int index = includeStack.indexOf(cleanFile);
+ if (index != -1) {
+ CppFiles::addIncludeCycle(includeStack.mid(index).toSet());
return;
}
@@ -1330,8 +1372,9 @@ void CppParser::processInclude(const QString &file, ConversionData &cd,
&& !CppFiles::isBlacklisted(cleanFile)
&& isHeader(cleanFile)) {
- if (const ParseResults *res = CppFiles::getResults(cleanFile)) {
- results->includes.insert(res);
+ QSet<const ParseResults *> res = CppFiles::getResults(cleanFile);
+ if (!res.isEmpty()) {
+ results->includes.unite(res);
return;
}
@@ -1357,7 +1400,9 @@ void CppParser::processInclude(const QString &file, ConversionData &cd,
break;
}
parser.setInput(ts, cleanFile);
- parser.parse(cd.m_defaultContext, cd, inclusions);
+ QStringList stack = includeStack;
+ stack << cleanFile;
+ parser.parse(cd.m_defaultContext, cd, stack, inclusions);
results->includes.insert(parser.recordResults(true));
} else {
CppParser parser(results);
@@ -1366,7 +1411,9 @@ void CppParser::processInclude(const QString &file, ConversionData &cd,
parser.functionContextUnresolved = functionContextUnresolved;
parser.pendingContext = pendingContext;
parser.setInput(ts, cleanFile);
- parser.parseInternal(cd, inclusions);
+ QStringList stack = includeStack;
+ stack << cleanFile;
+ parser.parseInternal(cd, stack, inclusions);
// Avoid that messages obtained by direct scanning are used
CppFiles::setBlacklisted(cleanFile);
}
@@ -1548,7 +1595,7 @@ void CppParser::recordMessage(
tor->append(msg);
}
-void CppParser::parse(const QString &initialContext, ConversionData &cd,
+void CppParser::parse(const QString &initialContext, ConversionData &cd, const QStringList &includeStack,
QSet<QString> &inclusions)
{
if (tor)
@@ -1558,10 +1605,10 @@ void CppParser::parse(const QString &initialContext, ConversionData &cd,
functionContext = namespaces;
functionContextUnresolved = initialContext;
- parseInternal(cd, inclusions);
+ parseInternal(cd, includeStack, inclusions);
}
-void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
+void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStack, QSet<QString> &inclusions)
{
static QString strColons(QLatin1String("::"));
@@ -1597,7 +1644,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyWord);
text.detach();
if (QFileInfo(text).isFile()) {
- processInclude(text, cd, inclusions);
+ processInclude(text, cd, includeStack, inclusions);
yyTok = getToken();
break;
}
@@ -1607,14 +1654,14 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
QStringList cSources = cd.m_allCSources.values(yyWord);
if (!cSources.isEmpty()) {
foreach (const QString &cSource, cSources)
- processInclude(cSource, cd, inclusions);
+ processInclude(cSource, cd, includeStack, inclusions);
goto incOk;
}
foreach (const QString &incPath, cd.m_includePath) {
text = QDir(incPath).absoluteFilePath(yyWord);
text.detach();
if (QFileInfo(text).isFile()) {
- processInclude(text, cd, inclusions);
+ processInclude(text, cd, includeStack, inclusions);
goto incOk;
}
}
@@ -2200,7 +2247,7 @@ void fetchtrInlinedCpp(const QString &in, Translator &translator, const QString
ConversionData cd;
QSet<QString> inclusions;
parser.setTranslator(&translator);
- parser.parse(context, cd, inclusions);
+ parser.parse(context, cd, QStringList(), inclusions);
parser.deleteResults();
}
@@ -2211,7 +2258,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat
QTextCodec *codec = QTextCodec::codecForName(codecName);
foreach (const QString &filename, filenames) {
- if (CppFiles::getResults(filename) || CppFiles::isBlacklisted(filename))
+ if (!CppFiles::getResults(filename).isEmpty() || CppFiles::isBlacklisted(filename))
continue;
QFile file(filename);
@@ -2231,7 +2278,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat
tor->setCodecName(translator.codecName());
parser.setTranslator(tor);
QSet<QString> inclusions;
- parser.parse(cd.m_defaultContext, cd, inclusions);
+ parser.parse(cd.m_defaultContext, cd, QStringList(), inclusions);
parser.recordResults(isHeader(filename));
}