Commit 3aab8bea authored by Erik Verbruggen's avatar Erik Verbruggen

Supply c++11 flags and per-project info to c++ code model.

A manual squash/merge of the changes below, plus a couple of subsequent
code fixes.

59085aa5fbb99e2d786cd2c1a06c24a111ccb49f:
    Modify CppModel::ProjectInfo

    Adding per project node information, to pass on the correct
    defines/includes for each file, instead of aggregating them incorrectly.

    Also split up SOURCES and OBJECTIVE_SOURCES.

    Also ask the toolchain to convert the compilerflags to flags the
    codemodel understands, for now only gcc and only c++11.

    Also make the toolchain aware of the flags used to compile, so that it
    can emit the correct defines.

    Note: No header files are passed on.

74028802314cd4e75b41b46407433e07090a304d:
    GCC: Evaluate cxxflags when checking for predefined macros

ebaaa4957e4c02cc9637a998eddae1d0acd74f83:
    MSVC: Take cxxflags into account when checking for predefined macros

9bfce7e889bcf7bcc47bf880e3ea25945ca7d0d7:
    Compile fixes

Change-Id: I9de94ad038dfc5dc1987732e84b13fb4419c96f5
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@nokia.com>
parent 89e64b5a
......@@ -32,6 +32,8 @@
#include "ModelManagerInterface.h"
#include <QtCore/QSet>
using namespace CPlusPlus;
static CppModelManagerInterface *g_instance = 0;
......@@ -54,3 +56,44 @@ CppModelManagerInterface *CppModelManagerInterface::instance()
return g_instance;
}
void CppModelManagerInterface::ProjectInfo::clearProjectParts()
{
m_projectParts.clear();
m_includePaths.clear();
m_frameworkPaths.clear();
m_sourceFiles.clear();
m_defines.clear();
}
void CppModelManagerInterface::ProjectInfo::appendProjectPart(
const CppModelManagerInterface::ProjectPart::Ptr &part)
{
if (!part)
return;
m_projectParts.append(part);
// update include paths
QSet<QString> incs = QSet<QString>::fromList(m_includePaths);
foreach (const QString &ins, part->includePaths)
incs.insert(ins);
m_includePaths = incs.toList();
// update framework paths
QSet<QString> frms = QSet<QString>::fromList(m_frameworkPaths);
foreach (const QString &frm, part->frameworkPaths)
frms.insert(frm);
m_frameworkPaths = frms.toList();
// update source files
QSet<QString> srcs = QSet<QString>::fromList(m_sourceFiles);
foreach (const QString &src, part->sourceFiles)
srcs.insert(src);
m_sourceFiles = srcs.toList();
// update defines
if (!m_defines.isEmpty())
m_defines.append('\n');
m_defines.append(part->defines);
}
......@@ -35,6 +35,9 @@
#include <cplusplus/CppDocument.h>
#include <languageutils/fakemetaobject.h>
#include <projectexplorer/project.h>
#include <projectexplorer/toolchain.h>
#include <QObject>
#include <QHash>
#include <QPointer>
......@@ -66,33 +69,88 @@ class CPLUSPLUS_EXPORT CppModelManagerInterface : public QObject
Q_OBJECT
public:
enum Language { CXX, OBJC };
class CPLUSPLUS_EXPORT ProjectPart
{
public:
ProjectPart()
: qtVersion(UnknownQt)
{}
public: //attributes
QStringList sourceFiles;
QByteArray defines;
QStringList includePaths;
QStringList frameworkPaths;
QStringList precompiledHeaders;
Language language;
ProjectExplorer::ToolChain::CompilerFlags flags;
enum QtVersion {
UnknownQt = -1,
NoQt = 0,
Qt4 = 1,
Qt5 = 2
};
QtVersion qtVersion;
bool cpp0xEnabled() const
{ return flags == ProjectExplorer::ToolChain::STD_CXX11; }
bool objcEnabled() const
{ return language == CppModelManagerInterface::OBJC; }
typedef QSharedPointer<ProjectPart> Ptr;
};
class ProjectInfo
{
public:
ProjectInfo()
{ }
ProjectInfo(QPointer<ProjectExplorer::Project> project)
: project(project)
ProjectInfo(QWeakPointer<ProjectExplorer::Project> project)
: m_project(project)
{ }
operator bool() const
{ return ! project.isNull(); }
{ return ! m_project.isNull(); }
bool isValid() const
{ return ! project.isNull(); }
{ return ! m_project.isNull(); }
bool isNull() const
{ return project.isNull(); }
{ return m_project.isNull(); }
public: // attributes
QPointer<ProjectExplorer::Project> project;
QString projectPath;
QByteArray defines;
QStringList sourceFiles;
QStringList includePaths;
QStringList frameworkPaths;
QStringList precompiledHeaders;
QWeakPointer<ProjectExplorer::Project> project() const
{ return m_project; }
const QList<ProjectPart::Ptr> projectParts() const
{ return m_projectParts; }
void clearProjectParts();
void appendProjectPart(const ProjectPart::Ptr &part);
const QStringList includePaths() const
{ return m_includePaths; }
const QStringList frameworkPaths() const
{ return m_frameworkPaths; }
const QStringList sourceFiles() const
{ return m_sourceFiles; }
const QByteArray defines() const
{ return m_defines; }
private: // attributes
QWeakPointer<ProjectExplorer::Project> m_project;
QList<ProjectPart::Ptr> m_projectParts;
// the attributes below are calculated from the project parts.
QStringList m_includePaths;
QStringList m_frameworkPaths;
QStringList m_sourceFiles;
QByteArray m_defines;
};
class WorkingCopy
......@@ -110,6 +168,9 @@ public:
QPair<QString, unsigned> get(const QString &fileName) const
{ return _elements.value(fileName); }
QHashIterator<QString, QPair<QString, unsigned> > iterator() const
{ return QHashIterator<QString, QPair<QString, unsigned> >(_elements); }
private:
typedef QHash<QString, QPair<QString, unsigned> > Table;
Table _elements;
......@@ -135,6 +196,7 @@ public:
virtual QList<ProjectInfo> projectInfos() const = 0;
virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0;
virtual void updateProjectInfo(const ProjectInfo &pinfo) = 0;
virtual QList<ProjectPart::Ptr> projectPart(const QString &fileName) const = 0;
virtual void addEditorSupport(CppTools::AbstractEditorSupport *editorSupport) = 0;
virtual void removeEditorSupport(CppTools::AbstractEditorSupport *editorSupport) = 0;
......
......@@ -513,19 +513,23 @@ void AutotoolsProject::updateCppCodeModel()
CPlusPlus::CppModelManagerInterface::ProjectInfo pinfo = modelManager->projectInfo(this);
const bool update = (pinfo.includePaths != allIncludePaths)
|| (pinfo.sourceFiles != m_files)
|| (pinfo.defines != m_toolChain->predefinedMacros())
|| (pinfo.frameworkPaths != allFrameworkPaths);
const bool update = (pinfo.includePaths() != allIncludePaths)
|| (pinfo.sourceFiles() != m_files)
|| (pinfo.defines() != m_toolChain->predefinedMacros(QStringList()))
|| (pinfo.frameworkPaths() != allFrameworkPaths);
if (update) {
pinfo.includePaths = allIncludePaths;
pinfo.sourceFiles = m_files;
pinfo.clearProjectParts();
CPlusPlus::CppModelManagerInterface::ProjectPart::Ptr part(
new CPlusPlus::CppModelManagerInterface::ProjectPart);
part->includePaths = allIncludePaths;
part->sourceFiles = m_files;
if (m_toolChain)
pinfo.defines = m_toolChain->predefinedMacros();
pinfo.frameworkPaths = allFrameworkPaths;
part->defines = m_toolChain->predefinedMacros(QStringList());
part->frameworkPaths = allFrameworkPaths;
part->language = CPlusPlus::CppModelManagerInterface::CXX;
pinfo.appendProjectPart(part);
modelManager->updateProjectInfo(pinfo);
modelManager->updateSourceFiles(pinfo.sourceFiles);
modelManager->updateSourceFiles(m_files);
}
modelManager->updateProjectInfo(pinfo);
}
......@@ -307,18 +307,23 @@ bool CMakeProject::parseCMakeLists()
CPlusPlus::CppModelManagerInterface::instance();
if (modelmanager) {
CPlusPlus::CppModelManagerInterface::ProjectInfo pinfo = modelmanager->projectInfo(this);
if (pinfo.includePaths != allIncludePaths
|| pinfo.sourceFiles != m_files
|| pinfo.defines != (activeBC->toolChain() ? activeBC->toolChain()->predefinedMacros() : QByteArray())
|| pinfo.frameworkPaths != allFrameworkPaths) {
pinfo.includePaths = allIncludePaths;
if (pinfo.includePaths() != allIncludePaths
|| pinfo.sourceFiles() != m_files
|| pinfo.defines() != (activeBC->toolChain() ? activeBC->toolChain()->predefinedMacros(QStringList()) : QByteArray())
|| pinfo.frameworkPaths() != allFrameworkPaths) {
pinfo.clearProjectParts();
CPlusPlus::CppModelManagerInterface::ProjectPart::Ptr part(
new CPlusPlus::CppModelManagerInterface::ProjectPart);
part->includePaths = allIncludePaths;
// TODO we only want C++ files, not all other stuff that might be in the project
pinfo.sourceFiles = m_files;
pinfo.defines = (activeBC->toolChain() ? activeBC->toolChain()->predefinedMacros() : QByteArray()); // TODO this is to simplistic
pinfo.frameworkPaths = allFrameworkPaths;
part->sourceFiles = m_files;
part->defines = (activeBC->toolChain() ? activeBC->toolChain()->predefinedMacros(QStringList()) : QByteArray()); // TODO this is to simplistic
part->frameworkPaths = allFrameworkPaths;
part->language = CPlusPlus::CppModelManagerInterface::CXX;
pinfo.appendProjectPart(part);
modelmanager->updateProjectInfo(pinfo);
m_codeModelFuture.cancel();
m_codeModelFuture = modelmanager->updateSourceFiles(pinfo.sourceFiles);
m_codeModelFuture = modelmanager->updateSourceFiles(m_files);
}
}
emit buildTargetsChanged();
......
......@@ -1863,15 +1863,19 @@ public:
QList<CppModelManagerInterface::ProjectInfo> projectInfos = modelManager->projectInfos();
bool inProject = false;
foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos) {
if (info.sourceFiles.contains(doc->fileName())) {
inProject = true;
includePaths += info.includePaths;
foreach (CppModelManagerInterface::ProjectPart::Ptr part, info.projectParts()) {
if (part->sourceFiles.contains(doc->fileName())) {
inProject = true;
includePaths += part->includePaths;
}
}
}
if (!inProject) {
// better use all include paths than none
foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos)
includePaths += info.includePaths;
foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos) {
foreach (CppModelManagerInterface::ProjectPart::Ptr part, info.projectParts())
includePaths += part->includePaths;
}
}
// find a include file through the locator
......
......@@ -58,8 +58,8 @@ TextEditor::IAssistInterface *CppCompletionSupport::createAssistInterface(Projec
QStringList includePaths;
QStringList frameworkPaths;
if (project) {
includePaths = modelManager->projectInfo(project).includePaths;
frameworkPaths = modelManager->projectInfo(project).frameworkPaths;
includePaths = modelManager->projectInfo(project).includePaths();
frameworkPaths = modelManager->projectInfo(project).frameworkPaths();
}
return new CppTools::Internal::CppCompletionAssistInterface(
document,
......
......@@ -90,6 +90,34 @@
#include <iostream>
#include <sstream>
namespace CPlusPlus {
uint qHash(const CppModelManagerInterface::ProjectPart &p)
{
uint h = qHash(p.defines) ^ p.language ^ p.flags;
foreach (const QString &i, p.includePaths)
h ^= qHash(i);
foreach (const QString &f, p.frameworkPaths)
h ^= qHash(f);
return h;
}
bool operator==(const CppModelManagerInterface::ProjectPart &p1,
const CppModelManagerInterface::ProjectPart &p2)
{
if (p1.defines != p2.defines)
return false;
if (p1.language != p2.language)
return false;
if (p1.flags != p2.flags)
return false;
if (p1.includePaths != p2.includePaths)
return false;
return p1.frameworkPaths == p2.frameworkPaths;
}
} // namespace CPlusPlus
using namespace CppTools;
using namespace CppTools::Internal;
using namespace CPlusPlus;
......@@ -733,7 +761,8 @@ QStringList CppModelManager::internalProjectFiles() const
while (it.hasNext()) {
it.next();
ProjectInfo pinfo = it.value();
files += pinfo.sourceFiles;
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
files += part->sourceFiles;
}
files.removeDuplicates();
return files;
......@@ -746,7 +775,8 @@ QStringList CppModelManager::internalIncludePaths() const
while (it.hasNext()) {
it.next();
ProjectInfo pinfo = it.value();
includePaths += pinfo.includePaths;
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
includePaths += part->includePaths;
}
includePaths.removeDuplicates();
return includePaths;
......@@ -759,7 +789,8 @@ QStringList CppModelManager::internalFrameworkPaths() const
while (it.hasNext()) {
it.next();
ProjectInfo pinfo = it.value();
frameworkPaths += pinfo.frameworkPaths;
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
frameworkPaths += part->frameworkPaths;
}
frameworkPaths.removeDuplicates();
return frameworkPaths;
......@@ -772,7 +803,8 @@ QByteArray CppModelManager::internalDefinedMacros() const
while (it.hasNext()) {
it.next();
ProjectInfo pinfo = it.value();
macros += pinfo.defines;
foreach (const ProjectPart::Ptr &part, pinfo.projectParts())
macros += part->defines;
}
return macros;
}
......@@ -860,13 +892,66 @@ CppModelManager::ProjectInfo CppModelManager::projectInfo(ProjectExplorer::Proje
void CppModelManager::updateProjectInfo(const ProjectInfo &pinfo)
{
#if 0
// Tons of debug output...
qDebug()<<"========= CppModelManager::updateProjectInfo ======";
qDebug()<<" for project:"<< pinfo.project.data()->file()->fileName();
foreach (const ProjectPart::Ptr &part, pinfo.projectParts) {
qDebug() << "=== part ===";
qDebug() << "language:" << (part->language == CXX ? "C++" : "ObjC++");
qDebug() << "compilerflags:" << part->flags;
qDebug() << "precompiled header:" << part->precompiledHeaders;
qDebug() << "defines:" << part->defines;
qDebug() << "includes:" << part->includePaths;
qDebug() << "frameworkPaths:" << part->frameworkPaths;
qDebug() << "sources:" << part->sourceFiles;
qDebug() << "";
}
qDebug() << "";
#endif
QMutexLocker locker(&mutex);
if (! pinfo.isValid())
return;
m_projects.insert(pinfo.project, pinfo);
ProjectExplorer::Project *project = pinfo.project().data();
m_projects.insert(project, pinfo);
m_dirty = true;
m_srcToProjectPart.clear();
foreach (const ProjectPart::Ptr &projectPart, pinfo.projectParts()) {
foreach (const QString &sourceFile, projectPart->sourceFiles) {
m_srcToProjectPart[sourceFile].append(projectPart);
}
}
}
QList<CppModelManager::ProjectPart::Ptr> CppModelManager::projectPart(const QString &fileName) const
{
QList<CppModelManager::ProjectPart::Ptr> parts = m_srcToProjectPart.value(fileName);
if (!parts.isEmpty())
return parts;
//### FIXME: This is a DIRTY hack!
if (fileName.endsWith(".h")) {
QString cppFile = fileName.mid(0, fileName.length() - 2) + QLatin1String(".cpp");
parts = m_srcToProjectPart.value(cppFile);
if (!parts.isEmpty())
return parts;
}
DependencyTable table;
table.build(snapshot());
QStringList deps = table.filesDependingOn(fileName);
foreach (const QString &dep, deps) {
parts = m_srcToProjectPart.value(dep);
if (!parts.isEmpty())
return parts;
}
return parts;
}
QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
......
......@@ -83,7 +83,7 @@ class CppPreprocessor;
class CppFindReferences;
#ifndef ICHECK_BUILD
class CppModelManager : public CPlusPlus::CppModelManagerInterface
class CPPTOOLS_EXPORT CppModelManager : public CPlusPlus::CppModelManagerInterface
{
Q_OBJECT
......@@ -99,6 +99,7 @@ public:
virtual QList<ProjectInfo> projectInfos() const;
virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
virtual void updateProjectInfo(const ProjectInfo &pinfo);
virtual QList<ProjectPart::Ptr> projectPart(const QString &fileName) const;
virtual CPlusPlus::Snapshot snapshot() const;
virtual void GC();
......@@ -237,6 +238,8 @@ private:
mutable QMutex protectExtraDiagnostics;
QHash<QString, QHash<int, QList<CPlusPlus::Document::DiagnosticMessage> > > m_extraDiagnostics;
QMap<QString, QList<ProjectPart::Ptr> > m_srcToProjectPart;
};
#endif
......
......@@ -45,18 +45,31 @@ using namespace CPlusPlus;
namespace CppTools {
void moveCursorToEndOfIdentifier(QTextCursor *tc) {
static void moveCursorToStartOrEndOfIdentifier(QTextCursor *tc,
QTextCursor::MoveOperation op,
int posDiff = 0)
{
QTextDocument *doc = tc->document();
if (!doc)
return;
QChar ch = doc->characterAt(tc->position());
QChar ch = doc->characterAt(tc->position() - posDiff);
while (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
tc->movePosition(QTextCursor::NextCharacter);
ch = doc->characterAt(tc->position());
tc->movePosition(op);
ch = doc->characterAt(tc->position() - posDiff);
}
}
void moveCursorToEndOfIdentifier(QTextCursor *tc)
{
moveCursorToStartOrEndOfIdentifier(tc, QTextCursor::NextCharacter);
}
void moveCursorToStartOfIdentifier(QTextCursor *tc)
{
moveCursorToStartOrEndOfIdentifier(tc, QTextCursor::PreviousCharacter, 1);
}
static bool isOwnershipRAIIName(const QString &name)
{
static QSet<QString> knownNames;
......
......@@ -45,6 +45,7 @@ class LookupContext;
namespace CppTools {
void CPPTOOLS_EXPORT moveCursorToEndOfIdentifier(QTextCursor *tc);
void CPPTOOLS_EXPORT moveCursorToStartOfIdentifier(QTextCursor *tc);
bool CPPTOOLS_EXPORT isOwnershipRAIIType(CPlusPlus::Symbol *symbol,
const CPlusPlus::LookupContext &context);
......
......@@ -257,30 +257,33 @@ void GenericProject::refresh(RefreshOptions options)
if (modelManager) {
CPlusPlus::CppModelManagerInterface::ProjectInfo pinfo = modelManager->projectInfo(this);
pinfo.clearProjectParts();
CPlusPlus::CppModelManagerInterface::ProjectPart::Ptr part(
new CPlusPlus::CppModelManagerInterface::ProjectPart);
if (m_toolChain) {
pinfo.defines = m_toolChain->predefinedMacros();
pinfo.defines += '\n';
part->defines = m_toolChain->predefinedMacros(QStringList());
part->defines += '\n';
foreach (const HeaderPath &headerPath, m_toolChain->systemHeaderPaths()) {
if (headerPath.kind() == HeaderPath::FrameworkHeaderPath)
pinfo.frameworkPaths.append(headerPath.path());
part->frameworkPaths.append(headerPath.path());
else
pinfo.includePaths.append(headerPath.path());
part->includePaths.append(headerPath.path());
}
}
pinfo.includePaths += allIncludePaths();
pinfo.defines += m_defines;
part->includePaths += allIncludePaths();
part->defines += m_defines;
// ### add _defines.
pinfo.sourceFiles = files();
pinfo.sourceFiles += generated();
part->sourceFiles = files();
part->sourceFiles += generated();
QStringList filesToUpdate;
if (options & Configuration) {
filesToUpdate = pinfo.sourceFiles;
filesToUpdate = part->sourceFiles;
filesToUpdate.append(QLatin1String("<configuration>")); // XXX don't hardcode configuration file name
// Full update, if there's a code model update, cancel it
m_codeModelFuture.cancel();
......@@ -291,6 +294,8 @@ void GenericProject::refresh(RefreshOptions options)
filesToUpdate.append(newFileList.toList());
}
pinfo.appendProjectPart(part);
modelManager->updateProjectInfo(pinfo);
m_codeModelFuture = modelManager->updateSourceFiles(filesToUpdate);
}
......
......@@ -85,16 +85,22 @@ bool AbstractMsvcToolChain::isValid() const
return !m_vcvarsBat.isEmpty();
}
QByteArray AbstractMsvcToolChain::predefinedMacros() const
QByteArray AbstractMsvcToolChain::predefinedMacros(const QStringList &cxxflags) const
{
if (m_predefinedMacros.isEmpty()) {
Utils::Environment env(m_lastEnvironment);
addToEnvironment(env);
m_predefinedMacros = msvcPredefinedMacros(env);
m_predefinedMacros = msvcPredefinedMacros(cxxflags, env);
}
return m_predefinedMacros;
}
ToolChain::CompilerFlags AbstractMsvcToolChain::compilerFlags(const QStringList &cxxflags) const
{
Q_UNUSED(cxxflags);
return NO_FLAGS;
}
QList<HeaderPath> AbstractMsvcToolChain::systemHeaderPaths() const
{
if (m_headerPaths.isEmpty()) {
......@@ -118,7 +124,6 @@ void AbstractMsvcToolChain::addToEnvironment(Utils::Environment &env) const
env = m_resultEnvironment;
}
QString AbstractMsvcToolChain::makeCommand() const
{
if (ProjectExplorerPlugin::instance()->projectExplorerSettings().useJom) {
......@@ -158,9 +163,12 @@ bool AbstractMsvcToolChain::canClone() const
return true;
}
QByteArray AbstractMsvcToolChain::msvcPredefinedMacros(const Utils::Environment& env) const
QByteArray AbstractMsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags,
const Utils::Environment& env) const
{
Q_UNUSED(cxxflags);
Q_UNUSED(env);
QByteArray predefinedMacros = "#define __MSVCRT__\n"
"#define __w64\n"
"#define __int64 long long\n"
......
......@@ -50,11 +50,12 @@ public:
Abi targetAbi() const;
bool isValid() const;
QByteArray predefinedMacros() const;
QByteArray predefinedMacros(const QStringList &cxxflags) const;
CompilerFlags compilerFlags(const QStringList &cxxflags) const;
QList<HeaderPath> systemHeaderPaths() const;