forked from qt-creator/qt-creator
CppEditor: Improve finding position for new includes
...by detecting include groups (separated by new lines, include types and same dir prefix). Task-number: QTCREATORBUG-9317 Change-Id: I73e80fdc715104901cb2d4f5b15b4cab5d04d305 Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
e3bc84c414
commit
f3186690bd
@@ -162,14 +162,28 @@ private slots:
|
|||||||
|
|
||||||
void test_quickfix_InsertDeclFromDef();
|
void test_quickfix_InsertDeclFromDef();
|
||||||
|
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_detectIncludeGroupsByNewLines();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_detectIncludeGroupsByIncludeDir();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_detectIncludeGroupsByIncludeType();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_normal();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_normal();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_ignoremoc();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_ignoremoc();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_sortingTop();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_sortingTop();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_sortingMiddle();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_sortingMiddle();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_sortingBottom();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_sortingBottom();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_appendToUnsorted();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_firstLocalIncludeAtFront();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_firstGlobalIncludeAtBack();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_preferGroupWithLongerMatchingPrefix();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_newGroupIfOnlyDifferentIncludeDirs();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_mixedDirsSorted();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_mixedDirsUnsorted();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_mixedIncludeTypes1();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_mixedIncludeTypes2();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_mixedIncludeTypes3();
|
||||||
|
void test_quickfix_AddIncludeForUndefinedIdentifier_mixedIncludeTypes4();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_noinclude();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_noinclude();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_noincludeComment01();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_veryFirstIncludeCppStyleCommentOnTop();
|
||||||
void test_quickfix_AddIncludeForUndefinedIdentifier_noincludeComment02();
|
void test_quickfix_AddIncludeForUndefinedIdentifier_veryFirstIncludeCStyleCommentOnTop();
|
||||||
|
|
||||||
void test_quickfix_MoveFuncDefOutside_MemberFuncToCpp();
|
void test_quickfix_MoveFuncDefOutside_MemberFuncToCpp();
|
||||||
void test_quickfix_MoveFuncDefOutside_MemberFuncOutside();
|
void test_quickfix_MoveFuncDefOutside_MemberFuncOutside();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,7 @@
|
|||||||
#include <cpptools/cpppointerdeclarationformatter.h>
|
#include <cpptools/cpppointerdeclarationformatter.h>
|
||||||
#include <cpptools/cpptoolsconstants.h>
|
#include <cpptools/cpptoolsconstants.h>
|
||||||
#include <cpptools/cpptoolsreuse.h>
|
#include <cpptools/cpptoolsreuse.h>
|
||||||
|
#include <cpptools/includeutils.h>
|
||||||
#include <cpptools/insertionpointlocator.h>
|
#include <cpptools/insertionpointlocator.h>
|
||||||
#include <cpptools/symbolfinder.h>
|
#include <cpptools/symbolfinder.h>
|
||||||
|
|
||||||
@@ -182,6 +183,37 @@ Class *isMemberFunction(const LookupContext &context, Function *function)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given include is e.g. "afile.h" or <afile.h> (quotes/angle brackets included!).
|
||||||
|
void insertNewIncludeDirective(const QString &include, CppRefactoringFilePtr file)
|
||||||
|
{
|
||||||
|
// Find optimal position
|
||||||
|
using namespace IncludeUtils;
|
||||||
|
LineForNewIncludeDirective finder(file->document(), file->cppDocument()->includes(),
|
||||||
|
LineForNewIncludeDirective::IgnoreMocIncludes,
|
||||||
|
LineForNewIncludeDirective::AutoDetect);
|
||||||
|
unsigned newLinesToPrepend = 0;
|
||||||
|
unsigned newLinesToAppend = 0;
|
||||||
|
const int insertLine = finder(include, &newLinesToPrepend, &newLinesToAppend);
|
||||||
|
QTC_ASSERT(insertLine >= 1, return);
|
||||||
|
const int insertPosition = file->position(insertLine, 1);
|
||||||
|
QTC_ASSERT(insertPosition >= 0, return);
|
||||||
|
|
||||||
|
// Construct text to insert
|
||||||
|
const QString includeLine = QLatin1String("#include ") + include + QLatin1Char('\n');
|
||||||
|
QString prependedNewLines, appendedNewLines;
|
||||||
|
while (newLinesToAppend--)
|
||||||
|
appendedNewLines += QLatin1String("\n");
|
||||||
|
while (newLinesToPrepend--)
|
||||||
|
prependedNewLines += QLatin1String("\n");
|
||||||
|
const QString textToInsert = prependedNewLines + includeLine + appendedNewLines;
|
||||||
|
|
||||||
|
// Insert
|
||||||
|
ChangeSet changes;
|
||||||
|
changes.insert(insertPosition, textToInsert);
|
||||||
|
file->setChangeSet(changes);
|
||||||
|
file->apply();
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -1479,24 +1511,8 @@ public:
|
|||||||
if (best.isEmpty())
|
if (best.isEmpty())
|
||||||
best = headerFile;
|
best = headerFile;
|
||||||
|
|
||||||
int pos = currentFile->startOf(1);
|
const QString include = QString::fromLatin1("<%1>").arg(QFileInfo(best).fileName());
|
||||||
|
insertNewIncludeDirective(include, currentFile);
|
||||||
unsigned currentLine = currentFile->cursor().blockNumber() + 1;
|
|
||||||
unsigned bestLine = 0;
|
|
||||||
foreach (const Document::Include &incl,
|
|
||||||
assistInterface()->semanticInfo().doc->includes()) {
|
|
||||||
if (incl.line() < currentLine)
|
|
||||||
bestLine = incl.line();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bestLine)
|
|
||||||
pos = currentFile->document()->findBlockByNumber(bestLine).position();
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
changes.insert(pos, QLatin1String("#include <")
|
|
||||||
+ QFileInfo(best).fileName() + QLatin1String(">\n"));
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1731,108 +1747,21 @@ void ConvertToCamelCase::match(const CppQuickFixInterface &interface, QuickFixOp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
AddIncludeForUndefinedIdentifierOp::AddIncludeForUndefinedIdentifierOp(
|
||||||
|
const CppQuickFixInterface &interface, int priority, const QString &include)
|
||||||
class AddIncludeForUndefinedIdentifierOp: public CppQuickFixOperation
|
: CppQuickFixOperation(interface, priority)
|
||||||
|
, m_include(include)
|
||||||
{
|
{
|
||||||
public:
|
setDescription(QApplication::translate("CppTools::QuickFix", "Add #include %1").arg(m_include));
|
||||||
AddIncludeForUndefinedIdentifierOp(const CppQuickFixInterface &interface, int priority,
|
}
|
||||||
const QString &include)
|
|
||||||
: CppQuickFixOperation(interface, priority)
|
|
||||||
, m_include(include)
|
|
||||||
{
|
|
||||||
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
||||||
"Add #include %1").arg(m_include));
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform()
|
void AddIncludeForUndefinedIdentifierOp::perform()
|
||||||
{
|
{
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
CppRefactoringChanges refactoring(snapshot());
|
||||||
CppRefactoringFilePtr file = refactoring.file(fileName());
|
CppRefactoringFilePtr file = refactoring.file(fileName());
|
||||||
|
|
||||||
QList<Document::Include> includes = file->cppDocument()->includes();
|
insertNewIncludeDirective(m_include, file);
|
||||||
if (!includes.isEmpty()) {
|
}
|
||||||
QHash<QString, unsigned> includePositions;
|
|
||||||
foreach (const Document::Include &include, includes) {
|
|
||||||
const QString fileName = include.unresolvedFileName();
|
|
||||||
if (fileName.endsWith(QLatin1String(".moc")))
|
|
||||||
continue;
|
|
||||||
includePositions.insert(fileName, include.line());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!includePositions.isEmpty()) {
|
|
||||||
const QString include = m_include.mid(1, m_include.length() - 2);
|
|
||||||
QList<QString> keys = includePositions.keys();
|
|
||||||
keys << include;
|
|
||||||
qSort(keys);
|
|
||||||
const int pos = keys.indexOf(include);
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
if (pos + 1 != keys.count()) {
|
|
||||||
const int insertPos = qMax(0, file->position(
|
|
||||||
includePositions.value(keys.at(pos + 1)), 1));
|
|
||||||
changes.insert(insertPos,
|
|
||||||
QLatin1String("#include ") + m_include + QLatin1String("\n"));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const int insertPos = qMax(0, file->position(includePositions.value(
|
|
||||||
keys.at(pos - 1)) + 1, 1) - 1);
|
|
||||||
changes.insert(insertPos, QLatin1String("\n#include ") + m_include);
|
|
||||||
}
|
|
||||||
file->setChangeSet(changes);
|
|
||||||
file->apply();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No includes or no matching include, find possible first/multi line comment
|
|
||||||
int insertPos = 0;
|
|
||||||
QTextBlock block = file->document()->firstBlock();
|
|
||||||
while (block.isValid()) {
|
|
||||||
const QString trimmedText = block.text().trimmed();
|
|
||||||
|
|
||||||
// Only skip the first comment!
|
|
||||||
if (trimmedText.startsWith(QLatin1String("/*"))) {
|
|
||||||
do {
|
|
||||||
const int pos = block.text().indexOf(QLatin1String("*/"));
|
|
||||||
if (pos > -1) {
|
|
||||||
insertPos = block.position() + pos + 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
block = block.next();
|
|
||||||
} while (block.isValid());
|
|
||||||
break;
|
|
||||||
} else if (trimmedText.startsWith(QLatin1String("//"))) {
|
|
||||||
block = block.next();
|
|
||||||
while (block.isValid()) {
|
|
||||||
if (!block.text().trimmed().startsWith(QLatin1String("//"))) {
|
|
||||||
insertPos = block.position() - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
block = block.next();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trimmedText.isEmpty())
|
|
||||||
break;
|
|
||||||
block = block.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
if (insertPos != 0)
|
|
||||||
changes.insert(insertPos, QLatin1String("\n\n#include ") + m_include);
|
|
||||||
else
|
|
||||||
changes.insert(insertPos, QString::fromLatin1("#include %1\n\n").arg(m_include));
|
|
||||||
file->setChangeSet(changes);
|
|
||||||
file->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_include;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interface,
|
void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interface,
|
||||||
QuickFixOperations &result)
|
QuickFixOperations &result)
|
||||||
|
@@ -71,6 +71,18 @@ public:
|
|||||||
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
|
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Exposed for tests
|
||||||
|
class AddIncludeForUndefinedIdentifierOp: public CppQuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddIncludeForUndefinedIdentifierOp(const CppQuickFixInterface &interface, int priority,
|
||||||
|
const QString &include);
|
||||||
|
void perform();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_include;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Can be triggered on a class forward declaration to add the matching #include.
|
Can be triggered on a class forward declaration to add the matching #include.
|
||||||
|
|
||||||
@@ -493,6 +505,7 @@ public:
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Insert (pure) virtual functions of a base class.
|
Insert (pure) virtual functions of a base class.
|
||||||
|
Exposed for tests.
|
||||||
*/
|
*/
|
||||||
class InsertVirtualMethodsDialog : public QDialog
|
class InsertVirtualMethodsDialog : public QDialog
|
||||||
{
|
{
|
||||||
|
@@ -124,6 +124,12 @@ public:
|
|||||||
return m_includePaths;
|
return m_includePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use this *only* for auto tests
|
||||||
|
void setIncludePaths(const QStringList &includePaths)
|
||||||
|
{
|
||||||
|
m_includePaths = includePaths;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList frameworkPaths()
|
QStringList frameworkPaths()
|
||||||
{
|
{
|
||||||
ensureUpdated();
|
ensureUpdated();
|
||||||
|
@@ -45,7 +45,8 @@ HEADERS += completionsettingspage.h \
|
|||||||
builtinindexingsupport.h \
|
builtinindexingsupport.h \
|
||||||
cpppointerdeclarationformatter.h \
|
cpppointerdeclarationformatter.h \
|
||||||
cppprojectfile.h \
|
cppprojectfile.h \
|
||||||
cpppreprocessor.h
|
cpppreprocessor.h \
|
||||||
|
includeutils.h
|
||||||
|
|
||||||
SOURCES += completionsettingspage.cpp \
|
SOURCES += completionsettingspage.cpp \
|
||||||
cppclassesfilter.cpp \
|
cppclassesfilter.cpp \
|
||||||
@@ -89,7 +90,8 @@ SOURCES += completionsettingspage.cpp \
|
|||||||
builtinindexingsupport.cpp \
|
builtinindexingsupport.cpp \
|
||||||
cpppointerdeclarationformatter.cpp \
|
cpppointerdeclarationformatter.cpp \
|
||||||
cppprojectfile.cpp \
|
cppprojectfile.cpp \
|
||||||
cpppreprocessor.cpp
|
cpppreprocessor.cpp \
|
||||||
|
includeutils.cpp
|
||||||
|
|
||||||
FORMS += completionsettingspage.ui \
|
FORMS += completionsettingspage.ui \
|
||||||
cppfilesettingspage.ui \
|
cppfilesettingspage.ui \
|
||||||
|
@@ -107,7 +107,9 @@ QtcPlugin {
|
|||||||
"builtinindexingsupport.cpp",
|
"builtinindexingsupport.cpp",
|
||||||
"builtinindexingsupport.h",
|
"builtinindexingsupport.h",
|
||||||
"cpppreprocessor.cpp",
|
"cpppreprocessor.cpp",
|
||||||
"cpppreprocessor.h"
|
"cpppreprocessor.h",
|
||||||
|
"includeutils.cpp",
|
||||||
|
"includeutils.h"
|
||||||
]
|
]
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
|
495
src/plugins/cpptools/includeutils.cpp
Normal file
495
src/plugins/cpptools/includeutils.cpp
Normal file
@@ -0,0 +1,495 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
** a written agreement between you and Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "includeutils.h"
|
||||||
|
|
||||||
|
#include <cplusplus/pp-engine.h>
|
||||||
|
#include <cplusplus/PreprocessorClient.h>
|
||||||
|
#include <cplusplus/PreprocessorEnvironment.h>
|
||||||
|
|
||||||
|
#include <utils/stringutils.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTextBlock>
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
using namespace CppTools;
|
||||||
|
using namespace CppTools::IncludeUtils;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
static bool includeLineLessThan(const Include &left, const Include &right)
|
||||||
|
{ return left.line() < right.line(); }
|
||||||
|
|
||||||
|
static bool includeFileNamelessThen(const Include & left, const Include & right)
|
||||||
|
{ return left.unresolvedFileName() < right.unresolvedFileName(); }
|
||||||
|
|
||||||
|
LineForNewIncludeDirective::LineForNewIncludeDirective(const QTextDocument *textDocument,
|
||||||
|
QList<Document::Include> includes,
|
||||||
|
MocIncludeMode mocIncludeMode,
|
||||||
|
IncludeStyle includeStyle)
|
||||||
|
: m_textDocument(textDocument)
|
||||||
|
, m_includeStyle(includeStyle)
|
||||||
|
{
|
||||||
|
// Ignore *.moc includes if requested
|
||||||
|
if (mocIncludeMode == IgnoreMocIncludes) {
|
||||||
|
foreach (const Document::Include &include, includes) {
|
||||||
|
if (!include.unresolvedFileName().endsWith(QLatin1String(".moc")))
|
||||||
|
m_includes << include;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_includes = includes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this filter loop once FastPreprocessor::sourceNeeded does not add
|
||||||
|
// extra includes anymore.
|
||||||
|
for (int i = m_includes.count() - 1; i >= 0; --i) {
|
||||||
|
if (!QFileInfo(m_includes.at(i).resolvedFileName()).isAbsolute())
|
||||||
|
m_includes.removeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect include style
|
||||||
|
if (m_includeStyle == AutoDetect) {
|
||||||
|
unsigned timesIncludeStyleChanged = 0;
|
||||||
|
if (m_includes.isEmpty() || m_includes.size() == 1) {
|
||||||
|
m_includeStyle = LocalBeforeGlobal; // Fallback
|
||||||
|
} else {
|
||||||
|
for (int i = 1, size = m_includes.size(); i < size; ++i) {
|
||||||
|
if (m_includes.at(i - 1).type() != m_includes.at(i).type()) {
|
||||||
|
if (++timesIncludeStyleChanged > 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (timesIncludeStyleChanged == 1) {
|
||||||
|
m_includeStyle = m_includes.first().type() == Client::IncludeLocal
|
||||||
|
? LocalBeforeGlobal
|
||||||
|
: GlobalBeforeLocal;
|
||||||
|
} else {
|
||||||
|
m_includeStyle = LocalBeforeGlobal; // Fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int LineForNewIncludeDirective::operator()(const QString &newIncludeFileName,
|
||||||
|
unsigned *newLinesToPrepend,
|
||||||
|
unsigned *newLinesToAppend)
|
||||||
|
{
|
||||||
|
if (newLinesToPrepend)
|
||||||
|
*newLinesToPrepend = false;
|
||||||
|
if (newLinesToAppend)
|
||||||
|
*newLinesToAppend = false;
|
||||||
|
|
||||||
|
const QString pureIncludeFileName = newIncludeFileName.mid(1, newIncludeFileName.length() - 2);
|
||||||
|
const CPlusPlus::Client::IncludeType newIncludeType =
|
||||||
|
newIncludeFileName.startsWith(QLatin1Char('"')) ? Client::IncludeLocal
|
||||||
|
: Client::IncludeGlobal;
|
||||||
|
|
||||||
|
// Handle no includes
|
||||||
|
if (m_includes.empty()) {
|
||||||
|
unsigned insertLine = 0;
|
||||||
|
|
||||||
|
QTextBlock block = m_textDocument->firstBlock();
|
||||||
|
while (block.isValid()) {
|
||||||
|
const QString trimmedText = block.text().trimmed();
|
||||||
|
|
||||||
|
// Only skip the first comment!
|
||||||
|
if (trimmedText.startsWith(QLatin1String("/*"))) {
|
||||||
|
do {
|
||||||
|
const int pos = block.text().indexOf(QLatin1String("*/"));
|
||||||
|
if (pos > -1) {
|
||||||
|
insertLine = block.blockNumber() + 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block = block.next();
|
||||||
|
} while (block.isValid());
|
||||||
|
break;
|
||||||
|
} else if (trimmedText.startsWith(QLatin1String("//"))) {
|
||||||
|
block = block.next();
|
||||||
|
while (block.isValid()) {
|
||||||
|
if (!block.text().trimmed().startsWith(QLatin1String("//"))) {
|
||||||
|
insertLine = block.blockNumber() + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block = block.next();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!trimmedText.isEmpty())
|
||||||
|
break;
|
||||||
|
block = block.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insertLine == 0) {
|
||||||
|
if (newLinesToAppend)
|
||||||
|
*newLinesToAppend += 1;
|
||||||
|
insertLine = 1;
|
||||||
|
} else {
|
||||||
|
if (newLinesToPrepend)
|
||||||
|
*newLinesToPrepend = 1;
|
||||||
|
}
|
||||||
|
return insertLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef QList<IncludeGroup> IncludeGroups;
|
||||||
|
|
||||||
|
const IncludeGroups groupsNewline = IncludeGroup::detectIncludeGroupsByNewLines(m_includes);
|
||||||
|
const bool includeAtTop
|
||||||
|
= (newIncludeType == Client::IncludeLocal && m_includeStyle == LocalBeforeGlobal)
|
||||||
|
|| (newIncludeType == Client::IncludeGlobal && m_includeStyle == GlobalBeforeLocal);
|
||||||
|
IncludeGroup bestGroup = includeAtTop ? groupsNewline.first() : groupsNewline.last();
|
||||||
|
|
||||||
|
IncludeGroups groupsMatchingIncludeType = getGroupsByIncludeType(groupsNewline, newIncludeType);
|
||||||
|
if (groupsMatchingIncludeType.isEmpty()) {
|
||||||
|
const IncludeGroups groupsMixedIncludeType
|
||||||
|
= IncludeGroup::filterMixedIncludeGroups(groupsNewline);
|
||||||
|
// case: The new include goes into an own include group
|
||||||
|
if (groupsMixedIncludeType.isEmpty()) {
|
||||||
|
return includeAtTop
|
||||||
|
? IncludeGroup::lineForPrependedIncludeGroup(groupsNewline, newLinesToAppend)
|
||||||
|
: IncludeGroup::lineForAppendedIncludeGroup(groupsNewline, newLinesToPrepend);
|
||||||
|
// case: add to mixed group
|
||||||
|
} else {
|
||||||
|
const IncludeGroup bestMixedGroup = groupsMixedIncludeType.last(); // TODO: flaterize
|
||||||
|
const IncludeGroups groupsIncludeType
|
||||||
|
= IncludeGroup::detectIncludeGroupsByIncludeType(bestMixedGroup.includes());
|
||||||
|
groupsMatchingIncludeType = getGroupsByIncludeType(groupsIncludeType, newIncludeType);
|
||||||
|
// Avoid extra new lines for include groups which are not separated by new lines
|
||||||
|
newLinesToPrepend = 0;
|
||||||
|
newLinesToAppend = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeGroups groupsSameIncludeDir;
|
||||||
|
IncludeGroups groupsMixedIncludeDirs;
|
||||||
|
foreach (const IncludeGroup &group, groupsMatchingIncludeType) {
|
||||||
|
if (group.hasCommonIncludeDir())
|
||||||
|
groupsSameIncludeDir << group;
|
||||||
|
else
|
||||||
|
groupsMixedIncludeDirs << group;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeGroups groupsMatchingIncludeDir;
|
||||||
|
foreach (const IncludeGroup &group, groupsSameIncludeDir) {
|
||||||
|
if (group.commonIncludeDir() == IncludeGroup::includeDir(pureIncludeFileName))
|
||||||
|
groupsMatchingIncludeDir << group;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case: There are groups with a matching include dir, insert the new include
|
||||||
|
// at the best position of the best group
|
||||||
|
if (!groupsMatchingIncludeDir.isEmpty()) {
|
||||||
|
// The group with the longest common matching prefix is the best group
|
||||||
|
int longestPrefixSoFar = 0;
|
||||||
|
foreach (const IncludeGroup &group, groupsMatchingIncludeDir) {
|
||||||
|
const int groupPrefixLength = group.commonPrefix().length();
|
||||||
|
if (groupPrefixLength >= longestPrefixSoFar) {
|
||||||
|
bestGroup = group;
|
||||||
|
longestPrefixSoFar = groupPrefixLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// case: The new include goes into an own include group
|
||||||
|
if (groupsMixedIncludeDirs.isEmpty()) {
|
||||||
|
if (includeAtTop) {
|
||||||
|
return groupsSameIncludeDir.isEmpty()
|
||||||
|
? IncludeGroup::lineForPrependedIncludeGroup(groupsNewline, newLinesToAppend)
|
||||||
|
: IncludeGroup::lineForAppendedIncludeGroup(groupsSameIncludeDir, newLinesToPrepend);
|
||||||
|
} else {
|
||||||
|
return IncludeGroup::lineForAppendedIncludeGroup(groupsNewline, newLinesToPrepend);
|
||||||
|
}
|
||||||
|
// case: The new include is inserted at the best position of the best
|
||||||
|
// group with mixed include dirs
|
||||||
|
} else {
|
||||||
|
IncludeGroups groupsIncludeDir;
|
||||||
|
foreach (const IncludeGroup &group, groupsMixedIncludeDirs) {
|
||||||
|
groupsIncludeDir.append(
|
||||||
|
IncludeGroup::detectIncludeGroupsByIncludeDir(group.includes()));
|
||||||
|
}
|
||||||
|
IncludeGroup localBestIncludeGroup = IncludeGroup(QList<Include>());
|
||||||
|
foreach (const IncludeGroup &group, groupsIncludeDir) {
|
||||||
|
if (group.commonIncludeDir() == IncludeGroup::includeDir(pureIncludeFileName))
|
||||||
|
localBestIncludeGroup = group;
|
||||||
|
}
|
||||||
|
if (!localBestIncludeGroup.isEmpty()) {
|
||||||
|
bestGroup = localBestIncludeGroup;
|
||||||
|
} else {
|
||||||
|
bestGroup = groupsMixedIncludeDirs.last();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestGroup.lineForNewInclude(pureIncludeFileName, newIncludeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<IncludeGroup> LineForNewIncludeDirective::getGroupsByIncludeType(
|
||||||
|
const QList<IncludeGroup> &groups, IncludeType includeType)
|
||||||
|
{
|
||||||
|
return includeType == Client::IncludeLocal
|
||||||
|
? IncludeGroup::filterIncludeGroups(groups, Client::IncludeLocal)
|
||||||
|
: IncludeGroup::filterIncludeGroups(groups, Client::IncludeGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// includes will be modified!
|
||||||
|
QList<IncludeGroup> IncludeGroup::detectIncludeGroupsByNewLines(QList<Document::Include> &includes)
|
||||||
|
{
|
||||||
|
// Sort by line
|
||||||
|
qSort(includes.begin(), includes.end(), includeLineLessThan);
|
||||||
|
|
||||||
|
// Create groups
|
||||||
|
QList<IncludeGroup> result;
|
||||||
|
unsigned lastLine = 0;
|
||||||
|
QList<Include> currentIncludes;
|
||||||
|
bool isFirst = true;
|
||||||
|
foreach (const Include &include, includes) {
|
||||||
|
// First include...
|
||||||
|
if (isFirst) {
|
||||||
|
isFirst = false;
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
// Include belongs to current group
|
||||||
|
else if (lastLine + 1 == include.line()) {
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
// Include is member of new group
|
||||||
|
else {
|
||||||
|
result << IncludeGroup(currentIncludes);
|
||||||
|
currentIncludes.clear();
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLine = include.line();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentIncludes.isEmpty())
|
||||||
|
result << IncludeGroup(currentIncludes);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<IncludeGroup> IncludeGroup::detectIncludeGroupsByIncludeDir(const QList<Include> &includes)
|
||||||
|
{
|
||||||
|
// Create sub groups
|
||||||
|
QList<IncludeGroup> result;
|
||||||
|
QString lastDir;
|
||||||
|
QList<Include> currentIncludes;
|
||||||
|
bool isFirst = true;
|
||||||
|
foreach (const Include &include, includes) {
|
||||||
|
const QString currentDirPrefix = includeDir(include.unresolvedFileName());
|
||||||
|
|
||||||
|
// First include...
|
||||||
|
if (isFirst) {
|
||||||
|
isFirst = false;
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
// Include belongs to current group
|
||||||
|
else if (lastDir == currentDirPrefix) {
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
// Include is member of new group
|
||||||
|
else {
|
||||||
|
result << IncludeGroup(currentIncludes);
|
||||||
|
currentIncludes.clear();
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastDir = currentDirPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentIncludes.isEmpty())
|
||||||
|
result << IncludeGroup(currentIncludes);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<IncludeGroup> IncludeGroup::detectIncludeGroupsByIncludeType(const QList<Include> &includes)
|
||||||
|
{
|
||||||
|
// Create sub groups
|
||||||
|
QList<IncludeGroup> result;
|
||||||
|
CPlusPlus::Client::IncludeType lastIncludeType;
|
||||||
|
QList<Include> currentIncludes;
|
||||||
|
bool isFirst = true;
|
||||||
|
foreach (const Include &include, includes) {
|
||||||
|
const CPlusPlus::Client::IncludeType currentIncludeType = include.type();
|
||||||
|
|
||||||
|
// First include...
|
||||||
|
if (isFirst) {
|
||||||
|
isFirst = false;
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
// Include belongs to current group
|
||||||
|
else if (lastIncludeType == currentIncludeType) {
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
// Include is member of new group
|
||||||
|
else {
|
||||||
|
result << IncludeGroup(currentIncludes);
|
||||||
|
currentIncludes.clear();
|
||||||
|
currentIncludes << include;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIncludeType = currentIncludeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentIncludes.isEmpty())
|
||||||
|
result << IncludeGroup(currentIncludes);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IncludeGroup::includeDir(const QString &include)
|
||||||
|
{
|
||||||
|
QString dirPrefix = QFileInfo(include).dir().path();
|
||||||
|
if (dirPrefix == QLatin1String("."))
|
||||||
|
return QString();
|
||||||
|
dirPrefix.append(QLatin1Char('/'));
|
||||||
|
return dirPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns groups that solely contains includes of the given include type
|
||||||
|
QList<IncludeGroup> IncludeGroup::filterIncludeGroups(const QList<IncludeGroup> &groups,
|
||||||
|
Client::IncludeType includeType)
|
||||||
|
{
|
||||||
|
QList<IncludeGroup> result;
|
||||||
|
foreach (const IncludeGroup &group, groups) {
|
||||||
|
if (group.hasOnlyIncludesOfType(includeType))
|
||||||
|
result << group;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns groups that contains includes with local and globale include type
|
||||||
|
QList<IncludeGroup> IncludeGroup::filterMixedIncludeGroups(const QList<IncludeGroup> &groups)
|
||||||
|
{
|
||||||
|
QList<IncludeGroup> result;
|
||||||
|
foreach (const IncludeGroup &group, groups) {
|
||||||
|
if (!group.hasOnlyIncludesOfType(Client::IncludeLocal)
|
||||||
|
&& !group.hasOnlyIncludesOfType(Client::IncludeGlobal)) {
|
||||||
|
result << group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IncludeGroup::hasOnlyIncludesOfType(Client::IncludeType includeType) const
|
||||||
|
{
|
||||||
|
foreach (const Include &include, m_includes) {
|
||||||
|
if (include.type() != includeType)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IncludeGroup::isSorted() const
|
||||||
|
{
|
||||||
|
const QStringList names = filesNames();
|
||||||
|
if (names.isEmpty() || names.size() == 1)
|
||||||
|
return true;
|
||||||
|
for (int i = 1, total = names.size(); i < total; ++i) {
|
||||||
|
if (names.at(i) < names.at(i - 1))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IncludeGroup::lineForNewInclude(const QString &newIncludeFileName,
|
||||||
|
Client::IncludeType newIncludeType) const
|
||||||
|
{
|
||||||
|
if (m_includes.empty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (isSorted()) {
|
||||||
|
const Include newInclude(newIncludeFileName, QString(), -1, newIncludeType);
|
||||||
|
const QList<Include>::const_iterator it = std::lower_bound(m_includes.begin(),
|
||||||
|
m_includes.end(), newInclude, includeFileNamelessThen);
|
||||||
|
if (it == m_includes.end())
|
||||||
|
return m_includes.last().line() + 1;
|
||||||
|
else
|
||||||
|
return (*it).line();
|
||||||
|
} else {
|
||||||
|
return m_includes.last().line() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList IncludeGroup::filesNames() const
|
||||||
|
{
|
||||||
|
QStringList names;
|
||||||
|
foreach (const Include &include, m_includes)
|
||||||
|
names << include.unresolvedFileName();
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IncludeGroup::commonPrefix() const
|
||||||
|
{
|
||||||
|
const QStringList files = filesNames();
|
||||||
|
if (files.size() <= 1)
|
||||||
|
return QString(); // no prefix for single item groups
|
||||||
|
return Utils::commonPrefix(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IncludeGroup::commonIncludeDir() const
|
||||||
|
{
|
||||||
|
if (m_includes.isEmpty())
|
||||||
|
return QString();
|
||||||
|
return includeDir(m_includes.first().unresolvedFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IncludeGroup::hasCommonIncludeDir() const
|
||||||
|
{
|
||||||
|
if (m_includes.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const QString candidate = includeDir(m_includes.first().unresolvedFileName());
|
||||||
|
for (int i = 1, size = m_includes.size(); i < size; ++i) {
|
||||||
|
if (includeDir(m_includes.at(i).unresolvedFileName()) != candidate)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IncludeGroup::lineForAppendedIncludeGroup(const QList<IncludeGroup> &groups,
|
||||||
|
unsigned *newLinesToPrepend)
|
||||||
|
{
|
||||||
|
if (newLinesToPrepend)
|
||||||
|
*newLinesToPrepend += 1;
|
||||||
|
return groups.last().last().line() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IncludeGroup::lineForPrependedIncludeGroup(const QList<IncludeGroup> &groups,
|
||||||
|
unsigned *newLinesToAppend)
|
||||||
|
{
|
||||||
|
if (newLinesToAppend)
|
||||||
|
*newLinesToAppend += 1;
|
||||||
|
return groups.first().first().line();
|
||||||
|
}
|
121
src/plugins/cpptools/includeutils.h
Normal file
121
src/plugins/cpptools/includeutils.h
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
** a written agreement between you and Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||||
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef INCLUDEUTILS_H
|
||||||
|
#define INCLUDEUTILS_H
|
||||||
|
|
||||||
|
#include "cpptools_global.h"
|
||||||
|
|
||||||
|
#include <cplusplus/CppDocument.h>
|
||||||
|
#include <cplusplus/PreprocessorClient.h>
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QStringList)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QTextDocument)
|
||||||
|
|
||||||
|
namespace CppTools {
|
||||||
|
namespace IncludeUtils {
|
||||||
|
|
||||||
|
typedef CPlusPlus::Document::Include Include;
|
||||||
|
typedef CPlusPlus::Client::IncludeType IncludeType;
|
||||||
|
|
||||||
|
class CPPTOOLS_EXPORT IncludeGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QList<IncludeGroup> detectIncludeGroupsByNewLines(QList<Include> &includes);
|
||||||
|
static QList<IncludeGroup> detectIncludeGroupsByIncludeDir(const QList<Include> &includes);
|
||||||
|
static QList<IncludeGroup> detectIncludeGroupsByIncludeType(const QList<Include> &includes);
|
||||||
|
|
||||||
|
static int lineForAppendedIncludeGroup(const QList<IncludeGroup> &groups,
|
||||||
|
unsigned *newLinesToPrepend);
|
||||||
|
static int lineForPrependedIncludeGroup(const QList<IncludeGroup> &groups,
|
||||||
|
unsigned *newLinesToAppend);
|
||||||
|
|
||||||
|
static QList<IncludeGroup> filterMixedIncludeGroups(const QList<IncludeGroup> &groups);
|
||||||
|
static QList<IncludeGroup> filterIncludeGroups(const QList<IncludeGroup> &groups,
|
||||||
|
CPlusPlus::Client::IncludeType includeType);
|
||||||
|
|
||||||
|
static QString includeDir(const QString &include);
|
||||||
|
|
||||||
|
public:
|
||||||
|
IncludeGroup(const QList<Include> &includes) : m_includes(includes) {}
|
||||||
|
|
||||||
|
QList<Include> includes() const { return m_includes; }
|
||||||
|
Include first() const { return m_includes.first(); }
|
||||||
|
Include last() const { return m_includes.last(); }
|
||||||
|
int size() const { return m_includes.size(); }
|
||||||
|
bool isEmpty() const { return m_includes.isEmpty(); }
|
||||||
|
|
||||||
|
QString commonPrefix() const;
|
||||||
|
QString commonIncludeDir() const; /// only valid if hasCommonDir() == true
|
||||||
|
bool hasCommonIncludeDir() const;
|
||||||
|
bool hasOnlyIncludesOfType(CPlusPlus::Client::IncludeType includeType) const;
|
||||||
|
bool isSorted() const; /// name-wise
|
||||||
|
|
||||||
|
int lineForNewInclude(const QString &newIncludeFileName,
|
||||||
|
CPlusPlus::Client::IncludeType newIncludeType) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList filesNames() const;
|
||||||
|
|
||||||
|
QList<Include> m_includes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CPPTOOLS_EXPORT LineForNewIncludeDirective
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum MocIncludeMode { RespectMocIncludes, IgnoreMocIncludes };
|
||||||
|
enum IncludeStyle { LocalBeforeGlobal, GlobalBeforeLocal, AutoDetect };
|
||||||
|
|
||||||
|
LineForNewIncludeDirective(const QTextDocument *textDocument,
|
||||||
|
QList<Include> includes,
|
||||||
|
MocIncludeMode mocIncludeMode = IgnoreMocIncludes,
|
||||||
|
IncludeStyle includeStyle = AutoDetect);
|
||||||
|
|
||||||
|
/// Returns the line (1-based) at which the include directive should be inserted.
|
||||||
|
/// On error, -1 is returned.
|
||||||
|
int operator()(const QString &newIncludeFileName, unsigned *newLinesToPrepend = 0,
|
||||||
|
unsigned *newLinesToAppend = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<IncludeGroup> getGroupsByIncludeType(const QList<IncludeGroup> &groups,
|
||||||
|
IncludeType includeType);
|
||||||
|
|
||||||
|
const QTextDocument *m_textDocument;
|
||||||
|
IncludeStyle m_includeStyle;
|
||||||
|
QList<Include> m_includes;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace IncludeUtils
|
||||||
|
} // namespace CppTools
|
||||||
|
|
||||||
|
#endif // INCLUDEUTILS_H
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
@@ -0,0 +1 @@
|
|||||||
|
// comment
|
Reference in New Issue
Block a user