Commit dc72cff7 authored by Christian Kamm's avatar Christian Kamm

C++: Add basic 'insert #include' quick fix.

Change-Id: I3a2fef56d6d1871ea4bbb139f9bdd2bc44dd0123
Reviewed-by: default avatarLeandro Melo <leandro.melo@nokia.com>
parent 5f44d8f5
......@@ -58,10 +58,10 @@ QT_END_NAMESPACE
namespace CPlusPlus {
class OverviewModel;
class Symbol;
class CppModelManagerInterface;
}
namespace CppTools {
class CppModelManagerInterface;
class CppCodeStyleSettings;
class CppRefactoringFile;
}
......
......@@ -36,8 +36,11 @@
#include "cppeditor_global.h"
#include <texteditor/quickfix.h>
namespace CPlusPlus {
class CppModelManagerInterface;
}
namespace CppTools {
class CppModelManagerInterface;
class CppRefactoringFile;
class CppRefactoringChanges;
typedef QSharedPointer<CppRefactoringFile> CppRefactoringFilePtr;
......
......@@ -56,12 +56,16 @@
#include <cplusplus/DependencyTable.h>
#include <cplusplus/Overview.h>
#include <cplusplus/TypeOfExpression.h>
#include <cplusplus/ModelManagerInterface.h>
#include <cplusplus/CppRewriter.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/insertionpointlocator.h>
#include <cpptools/cpptoolsreuse.h>
#include <cpptools/cppclassesfilter.h>
#include <cpptools/searchsymbols.h>
#include <extensionsystem/iplugin.h>
#include <extensionsystem/pluginmanager.h>
#include <QtCore/QFileInfo>
#include <QtGui/QApplication>
......@@ -1701,6 +1705,157 @@ private:
};
};
/**
* Adds an include for an undefined identifier.
*/
class IncludeAdder : public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const QSharedPointer<const CppQuickFixAssistInterface> &interface)
{
CppClassesFilter *classesFilter = ExtensionSystem::PluginManager::instance()->getObject<CppClassesFilter>();
if (!classesFilter)
return noResult();
const QList<AST *> &path = interface->path();
if (path.isEmpty())
return noResult();
// find the largest enclosing Name
const NameAST *enclosingName = 0;
const SimpleNameAST *innermostName = 0;
for (int i = path.size() - 1; i >= 0; --i) {
if (NameAST *nameAst = path.at(i)->asName()) {
enclosingName = nameAst;
if (!innermostName) {
innermostName = nameAst->asSimpleName();
if (!innermostName)
return noResult();
}
} else {
break;
}
}
if (!enclosingName || !enclosingName->name)
return noResult();
// find the enclosing scope
unsigned line, column;
const Document::Ptr &doc = interface->semanticInfo().doc;
doc->translationUnit()->getTokenStartPosition(enclosingName->firstToken(), &line, &column);
Scope *scope = doc->scopeAt(line, column);
if (!scope)
return noResult();
// check if the name resolves to something
QList<LookupItem> existingResults = interface->context().lookup(enclosingName->name, scope);
if (!existingResults.isEmpty())
return noResult();
const QString &className = Overview()(innermostName->name);
if (className.isEmpty())
return noResult();
QList<CppQuickFixOperation::Ptr> results;
// find the include paths
QStringList includePaths;
CppModelManagerInterface *modelManager = CppModelManagerInterface::instance();
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;
}
}
if (!inProject) {
// better use all include paths than none
foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos)
includePaths += info.includePaths;
}
// find a include file through the locator
QFutureInterface<Locator::FilterEntry> dummyInterface;
QList<Locator::FilterEntry> matches = classesFilter->matchesFor(dummyInterface, className);
bool classExists = false;
foreach (const Locator::FilterEntry &entry, matches) {
const ModelItemInfo info = entry.internalData.value<ModelItemInfo>();
if (info.symbolName != className)
continue;
classExists = true;
const QString &fileName = info.fileName;
const QFileInfo fileInfo(fileName);
// find the shortest way to include fileName given the includePaths
QString shortestInclude;
if (fileInfo.path() == QFileInfo(doc->fileName()).path()) {
shortestInclude = QString("\"%1\"").arg(fileInfo.fileName());
} else {
foreach (const QString &includePath, includePaths) {
if (!fileName.startsWith(includePath))
continue;
QString relativePath = fileName.mid(includePath.size());
if (!relativePath.isEmpty() && relativePath.at(0) == QLatin1Char('/'))
relativePath = relativePath.mid(1);
if (shortestInclude.isEmpty() || relativePath.size() + 2 < shortestInclude.size())
shortestInclude = QString("<%1>").arg(relativePath);
}
}
if (!shortestInclude.isEmpty())
results += CppQuickFixOperation::Ptr(new Operation(interface, 0, shortestInclude));
}
// for QSomething, propose a <QSomething> include -- if such a class was in the locator
if (classExists
&& className.size() > 2
&& className.at(0) == QLatin1Char('Q')
&& className.at(1).isUpper()) {
results += CppQuickFixOperation::Ptr(new Operation(interface, 1, QString("<%1>").arg(className)));
}
return results;
}
private:
class Operation: public CppQuickFixOperation
{
public:
Operation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, int priority, const QString &include)
: CppQuickFixOperation(interface, priority)
, m_include(include)
{
setDescription(QApplication::translate("CppTools::QuickFix",
"Add #include %1").arg(m_include));
}
virtual void performChanges(const CppRefactoringFilePtr &file,
const CppRefactoringChanges &)
{
// find location of last include in file
QList<Document::Include> includes = file->cppDocument()->includes();
unsigned lastIncludeLine = 0;
foreach (const Document::Include &include, includes) {
if (include.line() > lastIncludeLine)
lastIncludeLine = include.line();
}
// add include
const int insertPos = file->position(lastIncludeLine + 1, 1) - 1;
ChangeSet changes;
changes.insert(insertPos, QString("\n#include %1").arg(m_include));
file->setChangeSet(changes);
file->apply();
}
private:
QString m_include;
};
};
} // end of anonymous namespace
void registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
......@@ -1725,4 +1880,5 @@ void registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
plugIn->addAutoReleasedObject(new DeclFromDef);
plugIn->addAutoReleasedObject(new DefFromDecl);
plugIn->addAutoReleasedObject(new ApplyDeclDefLinkChanges);
plugIn->addAutoReleasedObject(new IncludeAdder);
}
......@@ -32,6 +32,7 @@
#include "cppclassesfilter.h"
using namespace CppTools;
using namespace CppTools::Internal;
CppClassesFilter::CppClassesFilter(CppModelManager *manager)
......
......@@ -33,17 +33,17 @@
#ifndef CPPCLASSESFILTER_H
#define CPPCLASSESFILTER_H
#include <cpplocatorfilter.h>
#include "cpptools_global.h"
#include "cpplocatorfilter.h"
namespace CppTools {
namespace Internal {
class CppClassesFilter : public CppLocatorFilter
class CPPTOOLS_EXPORT CppClassesFilter : public Internal::CppLocatorFilter
{
Q_OBJECT
public:
CppClassesFilter(CppModelManager *manager);
CppClassesFilter(Internal::CppModelManager *manager);
~CppClassesFilter();
QString displayName() const { return tr("Classes"); }
......@@ -51,7 +51,6 @@ public:
Priority priority() const { return Medium; }
};
} // namespace Internal
} // namespace CppTools
#endif // CPPCLASSESFILTER_H
......@@ -111,7 +111,7 @@ QList<Locator::FilterEntry> CppCurrentDocumentFilter::matchesFor(QFutureInterfac
void CppCurrentDocumentFilter::accept(Locator::FilterEntry selection) const
{
ModelItemInfo info = qvariant_cast<CppTools::Internal::ModelItemInfo>(selection.internalData);
ModelItemInfo info = qvariant_cast<CppTools::ModelItemInfo>(selection.internalData);
TextEditor::BaseTextEditorWidget::openEditorAt(info.fileName, info.line, info.column,
Core::Id(), Core::EditorManager::ModeSwitch);
}
......
......@@ -129,7 +129,7 @@ QList<Locator::FilterEntry> CppLocatorFilter::matchesFor(QFutureInterface<Locato
void CppLocatorFilter::accept(Locator::FilterEntry selection) const
{
ModelItemInfo info = qvariant_cast<CppTools::Internal::ModelItemInfo>(selection.internalData);
ModelItemInfo info = qvariant_cast<CppTools::ModelItemInfo>(selection.internalData);
TextEditor::BaseTextEditorWidget::openEditorAt(info.fileName, info.line, info.column,
Core::Id(), Core::EditorManager::ModeSwitch);
}
......
......@@ -39,7 +39,7 @@
#include <QDebug>
using namespace CPlusPlus;
using namespace CppTools::Internal;
using namespace CppTools;
SearchSymbols::SymbolTypes SearchSymbols::AllTypes =
SearchSymbols::Classes
......
......@@ -33,6 +33,8 @@
#ifndef SEARCHSYMBOLS_H
#define SEARCHSYMBOLS_H
#include "cpptools_global.h"
#include <cplusplus/CppDocument.h>
#include <cplusplus/Icons.h>
#include <cplusplus/Overview.h>
......@@ -48,9 +50,8 @@
#include <functional>
namespace CppTools {
namespace Internal {
struct ModelItemInfo
struct CPPTOOLS_EXPORT ModelItemInfo
{
enum ItemType { Enum, Class, Method, Declaration };
......@@ -180,10 +181,9 @@ private:
bool separateScope;
};
} // namespace Internal
} // namespace CppTools
Q_DECLARE_OPERATORS_FOR_FLAGS(CppTools::Internal::SearchSymbols::SymbolTypes)
Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo)
Q_DECLARE_OPERATORS_FOR_FLAGS(CppTools::SearchSymbols::SymbolTypes)
Q_DECLARE_METATYPE(CppTools::ModelItemInfo)
#endif // SEARCHSYMBOLS_H
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