Commit bbbeebbb authored by Gleb Popov's avatar Gleb Popov 💬
Browse files

Fix rare cases when rangeForIncludeSpec() wasn't working correctly. Move it to...

Fix rare cases when rangeForIncludeSpec() wasn't working correctly. Move it to ClangUtils:: namespace. Add a testcase. Based on

REVIEW: 122798

by Matthew Suozzo.
parent b79503db
......@@ -28,6 +28,7 @@
#include "util/clangdebug.h"
#include "util/clangtypes.h"
#include "util/clangutils.h"
#include "codecompletion/model.h"
......@@ -71,7 +72,6 @@
#include <KTextEditor/ConfigInterface>
#include <QAction>
#include <QRegularExpression>
K_PLUGIN_FACTORY_WITH_JSON(KDevClangSupportFactory, "kdevclangsupport.json", registerPlugin<ClangSupport>(); )
......@@ -79,44 +79,6 @@ using namespace KDevelop;
namespace {
/**
* Extract the range of the path-spec inside the include-directive in line @p line
*
* Example: line = "#include <vector>" => returns {0, 10, 0, 16}
*
* @param originalRange This is the range that the resulting range will be based on
*
* @return Range pointing to the path-spec of the include or invalid range if there is no #include directive on the line.
*/
KTextEditor::Range rangeForIncludePathSpec(const QString& line, const KTextEditor::Range& originalRange = KTextEditor::Range())
{
static const QRegularExpression pattern(QStringLiteral("^\\s*#include"));
if (!line.contains(pattern)) {
return KTextEditor::Range::invalid();
}
KTextEditor::Range range = originalRange;
int pos = 0;
for (; pos < line.size(); ++pos) {
if(line[pos] == QLatin1Char('"') || line[pos] == QLatin1Char('<')) {
range.setStart({range.start().line(), ++pos});
break;
}
}
for (; pos < line.size(); ++pos) {
if(line[pos] == QLatin1Char('"') || line[pos] == QLatin1Char('>')) {
range.setEnd({range.start().line(), pos});
break;
}
}
if(range.start() > range.end()) {
range.setStart(range.end());
}
return range;
}
QPair<QString, KTextEditor::Range> lineInDocument(const QUrl &url, const KTextEditor::Cursor& position)
{
KDevelop::IDocument* doc = ICore::self()->documentController()->documentForUrl(url);
......@@ -139,7 +101,7 @@ QPair<TopDUContextPointer, KTextEditor::Range> importedContextForPosition(const
if (line.isEmpty())
return {{}, KTextEditor::Range::invalid()};
KTextEditor::Range wordRange = rangeForIncludePathSpec(line, pair.second);
KTextEditor::Range wordRange = ClangUtils::rangeForIncludePathSpec(line, pair.second);
if (!wordRange.isValid()) {
return {{}, KTextEditor::Range::invalid()};
}
......
......@@ -212,3 +212,11 @@ void TestClangUtils::testGetRawContents_data()
<< KTextEditor::Range(0, 5, 0, 17)
<< " int ";
}
void TestClangUtils::testRangeForIncludePathSpec()
{
QCOMPARE(ClangUtils::rangeForIncludePathSpec("#include <vector>"), KTextEditor::Range(0, 10, 0, 16));
QCOMPARE(ClangUtils::rangeForIncludePathSpec("#include <foo\\\".h>"), KTextEditor::Range(0, 10, 0, 17));
QCOMPARE(ClangUtils::rangeForIncludePathSpec("#include \"foo\\\".h\""), KTextEditor::Range(0, 10, 0, 17));
QCOMPARE(ClangUtils::rangeForIncludePathSpec("#include \"foo<>.h\""), KTextEditor::Range(0, 10, 0, 17));
}
......@@ -35,6 +35,7 @@ private slots:
void testGetScope_data();
void testGetRawContents();
void testGetRawContents_data();
void testRangeForIncludePathSpec();
};
#endif // TESTCLANGUTILS_H
......@@ -31,6 +31,7 @@
#include <clang-c/Index.h>
#include <QTextStream>
#include <QRegularExpression>
using namespace KDevelop;
......@@ -52,6 +53,37 @@ CXCursor ClangUtils::getCXCursor(int line, int column, const CXTranslationUnit&
return clang_getCursor(unit, location);
}
KTextEditor::Range ClangUtils::rangeForIncludePathSpec(const QString& line, const KTextEditor::Range& originalRange)
{
static const QRegularExpression pattern(QStringLiteral("^\\s*#include"));
if (!line.contains(pattern)) {
return KTextEditor::Range::invalid();
}
KTextEditor::Range range = originalRange;
int pos = 0;
char term_char = 0;
for (; pos < line.size(); ++pos) {
if (line[pos] == QLatin1Char('"') || line[pos] == QLatin1Char('<')) {
term_char = line[pos] == QLatin1Char('"') ? '"' : '>';
range.setStart({ range.start().line(), ++pos });
break;
}
}
for (; pos < line.size(); ++pos) {
if (line[pos] == QLatin1Char('\\')) {
++pos;
continue;
} else if(line[pos] == QLatin1Char(term_char)) {
range.setEnd({ range.start().line(), pos });
break;
}
}
return range;
}
namespace {
struct FunctionInfo {
......
......@@ -24,6 +24,8 @@
#include <util/path.h>
#include <KTextEditor/View>
#include <clang-c/Index.h>
namespace KDevelop {
......@@ -121,6 +123,17 @@ namespace ClangUtils
* such API in libclang so having one function to check both cases is more efficient (only tokenize once)
*/
bool isExplicitlyDefaultedOrDeleted(CXCursor cursor);
/**
* Extract the range of the path-spec inside the include-directive in line @p line
*
* Example: line = "#include <vector>" => returns {0, 10, 0, 16}
*
* @param originalRange This is the range that the resulting range will be based on
*
* @return Range pointing to the path-spec of the include or invalid range if there is no #include directive on the line.
*/
KTextEditor::Range rangeForIncludePathSpec(const QString& line, const KTextEditor::Range& originalRange = KTextEditor::Range());
};
#endif // CLANGUTILS_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