Commit cb01bf84 authored by Milian Wolff's avatar Milian Wolff

Ensure we don't assume that the TU-file is the file we are working on.

This is done by explicitly requesting a path to be passed to
ParseSession::file and adding ::mainFile with the old logic. This
probably will fix quite some potential issues, e.g. in the signature
assistant or code completion.

Furthermore, we should not triviall be able to share the parse session
between different contexts, if I'm not mistaken.

REVIEW: 122094
parent 9d267fb5
......@@ -268,7 +268,7 @@ void ClangParseJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread
return;
}
auto context = ClangHelpers::buildDUChain(session.file(), imports, session,
auto context = ClangHelpers::buildDUChain(session.mainFile(), imports, session,
minimumFeatures(), includedFiles, clang()->index());
setDuChain(context);
......
......@@ -262,15 +262,15 @@ CompletionHelper::CompletionHelper()
{
}
void CompletionHelper::computeCompletions(const ParseSession& session, const KTextEditor::Cursor& position)
void CompletionHelper::computeCompletions(const ParseSession& session, CXFile file, const KTextEditor::Cursor& position)
{
const auto unit = session.unit();
CXSourceLocation location = clang_getLocation(unit, session.file(), position.line() + 1, position.column() + 1);
CXSourceLocation location = clang_getLocation(unit, file, position.line() + 1, position.column() + 1);
if (clang_equalLocations(clang_getNullLocation(), location)) {
clangDebug() << "Completion helper given invalid position " << position
<< " in file " << session.file();
<< " in file " << ClangString(clang_getFileName(file));
return;
}
......
......@@ -24,6 +24,7 @@
#include <QStringList>
#include <QVector>
#include <clang-c/Index.h>
#include <language/duchain/duchainpointer.h>
......@@ -61,7 +62,7 @@ class CompletionHelper
public:
CompletionHelper();
void computeCompletions(const ParseSession& session,
void computeCompletions(const ParseSession& session, CXFile file,
const KTextEditor::Cursor& position);
FunctionOverrideList overrides() const;
......
......@@ -355,6 +355,7 @@ bool isValidSpecialCompletionIdentifier(const QualifiedIdentifier& identifier)
ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& context,
const ParseSessionData::Ptr& sessionData,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text
)
......@@ -362,55 +363,44 @@ ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& c
, m_results(nullptr, clang_disposeCodeCompleteResults)
, m_parseSessionData(sessionData)
{
const QByteArray file = url.toLocalFile().toUtf8();
ParseSession session(m_parseSessionData);
{
ParseSession session(m_parseSessionData);
ClangString file(clang_getFileName(session.file()));
const unsigned int completeOptions = clang_defaultCodeCompleteOptions();
if (!m_text.isEmpty()) {
clangDebug() << "Unsaved contents found for file" << file << "- creating CXUnsavedFile";
CXUnsavedFile unsaved;
unsaved.Filename = file.constData();
const QByteArray content = m_text.toUtf8();
unsaved.Contents = content.constData();
unsaved.Length = content.size() + 1; // + \0-byte
CXUnsavedFile unsaved;
const QByteArray content = m_text.toUtf8();
unsaved.Contents = content.constData();
unsaved.Length = content.size() + 1; // + \0-byte
unsaved.Filename = file.c_str();
m_results.reset(clang_codeCompleteAt(session.unit(), file.c_str(),
position.line() + 1, position.column() + 1,
&unsaved, 1u,
completeOptions));
} else {
m_results.reset(clang_codeCompleteAt(session.unit(), file.c_str(),
position.line() + 1, position.column() + 1,
nullptr, 0u,
completeOptions));
}
m_results.reset(clang_codeCompleteAt(session.unit(), file.constData(),
position.line() + 1, position.column() + 1,
content.isEmpty() ? nullptr : &unsaved, content.isEmpty() ? 0 : 1,
completeOptions));
if (!m_results) {
qCWarning(KDEV_CLANG) << "Something went wrong during 'clang_codeCompleteAt' for file" << file.toString();
qCWarning(KDEV_CLANG) << "Something went wrong during 'clang_codeCompleteAt' for file" << file;
}
}
// check 'isValidPosition' after parsing the new content
if (!isValidPosition()) {
auto clangFile = session.file(file);
if (!isValidPosition(session.unit(), clangFile)) {
m_valid = false;
return;
}
ParseSession session(m_parseSessionData);
m_completionHelper.computeCompletions(session, position);
m_completionHelper.computeCompletions(session, clangFile, position);
}
ClangCodeCompletionContext::~ClangCodeCompletionContext()
{
}
bool ClangCodeCompletionContext::isValidPosition() const
bool ClangCodeCompletionContext::isValidPosition(CXTranslationUnit unit, CXFile file) const
{
ParseSession session(m_parseSessionData);
if (isInsideComment(session.unit(), session.file(), m_position.castToSimpleCursor())) {
if (isInsideComment(unit, file, m_position.castToSimpleCursor())) {
clangDebug() << "Invalid completion context: Inside comment";
return false;
}
......
......@@ -47,6 +47,7 @@ public:
ClangCodeCompletionContext(const KDevelop::DUContextPointer& context,
const ParseSessionData::Ptr& sessionData,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text);
~ClangCodeCompletionContext();
......@@ -66,7 +67,7 @@ private:
void eventuallyAddGroup(const QString& name, int priority, const QList<KDevelop::CompletionTreeItemPointer>& items);
/// Returns whether the we are at a valid completion-position
bool isValidPosition() const;
bool isValidPosition(CXTranslationUnit unit, CXFile file) const;
std::unique_ptr<CXCodeCompleteResults, void(*)(CXCodeCompleteResults*)> m_results;
QList<KDevelop::CompletionTreeElementPointer> m_ungrouped;
......
......@@ -164,6 +164,7 @@ public:
IncludePathCompletionContext::IncludePathCompletionContext(const DUContextPointer& context,
const ParseSessionData::Ptr& sessionData,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text)
: CodeCompletionContext(context, text, CursorInRevision::castFromSimpleCursor(position), 0)
......
......@@ -32,6 +32,7 @@ class IncludePathCompletionContext : public KDevelop::CodeCompletionContext
public:
IncludePathCompletionContext(const KDevelop::DUContextPointer& context,
const ParseSessionData::Ptr& sessionData,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text);
......
......@@ -61,13 +61,14 @@ bool includePathCompletionRequired(const QString& text)
QSharedPointer<CodeCompletionContext> createCompletionContext(const KDevelop::DUContextPointer& context,
const ParseSessionData::Ptr& session,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text)
{
if (includePathCompletionRequired(text)) {
return QSharedPointer<IncludePathCompletionContext>(new IncludePathCompletionContext(context, session, position, text));
return QSharedPointer<IncludePathCompletionContext>(new IncludePathCompletionContext(context, session, url, position, text));
} else {
return QSharedPointer<ClangCodeCompletionContext>(new ClangCodeCompletionContext(context, session, position, text));
return QSharedPointer<ClangCodeCompletionContext>(new ClangCodeCompletionContext(context, session, url, position, text));
}
}
......@@ -112,7 +113,7 @@ public slots:
return;
}
auto completionContext = ::createCompletionContext(DUContextPointer(top), sessionData, position, text);
auto completionContext = ::createCompletionContext(DUContextPointer(top), sessionData, url, position, text);
lock.lock();
if (aborting()) {
......
......@@ -330,8 +330,13 @@ void ClangSignatureAssistant::textChanged(KTextEditor::View* view, const KTextEd
return;
}
CXFile file = session.file(fileUrl.toLocalFile().toUtf8());
if (!file) {
return;
}
const KTextEditor::Cursor simpleCursor(invocationRange.start());
CXCursor cursor = getFunctionCursor(simpleCursor, session.unit(), session.file());
CXCursor cursor = getFunctionCursor(simpleCursor, session.unit(), file);
if (clang_Cursor_isNull(cursor)) {
return;
}
......@@ -381,7 +386,7 @@ void ClangSignatureAssistant::textChanged(KTextEditor::View* view, const KTextEd
//the function could be defined in any file which includes us, but that
//information is not available to use through clang's translation unit model. The
//best we can do is guess at similar file names.
m_targetUnit = findCompanionFile(fileUrl, simpleCursor, session.file(), otherSide);
m_targetUnit = findCompanionFile(fileUrl, simpleCursor, file, otherSide);
if (m_targetUnit.isEmpty()) {
clangDebug() << "Could not find candidate target for " << fileUrl;
......@@ -427,9 +432,11 @@ void ClangSignatureAssistant::parseJobFinished(ParseJob* job)
}
clearActions();
// TODO: remove this lock?
DUChainReadLocker lock;
KTextEditor::Cursor c = KTextEditor::Cursor(m_view.data()->cursorPosition());
// TODO: there should be only one session
const ParseSession sourceSession(getSession(m_view.data()->document()->url()));
if (!sourceSession.data()) {
reset();
......@@ -448,15 +455,16 @@ void ClangSignatureAssistant::parseJobFinished(ParseJob* job)
targetUnit = sourceSession.unit();
}
CXFile otherFile = clang_getFile(targetUnit, m_otherLoc.document.byteArray().constData());
CXCursor cursor = getFunctionCursor(c, sourceSession.unit(), sourceSession.file());
CXCursor otherCursor = getFunctionCursor(m_otherLoc, targetUnit, otherFile);
CXFile file = clang_getFile(targetUnit, qPrintable(m_view.data()->document()->url().toLocalFile()));
CXCursor cursor = getFunctionCursor(c, sourceSession.unit(), file);
if (clang_Cursor_isNull(cursor)) {
clangDebug() << "Couldn't get source cursor " << clang_getFileName(sourceSession.file()) << ":" << c;
clangDebug() << "Couldn't get source cursor " << m_view.data()->document()->url() << ":" << c;
reset();
return;
}
CXFile otherFile = clang_getFile(targetUnit, qPrintable(m_otherLoc.document.toUrl().toLocalFile()));
CXCursor otherCursor = getFunctionCursor(m_otherLoc, targetUnit, otherFile);
if (clang_Cursor_isNull(otherCursor)) {
clangDebug() << "Couldn't get target cursor " << clang_getFileName(otherFile) << ":" << m_otherLoc;
reset();
......
......@@ -57,7 +57,7 @@ ClangPCH::ClangPCH(const ClangParsingEnvironment& environment, ClangIndex* index
}
auto imports = ClangHelpers::tuImports(m_session.unit());
m_context = ClangHelpers::buildDUChain(m_session.file(), imports, m_session, pchFeatures, m_includes);
m_context = ClangHelpers::buildDUChain(m_session.mainFile(), imports, m_session, pchFeatures, m_includes);
}
IncludeFileContexts ClangPCH::mapIncludes(CXTranslationUnit tu) const
......@@ -72,7 +72,7 @@ IncludeFileContexts ClangPCH::mapIncludes(CXTranslationUnit tu) const
CXFile ClangPCH::mapFile(CXTranslationUnit tu) const
{
return ::mapFile(m_session.file(), tu);
return ::mapFile(m_session.mainFile(), tu);
}
ReferencedTopDUContext ClangPCH::context() const
......
......@@ -28,6 +28,7 @@ struct ClientData
{
QTextStream* out;
ParseSession* session;
CXFile file;
uint depth;
};
......@@ -40,7 +41,7 @@ CXChildVisitResult visitCursor(CXCursor cursor, CXCursor /*parent*/, CXClientDat
uint line;
uint column;
clang_getFileLocation(location, &file, &line, &column, 0);
if (file != data->session->file()) {
if (file != data->file) {
return CXChildVisit_Continue;
}
......@@ -79,7 +80,7 @@ CXChildVisitResult visitCursor(CXCursor cursor, CXCursor /*parent*/, CXClientDat
(*data->out) << endl;
ClientData childData{data->out, data->session, data->depth + 1};
ClientData childData{data->out, data->session, data->file, data->depth + 1};
clang_visitChildren(cursor, &visitCursor, &childData);
return CXChildVisit_Continue;
......@@ -93,10 +94,10 @@ DebugVisitor::DebugVisitor(ParseSession* session)
}
void DebugVisitor::visit(CXTranslationUnit unit)
void DebugVisitor::visit(CXTranslationUnit unit, CXFile file)
{
auto cursor = clang_getTranslationUnitCursor(unit);
QTextStream out(stdout);
ClientData data {&out, m_session, 0};
ClientData data {&out, m_session, file, 0};
clang_visitChildren(cursor, &visitCursor, &data);
}
......@@ -30,7 +30,7 @@ class KDEVCLANGDUCHAIN_EXPORT DebugVisitor
public:
DebugVisitor(ParseSession* session);
void visit(CXTranslationUnit unit);
void visit(CXTranslationUnit unit, CXFile file);
private:
ParseSession* m_session;
......
......@@ -318,7 +318,12 @@ CXTranslationUnit ParseSession::unit() const
return d ? d->m_unit : nullptr;
}
CXFile ParseSession::file() const
CXFile ParseSession::file(const QByteArray& path) const
{
return clang_getFile(unit(), path.constData());
}
CXFile ParseSession::mainFile() const
{
return d ? d->m_file : nullptr;
}
......
......@@ -110,9 +110,14 @@ public:
ParseSessionData::Ptr data() const;
/**
* @return the file of this session
* @return find the CXFile for the given path.
*/
CXFile file() const;
CXFile file(const QByteArray& path) const;
/**
* @return the CXFile for the first file in this translation unit.
*/
CXFile mainFile() const;
QList<KDevelop::ProblemPointer> problemsForFile(CXFile file) const;
......
......@@ -91,14 +91,19 @@ private:
if (!m_session.unit()) {
qerr << "no AST tree could be generated" << endl;
} else {
qout << "AST tree successfully generated" << endl;
if (m_printAst) {
DebugVisitor visitor(&m_session);
visitor.visit(m_session.unit());
}
exit(255);
return;
}
qout << "AST tree successfully generated" << endl;
auto file = m_session.mainFile();
if (m_printAst) {
DebugVisitor visitor(&m_session);
visitor.visit(m_session.unit(), file);
}
const auto problems = m_session.problemsForFile(m_session.file());
const auto problems = m_session.problemsForFile(file);
if (!problems.isEmpty()) {
qerr << endl << "problems encountered during parsing:" << endl;
foreach(const ProblemPointer problem, problems) {
......@@ -107,10 +112,6 @@ private:
} else {
qout << "no problems encountered during parsing" << endl;
}
if (!m_session.unit()) {
exit(255);
}
}
ParseSession m_session;
......
......@@ -83,7 +83,7 @@ void executeCompletionTest(const QString& code, const CompletionItemsList& expec
foreach(CompletionItems items, expectedCompletionItems) {
// TODO: We should not need to pass 'session' to the context, should just use the base class ctor
auto context = new ClangCodeCompletionContext(topPtr, sessionData, items.position, QString());
auto context = new ClangCodeCompletionContext(topPtr, sessionData, file.url().toUrl(), items.position, QString());
context->setFilters(filters);
DUChainReadLocker lock;
......@@ -109,7 +109,7 @@ void executeIncludePathCompletion(TestFile* file, const KTextEditor::Cursor& pos
lock.unlock();
auto context = new IncludePathCompletionContext(topPtr, sessionData, position, file->fileContents());
auto context = new IncludePathCompletionContext(topPtr, sessionData, file->url().toUrl(), position, file->fileContents());
lock.lock();
auto tester = CodeCompletionItemTester<IncludePathCompletionContext>(QExplicitlySharedDataPointer<IncludePathCompletionContext>(context));
......
......@@ -74,8 +74,7 @@ QList<ProblemPointer> TestProblems::parse(const QByteArray& code)
environment.setTranslationUnitUrl(IndexedString(FileName));
ParseSession session(ParseSessionData::Ptr(new ParseSessionData({UnsavedFile(FileName, {code})},
&index, environment)));
return session.problemsForFile(session.file());
return {};
return session.problemsForFile(session.mainFile());
}
void TestProblems::testNoProblems()
......
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