Commit 6a12f3b9 authored by Nikolai Kosjar's avatar Nikolai Kosjar

CppTools: Clean up CppSourceProcessor

This mostly makes sourceNeeded() a bit more readable.

Change-Id: I8da40090fb499837ec56276e7a4273211920c2d2
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent ec97d967
......@@ -10,6 +10,7 @@
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDir>
#include <QTextCodec>
/*!
......@@ -28,6 +29,56 @@ using namespace CPlusPlus;
using namespace CppTools;
using namespace CppTools::Internal;
typedef Document::DiagnosticMessage Message;
namespace {
inline QByteArray generateFingerPrint(const QList<Macro> &definedMacros, const QByteArray &code)
{
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(code);
foreach (const Macro &macro, definedMacros) {
if (macro.isHidden()) {
static const QByteArray undef("#undef ");
hash.addData(undef);
hash.addData(macro.name());
} else {
static const QByteArray def("#define ");
hash.addData(macro.name());
hash.addData(" ", 1);
hash.addData(def);
hash.addData(macro.definitionText());
}
hash.addData("\n", 1);
}
return hash.result();
}
inline Message messageNoSuchFile(Document::Ptr &document, const QString &fileName, unsigned line)
{
const QString text = QCoreApplication::translate(
"CppSourceProcessor", "%1: No such file or directory").arg(fileName);
return Message(Message::Warning, document->fileName(), line, /*column =*/ 0, text);
}
inline Message messageNoFileContents(Document::Ptr &document, const QString &fileName,
unsigned line)
{
const QString text = QCoreApplication::translate(
"CppSourceProcessor", "%1: Could not get file contents").arg(fileName);
return Message(Message::Warning, document->fileName(), line, /*column =*/ 0, text);
}
inline const Macro revision(const CppModelManagerInterface::WorkingCopy &workingCopy,
const Macro &macro)
{
Macro newMacro(macro);
newMacro.setFileRevision(workingCopy.get(macro.fileName()).second);
return newMacro;
}
} // anonymous namespace
CppSourceProcessor::CppSourceProcessor(QPointer<CppModelManager> modelManager,
bool dumpFileNameWhileParsing)
: m_snapshot(modelManager->snapshot()),
......@@ -125,37 +176,6 @@ void CppSourceProcessor::addFrameworkPath(const QString &frameworkPath)
void CppSourceProcessor::setTodo(const QStringList &files)
{ m_todo = QSet<QString>::fromList(files); }
namespace {
class Process: public std::unary_function<Document::Ptr, void>
{
QPointer<CppModelManager> _modelManager;
Document::Ptr _doc;
Document::CheckMode _mode;
public:
Process(QPointer<CppModelManager> modelManager,
Document::Ptr doc,
const CppModelManager::WorkingCopy &workingCopy)
: _modelManager(modelManager),
_doc(doc),
_mode(Document::FastCheck)
{
if (workingCopy.contains(_doc->fileName()))
_mode = Document::FullCheck;
}
void operator()()
{
_doc->check(_mode);
if (_modelManager) {
_modelManager->emitDocumentUpdated(_doc);
_doc->releaseSourceAndAST();
}
}
};
} // end of anonymous namespace
void CppSourceProcessor::run(const QString &fileName)
{
sourceNeeded(0, fileName, IncludeGlobal);
......@@ -284,14 +304,6 @@ void CppSourceProcessor::macroAdded(const Macro &macro)
m_currentDoc->appendMacro(macro);
}
static inline const Macro revision(const CppModelManagerInterface::WorkingCopy &s,
const Macro &macro)
{
Macro newMacro(macro);
newMacro.setFileRevision(s.get(macro.fileName()).second);
return newMacro;
}
void CppSourceProcessor::passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const Macro &macro)
{
......@@ -391,7 +403,6 @@ void CppSourceProcessor::stopSkippingBlocks(unsigned utf16charsOffset)
void CppSourceProcessor::sourceNeeded(unsigned line, const QString &fileName, IncludeType type)
{
typedef Document::DiagnosticMessage Message;
if (fileName.isEmpty())
return;
......@@ -400,22 +411,18 @@ void CppSourceProcessor::sourceNeeded(unsigned line, const QString &fileName, In
if (m_currentDoc) {
m_currentDoc->addIncludeFile(Document::Include(fileName, absoluteFileName, line, type));
if (absoluteFileName.isEmpty()) {
const QString text = QCoreApplication::translate(
"CppSourceProcessor", "%1: No such file or directory").arg(fileName);
Message message(Message::Warning, m_currentDoc->fileName(), line, /*column =*/ 0, text);
m_currentDoc->addDiagnosticMessage(message);
m_currentDoc->addDiagnosticMessage(messageNoSuchFile(m_currentDoc, fileName, line));
return;
}
}
if (m_included.contains(absoluteFileName))
return; // we've already seen this file.
return; // We've already seen this file.
if (absoluteFileName != modelManager()->configurationFileName())
m_included.insert(absoluteFileName);
// Already in snapshot? Use it!
Document::Ptr doc = m_snapshot.document(absoluteFileName);
if (doc) {
mergeEnvironment(doc);
if (Document::Ptr document = m_snapshot.document(absoluteFileName)) {
mergeEnvironment(document);
return;
}
......@@ -424,77 +431,56 @@ void CppSourceProcessor::sourceNeeded(unsigned line, const QString &fileName, In
QByteArray contents;
const bool gotFileContents = getFileContents(absoluteFileName, &contents, &editorRevision);
if (m_currentDoc && !gotFileContents) {
const QString text = QCoreApplication::translate(
"CppSourceProcessor", "%1: Could not get file contents").arg(fileName);
Message message(Message::Warning, m_currentDoc->fileName(), line, /*column =*/ 0, text);
m_currentDoc->addDiagnosticMessage(message);
m_currentDoc->addDiagnosticMessage(messageNoFileContents(m_currentDoc, fileName, line));
return;
}
if (m_dumpFileNameWhileParsing) {
qDebug() << "Parsing file:" << absoluteFileName
<< "contents:" << contents.size() << "bytes";
}
doc = Document::create(absoluteFileName);
doc->setRevision(m_revision);
doc->setEditorRevision(editorRevision);
if (m_dumpFileNameWhileParsing)
qDebug() << "Parsing:" << absoluteFileName << "contents:" << contents.size() << "bytes";
Document::Ptr document = Document::create(absoluteFileName);
document->setRevision(m_revision);
document->setEditorRevision(editorRevision);
const QFileInfo info(absoluteFileName);
if (info.exists())
doc->setLastModified(info.lastModified());
const Document::Ptr previousDoc = switchDocument(doc);
document->setLastModified(info.lastModified());
const Document::Ptr previousDocument = switchCurrentDocument(document);
const QByteArray preprocessedCode = m_preprocess.run(absoluteFileName, contents);
// {
// QByteArray b(preprocessedCode);
// b.replace("\n", "<<<\n");
// qDebug("Preprocessed code for \"%s\": [[%s]]", fileName.toUtf8().constData(),
// b.constData());
// QByteArray b(preprocessedCode); b.replace("\n", "<<<\n");
// qDebug("Preprocessed code for \"%s\": [[%s]]", fileName.toUtf8().constData(), b.constData());
// }
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(preprocessedCode);
foreach (const Macro &macro, doc->definedMacros()) {
if (macro.isHidden()) {
static const QByteArray undef("#undef ");
hash.addData(undef);
hash.addData(macro.name());
} else {
static const QByteArray def("#define ");
hash.addData(macro.name());
hash.addData(" ", 1);
hash.addData(def);
hash.addData(macro.definitionText());
}
hash.addData("\n", 1);
}
doc->setFingerprint(hash.result());
Document::Ptr anotherDoc = m_globalSnapshot.document(absoluteFileName);
if (anotherDoc && anotherDoc->fingerprint() == doc->fingerprint()) {
switchDocument(previousDoc);
mergeEnvironment(anotherDoc);
m_snapshot.insert(anotherDoc);
document->setFingerprint(generateFingerPrint(document->definedMacros(), preprocessedCode));
// Re-use document from global snapshot if possible
Document::Ptr globalDocument = m_globalSnapshot.document(absoluteFileName);
if (globalDocument && globalDocument->fingerprint() == document->fingerprint()) {
switchCurrentDocument(previousDocument);
mergeEnvironment(globalDocument);
m_snapshot.insert(globalDocument);
m_todo.remove(absoluteFileName);
return;
}
doc->setUtf8Source(preprocessedCode);
doc->keepSourceAndAST();
doc->tokenize();
// Otherwise process the document
document->setUtf8Source(preprocessedCode);
document->keepSourceAndAST();
document->tokenize();
document->check(m_workingCopy.contains(document->fileName()) ? Document::FullCheck
: Document::FastCheck);
m_snapshot.insert(doc);
m_todo.remove(absoluteFileName);
Process process(m_modelManager, doc, m_workingCopy);
process();
if (m_modelManager) {
m_modelManager->emitDocumentUpdated(document);
document->releaseSourceAndAST();
}
(void) switchDocument(previousDoc);
m_snapshot.insert(document);
m_todo.remove(absoluteFileName);
switchCurrentDocument(previousDocument);
}
Document::Ptr CppSourceProcessor::switchDocument(Document::Ptr doc)
Document::Ptr CppSourceProcessor::switchCurrentDocument(Document::Ptr doc)
{
const Document::Ptr previousDoc = m_currentDoc;
m_currentDoc = doc;
......
......@@ -5,9 +5,12 @@
#include <cplusplus/PreprocessorEnvironment.h>
#include <cplusplus/pp-engine.h>
#include <utils/qtcoverride.h>
#include <QHash>
#include <QPointer>
#include <QSet>
#include <QStringList>
QT_BEGIN_NAMESPACE
class QTextCodec;
......@@ -29,7 +32,7 @@ public:
CppSourceProcessor(QPointer<CppModelManager> modelManager, bool dumpFileNameWhileParsing = false);
CppSourceProcessor(QPointer<CppModelManager> modelManager, const CPlusPlus::Snapshot &snapshot,
bool dumpFileNameWhileParsing = false);
virtual ~CppSourceProcessor();
~CppSourceProcessor();
void setRevision(unsigned revision);
void setWorkingCopy(const CppTools::CppModelManagerInterface::WorkingCopy &workingCopy);
......@@ -41,19 +44,17 @@ public:
void removeFromCache(const QString &fileName);
void resetEnvironment();
CPlusPlus::Snapshot snapshot() const
{ return m_snapshot; }
const QSet<QString> &todo() const
{ return m_todo; }
CppModelManager *modelManager() const
{ return m_modelManager.data(); }
CPlusPlus::Snapshot snapshot() const { return m_snapshot; }
const QSet<QString> &todo() const { return m_todo; }
CppModelManager *modelManager() const { return m_modelManager.data(); }
void setGlobalSnapshot(const CPlusPlus::Snapshot &snapshot) { m_globalSnapshot = snapshot; }
protected:
CPlusPlus::Document::Ptr switchDocument(CPlusPlus::Document::Ptr doc);
private:
CppSourceProcessor();
void addFrameworkPath(const QString &frameworkPath);
CPlusPlus::Document::Ptr switchCurrentDocument(CPlusPlus::Document::Ptr doc);
bool getFileContents(const QString &absoluteFilePath, QByteArray *contents,
unsigned *revision) const;
......@@ -63,28 +64,24 @@ protected:
void mergeEnvironment(CPlusPlus::Document::Ptr doc);
virtual void macroAdded(const CPlusPlus::Macro &macro);
virtual void passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const CPlusPlus::Macro &macro);
virtual void failedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charOffset,
const CPlusPlus::ByteArrayRef &name);
virtual void notifyMacroReference(unsigned bytesOffset, unsigned utf16charOffset,
unsigned line, const CPlusPlus::Macro &macro);
virtual void startExpandingMacro(unsigned bytesOffset,
unsigned utf16charOffset,
unsigned line,
const CPlusPlus::Macro &macro,
const QVector<CPlusPlus::MacroArgumentReference> &actuals);
virtual void stopExpandingMacro(unsigned bytesOffset, const CPlusPlus::Macro &macro);
virtual void markAsIncludeGuard(const QByteArray &macroName);
virtual void startSkippingBlocks(unsigned utf16charsOffset);
virtual void stopSkippingBlocks(unsigned utf16charsOffset);
virtual void sourceNeeded(unsigned line, const QString &fileName, IncludeType type);
// Client interface
void macroAdded(const CPlusPlus::Macro &macro) QTC_OVERRIDE;
void passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
unsigned line, const CPlusPlus::Macro &macro) QTC_OVERRIDE;
void failedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charOffset,
const CPlusPlus::ByteArrayRef &name) QTC_OVERRIDE;
void notifyMacroReference(unsigned bytesOffset, unsigned utf16charOffset,
unsigned line, const CPlusPlus::Macro &macro) QTC_OVERRIDE;
void startExpandingMacro(unsigned bytesOffset, unsigned utf16charOffset,
unsigned line, const CPlusPlus::Macro &macro,
const QVector<CPlusPlus::MacroArgumentReference> &actuals) QTC_OVERRIDE;
void stopExpandingMacro(unsigned bytesOffset, const CPlusPlus::Macro &macro) QTC_OVERRIDE;
void markAsIncludeGuard(const QByteArray &macroName) QTC_OVERRIDE;
void startSkippingBlocks(unsigned utf16charsOffset) QTC_OVERRIDE;
void stopSkippingBlocks(unsigned utf16charsOffset) QTC_OVERRIDE;
void sourceNeeded(unsigned line, const QString &fileName, IncludeType type) QTC_OVERRIDE;
private:
CppSourceProcessor();
void addFrameworkPath(const QString &frameworkPath);
CPlusPlus::Snapshot m_snapshot;
CPlusPlus::Snapshot m_globalSnapshot;
QPointer<CppModelManager> m_modelManager;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment