2014-08-22 08:42:04 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-08-22 08:42:04 +02:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2014-08-22 08:42:04 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2014-08-22 08:42:04 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
#include "cppsourceprocessor.h"
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2013-07-08 16:57:17 +02:00
|
|
|
#include "cppmodelmanager.h"
|
2015-05-12 14:20:32 +02:00
|
|
|
#include "cpptoolsreuse.h"
|
2013-07-08 16:57:17 +02:00
|
|
|
|
2013-11-14 10:59:46 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
|
|
|
|
|
|
|
|
#include <utils/fileutils.h>
|
2013-04-23 15:04:36 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2014-06-25 17:23:19 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2013-08-19 15:47:51 +02:00
|
|
|
#include <utils/textfileformat.h>
|
2013-04-23 15:04:36 +02:00
|
|
|
|
|
|
|
|
#include <QCoreApplication>
|
2013-08-19 16:05:29 +02:00
|
|
|
#include <QCryptographicHash>
|
2014-05-16 16:09:26 -04:00
|
|
|
#include <QDir>
|
2014-10-23 12:39:59 +02:00
|
|
|
#include <QLoggingCategory>
|
2013-11-14 10:59:46 +01:00
|
|
|
#include <QTextCodec>
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2013-05-26 10:57:41 +04:00
|
|
|
/*!
|
2014-05-16 15:51:04 -04:00
|
|
|
* \class CppTools::Internal::CppSourceProcessor
|
|
|
|
|
* \brief The CppSourceProcessor class updates set of indexed C++ files.
|
2013-05-26 10:57:41 +04:00
|
|
|
*
|
2014-06-06 14:41:19 +02:00
|
|
|
* Working copy ensures that documents with most recent copy placed in memory will be parsed
|
|
|
|
|
* correctly.
|
2013-05-26 10:57:41 +04:00
|
|
|
*
|
|
|
|
|
* \sa CPlusPlus::Document
|
2014-07-30 16:29:02 +02:00
|
|
|
* \sa CppTools::WorkingCopy
|
2013-05-26 10:57:41 +04:00
|
|
|
*/
|
|
|
|
|
|
2013-04-23 15:04:36 +02:00
|
|
|
using namespace CPlusPlus;
|
|
|
|
|
using namespace CppTools;
|
|
|
|
|
using namespace CppTools::Internal;
|
|
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
typedef Document::DiagnosticMessage Message;
|
|
|
|
|
|
2014-10-23 12:39:59 +02:00
|
|
|
static Q_LOGGING_CATEGORY(log, "qtc.cpptools.sourceprocessor")
|
|
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
inline QByteArray generateFingerPrint(const QList<Macro> &definedMacros, const QByteArray &code)
|
|
|
|
|
{
|
|
|
|
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
|
|
|
|
hash.addData(code);
|
|
|
|
|
foreach (const Macro ¯o, 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);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-30 16:29:02 +02:00
|
|
|
inline const Macro revision(const WorkingCopy &workingCopy,
|
2014-05-16 16:09:26 -04:00
|
|
|
const Macro ¯o)
|
|
|
|
|
{
|
|
|
|
|
Macro newMacro(macro);
|
|
|
|
|
newMacro.setFileRevision(workingCopy.get(macro.fileName()).second);
|
|
|
|
|
return newMacro;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
2014-06-06 14:41:19 +02:00
|
|
|
CppSourceProcessor::CppSourceProcessor(const Snapshot &snapshot, DocumentCallback documentFinished)
|
2013-08-19 16:05:29 +02:00
|
|
|
: m_snapshot(snapshot),
|
2014-06-06 14:41:19 +02:00
|
|
|
m_documentFinished(documentFinished),
|
2013-08-19 16:05:29 +02:00
|
|
|
m_preprocess(this, &m_env),
|
2015-02-15 23:43:26 +02:00
|
|
|
m_languageFeatures(LanguageFeatures::defaultFeatures()),
|
2013-11-14 10:59:46 +01:00
|
|
|
m_defaultCodec(Core::EditorManager::defaultTextCodec())
|
2013-08-19 16:05:29 +02:00
|
|
|
{
|
|
|
|
|
m_preprocess.setKeepComments(true);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
CppSourceProcessor::~CppSourceProcessor()
|
2013-04-23 15:04:36 +02:00
|
|
|
{ }
|
|
|
|
|
|
2016-07-27 14:48:42 +02:00
|
|
|
void CppSourceProcessor::setCancelChecker(const CppSourceProcessor::CancelChecker &cancelChecker)
|
|
|
|
|
{
|
|
|
|
|
m_preprocess.setCancelChecker(cancelChecker);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-30 16:29:02 +02:00
|
|
|
void CppSourceProcessor::setWorkingCopy(const WorkingCopy &workingCopy)
|
2013-04-23 15:04:36 +02:00
|
|
|
{ m_workingCopy = workingCopy; }
|
|
|
|
|
|
2016-01-13 14:12:15 +01:00
|
|
|
void CppSourceProcessor::setHeaderPaths(const ProjectPartHeaderPaths &headerPaths)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2014-06-25 17:23:19 +02:00
|
|
|
m_headerPaths.clear();
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-06-25 17:23:19 +02:00
|
|
|
for (int i = 0, ei = headerPaths.size(); i < ei; ++i) {
|
2016-01-13 14:12:15 +01:00
|
|
|
const ProjectPartHeaderPath &path = headerPaths.at(i);
|
2014-06-25 17:23:19 +02:00
|
|
|
|
2016-01-13 14:12:15 +01:00
|
|
|
if (path.type == ProjectPartHeaderPath::IncludePath)
|
|
|
|
|
m_headerPaths.append(ProjectPartHeaderPath(cleanPath(path.path), path.type));
|
2014-06-25 17:23:19 +02:00
|
|
|
else
|
|
|
|
|
addFrameworkPath(path);
|
|
|
|
|
}
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-15 23:43:26 +02:00
|
|
|
void CppSourceProcessor::setLanguageFeatures(const LanguageFeatures languageFeatures)
|
|
|
|
|
{
|
|
|
|
|
m_languageFeatures = languageFeatures;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-23 15:04:36 +02:00
|
|
|
// Add the given framework path, and expand private frameworks.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
// <framework-path>/ApplicationServices.framework
|
|
|
|
|
// has private frameworks in:
|
|
|
|
|
// <framework-path>/ApplicationServices.framework/Frameworks
|
|
|
|
|
// if the "Frameworks" folder exists inside the top level framework.
|
2016-01-13 14:12:15 +01:00
|
|
|
void CppSourceProcessor::addFrameworkPath(const ProjectPartHeaderPath &frameworkPath)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2014-06-25 17:23:19 +02:00
|
|
|
QTC_ASSERT(frameworkPath.isFrameworkPath(), return);
|
|
|
|
|
|
2013-04-23 15:04:36 +02:00
|
|
|
// The algorithm below is a bit too eager, but that's because we're not getting
|
|
|
|
|
// in the frameworks we're linking against. If we would have that, then we could
|
|
|
|
|
// add only those private frameworks.
|
2016-01-13 14:12:15 +01:00
|
|
|
const ProjectPartHeaderPath cleanFrameworkPath(cleanPath(frameworkPath.path),
|
|
|
|
|
frameworkPath.type);
|
2014-06-25 17:23:19 +02:00
|
|
|
if (!m_headerPaths.contains(cleanFrameworkPath))
|
|
|
|
|
m_headerPaths.append(cleanFrameworkPath);
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-06-25 17:23:19 +02:00
|
|
|
const QDir frameworkDir(cleanFrameworkPath.path);
|
2013-04-23 15:04:36 +02:00
|
|
|
const QStringList filter = QStringList() << QLatin1String("*.framework");
|
|
|
|
|
foreach (const QFileInfo &framework, frameworkDir.entryInfoList(filter)) {
|
|
|
|
|
if (!framework.isDir())
|
|
|
|
|
continue;
|
2013-07-08 16:57:17 +02:00
|
|
|
const QFileInfo privateFrameworks(framework.absoluteFilePath(),
|
|
|
|
|
QLatin1String("Frameworks"));
|
2013-04-23 15:04:36 +02:00
|
|
|
if (privateFrameworks.exists() && privateFrameworks.isDir())
|
2016-01-13 14:12:15 +01:00
|
|
|
addFrameworkPath(ProjectPartHeaderPath(privateFrameworks.absoluteFilePath(),
|
|
|
|
|
frameworkPath.type));
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-04 14:59:50 +02:00
|
|
|
void CppSourceProcessor::setTodo(const QSet<QString> &files)
|
|
|
|
|
{
|
|
|
|
|
m_todo = files;
|
|
|
|
|
}
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-07-16 11:25:15 +02:00
|
|
|
void CppSourceProcessor::run(const QString &fileName,
|
|
|
|
|
const QStringList &initialIncludes)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2014-07-16 11:25:15 +02:00
|
|
|
sourceNeeded(0, fileName, IncludeGlobal, initialIncludes);
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::removeFromCache(const QString &fileName)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
m_snapshot.remove(fileName);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::resetEnvironment()
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
m_env.reset();
|
|
|
|
|
m_processed.clear();
|
2013-05-15 11:45:30 +02:00
|
|
|
m_included.clear();
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
bool CppSourceProcessor::getFileContents(const QString &absoluteFilePath,
|
|
|
|
|
QByteArray *contents,
|
|
|
|
|
unsigned *revision) const
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2014-02-19 09:11:59 -03:00
|
|
|
if (absoluteFilePath.isEmpty() || !contents || !revision)
|
|
|
|
|
return false;
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-02-19 09:11:59 -03:00
|
|
|
// Get from working copy
|
2013-04-23 15:04:36 +02:00
|
|
|
if (m_workingCopy.contains(absoluteFilePath)) {
|
2013-08-19 15:47:51 +02:00
|
|
|
const QPair<QByteArray, unsigned> entry = m_workingCopy.get(absoluteFilePath);
|
2014-02-19 09:11:59 -03:00
|
|
|
*contents = entry.first;
|
|
|
|
|
*revision = entry.second;
|
|
|
|
|
return true;
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-19 09:11:59 -03:00
|
|
|
// Get from file
|
|
|
|
|
*revision = 0;
|
|
|
|
|
QString error;
|
|
|
|
|
if (Utils::TextFileFormat::readFileUTF8(absoluteFilePath, m_defaultCodec, contents, &error)
|
|
|
|
|
!= Utils::TextFileFormat::ReadSuccess) {
|
|
|
|
|
qWarning("Error reading file \"%s\": \"%s\".", qPrintable(absoluteFilePath),
|
|
|
|
|
qPrintable(error));
|
|
|
|
|
return false;
|
2013-11-14 10:59:46 +01:00
|
|
|
}
|
2014-02-19 09:11:59 -03:00
|
|
|
return true;
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
bool CppSourceProcessor::checkFile(const QString &absoluteFilePath) const
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2014-03-21 10:13:31 -03:00
|
|
|
if (absoluteFilePath.isEmpty()
|
|
|
|
|
|| m_included.contains(absoluteFilePath)
|
|
|
|
|
|| m_workingCopy.contains(absoluteFilePath)) {
|
2013-04-23 15:04:36 +02:00
|
|
|
return true;
|
2014-03-21 10:13:31 -03:00
|
|
|
}
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2013-07-08 16:57:17 +02:00
|
|
|
const QFileInfo fileInfo(absoluteFilePath);
|
2013-04-23 15:04:36 +02:00
|
|
|
return fileInfo.isFile() && fileInfo.isReadable();
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
QString CppSourceProcessor::cleanPath(const QString &path)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
QString result = QDir::cleanPath(path);
|
|
|
|
|
const QChar slash(QLatin1Char('/'));
|
|
|
|
|
if (!result.endsWith(slash))
|
|
|
|
|
result.append(slash);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 15:10:28 +01:00
|
|
|
/// Resolve the given file name to its absolute path w.r.t. the include type.
|
|
|
|
|
QString CppSourceProcessor::resolveFile(const QString &fileName, IncludeType type)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2014-02-24 12:12:14 -03:00
|
|
|
if (isInjectedFile(fileName))
|
2013-04-23 15:04:36 +02:00
|
|
|
return fileName;
|
|
|
|
|
|
2014-02-24 12:12:14 -03:00
|
|
|
if (QFileInfo(fileName).isAbsolute())
|
|
|
|
|
return checkFile(fileName) ? fileName : QString();
|
|
|
|
|
|
2014-12-05 11:56:06 +01:00
|
|
|
if (m_currentDoc) {
|
|
|
|
|
if (type == IncludeLocal) {
|
|
|
|
|
const QFileInfo currentFileInfo(m_currentDoc->fileName());
|
|
|
|
|
const QString path = cleanPath(currentFileInfo.absolutePath()) + fileName;
|
|
|
|
|
if (checkFile(path))
|
|
|
|
|
return path;
|
|
|
|
|
// Fall through! "16.2 Source file inclusion" from the standard states to continue
|
|
|
|
|
// searching as if this would be a global include.
|
|
|
|
|
|
|
|
|
|
} else if (type == IncludeNext) {
|
|
|
|
|
const QFileInfo currentFileInfo(m_currentDoc->fileName());
|
|
|
|
|
const QString currentDirPath = cleanPath(currentFileInfo.dir().path());
|
2016-03-11 15:10:28 +01:00
|
|
|
auto headerPathsEnd = m_headerPaths.end();
|
|
|
|
|
auto headerPathsIt = m_headerPaths.begin();
|
2014-12-05 11:56:06 +01:00
|
|
|
for (; headerPathsIt != headerPathsEnd; ++headerPathsIt) {
|
|
|
|
|
if (headerPathsIt->path == currentDirPath) {
|
|
|
|
|
++headerPathsIt;
|
2016-03-11 15:10:28 +01:00
|
|
|
return resolveFile_helper(fileName, headerPathsIt);
|
2014-12-05 11:56:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-11 15:10:28 +01:00
|
|
|
QHash<QString, QString>::ConstIterator it = m_fileNameCache.constFind(fileName);
|
|
|
|
|
if (it != m_fileNameCache.constEnd())
|
|
|
|
|
return it.value();
|
|
|
|
|
const QString fn = resolveFile_helper(fileName, m_headerPaths.begin());
|
|
|
|
|
if (!fn.isEmpty())
|
|
|
|
|
m_fileNameCache.insert(fileName, fn);
|
|
|
|
|
return fn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString CppSourceProcessor::resolveFile_helper(const QString &fileName,
|
|
|
|
|
ProjectPartHeaderPaths::Iterator headerPathsIt)
|
|
|
|
|
{
|
|
|
|
|
auto headerPathsEnd = m_headerPaths.end();
|
2013-07-08 16:57:17 +02:00
|
|
|
const int index = fileName.indexOf(QLatin1Char('/'));
|
2016-05-31 10:35:56 +02:00
|
|
|
for (; headerPathsIt != headerPathsEnd; ++headerPathsIt) {
|
|
|
|
|
if (headerPathsIt->isValid()) {
|
|
|
|
|
QString path;
|
|
|
|
|
if (headerPathsIt->isFrameworkPath()) {
|
|
|
|
|
if (index == -1)
|
|
|
|
|
continue;
|
|
|
|
|
path = headerPathsIt->path + fileName.left(index)
|
|
|
|
|
+ QLatin1String(".framework/Headers/") + fileName.mid(index + 1);
|
|
|
|
|
} else {
|
|
|
|
|
path = headerPathsIt->path + fileName;
|
|
|
|
|
}
|
|
|
|
|
if (m_workingCopy.contains(path) || checkFile(path))
|
2013-04-23 15:04:36 +02:00
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::macroAdded(const Macro ¯o)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!m_currentDoc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_currentDoc->appendMacro(macro);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::passedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charsOffset,
|
|
|
|
|
unsigned line, const Macro ¯o)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!m_currentDoc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
|
2014-05-09 10:04:13 -04:00
|
|
|
m_currentDoc->addMacroUse(revision(m_workingCopy, macro),
|
|
|
|
|
bytesOffset, macro.name().length(),
|
|
|
|
|
utf16charsOffset, macro.nameToQString().size(),
|
|
|
|
|
line, QVector<MacroArgumentReference>());
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::failedMacroDefinitionCheck(unsigned bytesOffset, unsigned utf16charOffset,
|
|
|
|
|
const ByteArrayRef &name)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!m_currentDoc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
|
2014-05-09 10:04:13 -04:00
|
|
|
m_currentDoc->addUndefinedMacroUse(QByteArray(name.start(), name.size()),
|
|
|
|
|
bytesOffset, utf16charOffset);
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::notifyMacroReference(unsigned bytesOffset, unsigned utf16charOffset,
|
|
|
|
|
unsigned line, const Macro ¯o)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!m_currentDoc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
|
2014-05-09 10:04:13 -04:00
|
|
|
m_currentDoc->addMacroUse(revision(m_workingCopy, macro),
|
|
|
|
|
bytesOffset, macro.name().length(),
|
|
|
|
|
utf16charOffset, macro.nameToQString().size(),
|
|
|
|
|
line, QVector<MacroArgumentReference>());
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::startExpandingMacro(unsigned bytesOffset, unsigned utf16charOffset,
|
|
|
|
|
unsigned line, const Macro ¯o,
|
|
|
|
|
const QVector<MacroArgumentReference> &actuals)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!m_currentDoc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
|
2014-05-09 10:04:13 -04:00
|
|
|
m_currentDoc->addMacroUse(revision(m_workingCopy, macro),
|
|
|
|
|
bytesOffset, macro.name().length(),
|
|
|
|
|
utf16charOffset, macro.nameToQString().size(),
|
|
|
|
|
line, actuals);
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::stopExpandingMacro(unsigned, const Macro &)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!m_currentDoc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::markAsIncludeGuard(const QByteArray ¯oName)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
if (!m_currentDoc)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_currentDoc->setIncludeGuardMacroName(macroName);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::mergeEnvironment(Document::Ptr doc)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-24 11:59:39 +02:00
|
|
|
if (!doc)
|
2013-04-23 15:04:36 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const QString fn = doc->fileName();
|
|
|
|
|
|
|
|
|
|
if (m_processed.contains(fn))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_processed.insert(fn);
|
|
|
|
|
|
2013-07-25 11:21:31 +02:00
|
|
|
foreach (const Document::Include &incl, doc->resolvedIncludes()) {
|
2013-07-08 16:57:17 +02:00
|
|
|
const QString includedFile = incl.resolvedFileName();
|
2013-04-23 15:04:36 +02:00
|
|
|
|
|
|
|
|
if (Document::Ptr includedDoc = m_snapshot.document(includedFile))
|
|
|
|
|
mergeEnvironment(includedDoc);
|
2014-02-19 11:39:06 -03:00
|
|
|
else if (!m_included.contains(includedFile))
|
2013-04-23 15:04:36 +02:00
|
|
|
run(includedFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_env.addMacros(doc->definedMacros());
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::startSkippingBlocks(unsigned utf16charsOffset)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
if (m_currentDoc)
|
2014-05-09 10:04:13 -04:00
|
|
|
m_currentDoc->startSkippingBlocks(utf16charsOffset);
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-05-16 15:51:04 -04:00
|
|
|
void CppSourceProcessor::stopSkippingBlocks(unsigned utf16charsOffset)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
if (m_currentDoc)
|
2014-05-09 10:04:13 -04:00
|
|
|
m_currentDoc->stopSkippingBlocks(utf16charsOffset);
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-16 11:25:15 +02:00
|
|
|
void CppSourceProcessor::sourceNeeded(unsigned line, const QString &fileName, IncludeType type,
|
|
|
|
|
const QStringList &initialIncludes)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
|
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QString absoluteFileName = resolveFile(fileName, type);
|
|
|
|
|
absoluteFileName = QDir::cleanPath(absoluteFileName);
|
2014-02-19 09:11:59 -03:00
|
|
|
if (m_currentDoc) {
|
2013-06-06 09:35:40 +02:00
|
|
|
m_currentDoc->addIncludeFile(Document::Include(fileName, absoluteFileName, line, type));
|
2014-02-19 09:11:59 -03:00
|
|
|
if (absoluteFileName.isEmpty()) {
|
2014-05-16 16:09:26 -04:00
|
|
|
m_currentDoc->addDiagnosticMessage(messageNoSuchFile(m_currentDoc, fileName, line));
|
2014-02-19 09:11:59 -03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-04-23 15:04:36 +02:00
|
|
|
if (m_included.contains(absoluteFileName))
|
2014-05-16 16:09:26 -04:00
|
|
|
return; // We've already seen this file.
|
2014-06-06 14:41:19 +02:00
|
|
|
if (!isInjectedFile(absoluteFileName))
|
2013-04-23 15:04:36 +02:00
|
|
|
m_included.insert(absoluteFileName);
|
|
|
|
|
|
2014-03-05 16:58:19 -03:00
|
|
|
// Already in snapshot? Use it!
|
2014-05-16 16:09:26 -04:00
|
|
|
if (Document::Ptr document = m_snapshot.document(absoluteFileName)) {
|
|
|
|
|
mergeEnvironment(document);
|
2014-03-05 16:58:19 -03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-12 14:20:32 +02:00
|
|
|
const QFileInfo info(absoluteFileName);
|
2016-08-16 13:37:49 +02:00
|
|
|
if (fileSizeExceedsLimit(info, m_fileSizeLimitInMb))
|
2015-05-12 14:20:32 +02:00
|
|
|
return; // TODO: Add diagnostic message
|
|
|
|
|
|
2014-03-05 16:58:19 -03:00
|
|
|
// Otherwise get file contents
|
2013-04-23 15:04:36 +02:00
|
|
|
unsigned editorRevision = 0;
|
2013-08-19 15:47:51 +02:00
|
|
|
QByteArray contents;
|
2014-02-19 09:11:59 -03:00
|
|
|
const bool gotFileContents = getFileContents(absoluteFileName, &contents, &editorRevision);
|
|
|
|
|
if (m_currentDoc && !gotFileContents) {
|
2014-05-16 16:09:26 -04:00
|
|
|
m_currentDoc->addDiagnosticMessage(messageNoFileContents(m_currentDoc, fileName, line));
|
2014-02-19 09:11:59 -03:00
|
|
|
return;
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-23 12:39:59 +02:00
|
|
|
qCDebug(log) << "Parsing:" << absoluteFileName << "contents:" << contents.size() << "bytes";
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
Document::Ptr document = Document::create(absoluteFileName);
|
|
|
|
|
document->setEditorRevision(editorRevision);
|
2015-02-15 23:43:26 +02:00
|
|
|
document->setLanguageFeatures(m_languageFeatures);
|
2014-07-16 11:25:15 +02:00
|
|
|
foreach (const QString &include, initialIncludes) {
|
|
|
|
|
m_included.insert(include);
|
|
|
|
|
Document::Include inc(include, include, 0, IncludeLocal);
|
|
|
|
|
document->addIncludeFile(inc);
|
|
|
|
|
}
|
2013-04-23 15:04:36 +02:00
|
|
|
if (info.exists())
|
2014-05-16 16:09:26 -04:00
|
|
|
document->setLastModified(info.lastModified());
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
const Document::Ptr previousDocument = switchCurrentDocument(document);
|
2013-04-23 15:04:36 +02:00
|
|
|
const QByteArray preprocessedCode = m_preprocess.run(absoluteFileName, contents);
|
2013-07-08 16:57:17 +02:00
|
|
|
// {
|
2014-05-16 16:09:26 -04:00
|
|
|
// QByteArray b(preprocessedCode); b.replace("\n", "<<<\n");
|
|
|
|
|
// qDebug("Preprocessed code for \"%s\": [[%s]]", fileName.toUtf8().constData(), b.constData());
|
2013-07-08 16:57:17 +02:00
|
|
|
// }
|
2014-05-16 16:09:26 -04:00
|
|
|
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);
|
2013-08-19 16:05:29 +02:00
|
|
|
m_todo.remove(absoluteFileName);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
// Otherwise process the document
|
|
|
|
|
document->setUtf8Source(preprocessedCode);
|
|
|
|
|
document->keepSourceAndAST();
|
|
|
|
|
document->tokenize();
|
|
|
|
|
document->check(m_workingCopy.contains(document->fileName()) ? Document::FullCheck
|
|
|
|
|
: Document::FastCheck);
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-06-06 14:41:19 +02:00
|
|
|
m_documentFinished(document);
|
2013-04-23 15:04:36 +02:00
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
m_snapshot.insert(document);
|
|
|
|
|
m_todo.remove(absoluteFileName);
|
|
|
|
|
switchCurrentDocument(previousDocument);
|
2013-04-23 15:04:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-16 13:37:49 +02:00
|
|
|
void CppSourceProcessor::setFileSizeLimitInMb(int fileSizeLimitInMb)
|
|
|
|
|
{
|
|
|
|
|
m_fileSizeLimitInMb = fileSizeLimitInMb;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 16:09:26 -04:00
|
|
|
Document::Ptr CppSourceProcessor::switchCurrentDocument(Document::Ptr doc)
|
2013-04-23 15:04:36 +02:00
|
|
|
{
|
2013-07-08 16:57:17 +02:00
|
|
|
const Document::Ptr previousDoc = m_currentDoc;
|
2013-04-23 15:04:36 +02:00
|
|
|
m_currentDoc = doc;
|
|
|
|
|
return previousDoc;
|
|
|
|
|
}
|