kdev-clang not finding included files
David Nolden
david.nolden.kdevelop at art-master.de
Tue Jul 12 10:12:14 UTC 2016
The attached patch works around the clang parsing problem for clang
versions that don't have the fix.
Greetings, David
2016-07-11 23:16 GMT+02:00 Sven Brauch <mail at svenbrauch.de>:
> Ok, follow-up on our IRC talk:
>
> clang is invoked like this:
> Invocation: clang -ferror-limit=100 -fspell-checking -Wdocumentation
> -Wunused-parameter -Wunreachable-code -Wall -std=c++11 -nostdinc
> -nostdinc++ -xc++ -isystem
> /home/sven/install/share/kdevclangsupport/wrappedQtHeaders -isystem
> /home/sven/install/share/kdevclangsupport/wrappedQtHeaders/QtCore
> -isystem/usr/include/qt -isystem/usr/include/qt/QtCore
> -isystem/usr/lib/qt/mkspecs/linux-g++
> -isystem/usr/include/KF5/KTextEditor -isystem/usr/include/KF5
> -isystem/usr/include/KF5/KParts -isystem/usr/include/KF5/KIOWidgets
> -isystem/usr/include/KF5/KIOCore -isystem/usr/include/KF5/KCoreAddons
> -isystem/usr/include/KF5/KService -isystem/usr/include/KF5/KConfigCore
> -isystem/usr/include/KF5/KJobWidgets -isystem/usr/include/qt/QtWidgets
> -isystem/usr/include/qt/QtGui -isystem/usr/include/qt/QtNetwork
> -isystem/usr/include/KF5/KCompletion
> -isystem/usr/include/KF5/KWidgetsAddons -isystem/usr/include/KF5/KXmlGui
> -isystem/usr/include/qt/QtDBus -isystem/usr/include/qt/QtXml
> -isystem/usr/include/KF5/KConfigWidgets -isystem/usr/include/KF5/KCodecs
> -isystem/usr/include/KF5/KConfigGui -isystem/usr/include/KF5/KAuth
> -isystem/usr/include/KF5/KTextWidgets -isystem/usr/include/KF5/SonnetUi
> -isystem/usr/include/KF5/KI18n -isystem/usr/include/KF5/ThreadWeaver
> -isystem/home/sven/install/include/kdevplatform
> -isystem/home/sven/install/include -isystem/usr/include/KF5/KItemModels
> -isystem/usr/include -isystem/usr/include/c++/6.1.1
> -isystem/usr/include/c++/6.1.1/x86_64-pc-linux-gnu
> -isystem/usr/include/c++/6.1.1/backward -isystem/usr/local/include
> -isystem/usr/lib/clang/3.8.0/include -isystem/usr/include
> -I/home/sven/Projekte/kde/kdevelop/build/languages/clang
> -I/home/sven/Projekte/kde/kdevelop/languages/clang
> -I/home/sven/Projekte/kde/kdevelop
> -I/home/sven/Projekte/kde/kdevelop/build
> -I/home/sven/Projekte/kde/kdevelop/languages/clang/libs
> -I/home/sven/Projekte/kde/kdevelop/languages/plugin -imacros
> /tmp/kdevelop.pJ1057
> /home/sven/Projekte/kde/kdevelop/languages/clang/duchain/parsesession.cpp
>
> Doing that on command line reproduces the issue. The issue is that
> -isystem/usr/include is there twice, once as first and once as last path
> in the standard include paths list. If you remove the _first_ occurence,
> it works. I suspect some kind of circular #include or something if you
> have it in the first place.
>
> Do you clang people know what the reason for this is?
>
> Best,
> Sven
>
>
> _______________________________________________
> KDevelop-devel mailing list
> KDevelop-devel at kde.org
> https://mail.kde.org/mailman/listinfo/kdevelop-devel
>
-------------- next part --------------
commit 0b52400c6e6f7bf268607c3f4f47991920c2984f
Author: David Nolden <david.nolden.kde at art-master.de>
Date: Mon Jul 4 09:35:40 2016 +0200
annihilate missing includes
diff --git a/languages/clang/clangparsejob.cpp b/languages/clang/clangparsejob.cpp
index 8375eb5..1c65d10 100644
--- a/languages/clang/clangparsejob.cpp
+++ b/languages/clang/clangparsejob.cpp
@@ -280,6 +280,10 @@ void ClangParseJob::run(ThreadWeaver::JobPointer /*self*/, ThreadWeaver::Thread*
session.setData(createSessionData());
}
+ if (session.unit()) {
+ session.annihilateMissingIncludes(m_unsavedFiles, m_environment);
+ }
+
if (!session.unit()) {
// failed to parse file, unpin and don't try again
clang()->index()->unpinTranslationUnitForUrl(document());
diff --git a/languages/clang/duchain/parsesession.cpp b/languages/clang/duchain/parsesession.cpp
index aae0661..84dbfea 100644
--- a/languages/clang/duchain/parsesession.cpp
+++ b/languages/clang/duchain/parsesession.cpp
@@ -352,13 +353,70 @@ IndexedString ParseSession::languageString()
return lang;
}
+void ParseSession::annihilateMissingIncludes(
+ QVector<UnsavedFile>& unsavedFiles, const ClangParsingEnvironment& environment)
+{
+ d->m_staticProblems.clear();
+
+ // unfortunately clang dumps just 1 missing include per parse, so we can
+ // do only one correction per iteration
+ const int maxReparse = 20;
+ for (uint iReparse = 0; iReparse < maxReparse; ++iReparse) {
+ bool fixedMissing = false;
+ const uint numDiagnostics = clang_getNumDiagnostics(d->m_unit);
+ for (uint i = 0; i < numDiagnostics; ++i) {
+ auto diagnostic = clang_getDiagnostic(d->m_unit, i);
+
+ CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
+ if (ClangDiagnosticEvaluator::diagnosticType(diagnostic) == ClangDiagnosticEvaluator::IncludeFileNotFoundProblem) {
+ CXFile diagnosticFile;
+ uint line = 0;
+ clang_getFileLocation(location, &diagnosticFile, &line, nullptr, nullptr);
+ QString fileName = ClangString(clang_getFileName(diagnosticFile)).toString();
+ QStringList fileContents;
+ for (int i = 0; i < unsavedFiles.count(); ++i) {
+ if (unsavedFiles[i].filename() == fileName) {
+ fileContents = unsavedFiles[i].contents();
+ unsavedFiles.removeAt(i);
+ break;
+ }
+ }
+ if (fileContents.isEmpty()) { // need to read the file contents from disk
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ fileContents = QString::fromLocal8Bit(file.readAll()).split(QChar::fromLatin1('\n'));
+ }
+ }
+ line -= 1; // clang seems to start counting at 1
+ if (line < (uint)fileContents.count() && fileContents[line].simplified().contains(QLatin1String("#include "))) {
+ fileContents[line] = QString::fromLatin1("// REMOVED BY ANNIHILATION: ")+fileContents[line];
+ unsavedFiles << UnsavedFile(fileName, fileContents);
+ fixedMissing = true;
+ ProblemPointer problem = ProblemPointer(ClangDiagnosticEvaluator::createProblem(diagnostic, d->m_unit));
+ d->m_staticProblems[fileName] << problem;
+ d->m_staticProblems[ClangString(clang_getFileName(d->m_file)).toString()] << problem;
+ qDebug(KDEV_CLANG) << "annihilated missing include: " << problem->toString();
+ }
+ }
+ }
+ if (!fixedMissing) {
+ break;
+ }
+ qDebug(KDEV_CLANG) << "reparsing to fix missing includes";
+
+ if (!reparse(unsavedFiles, environment)) {
+ break;
+ }
+ }
+}
+
QList<ProblemPointer> ParseSession::problemsForFile(CXFile file) const
{
if (!d) {
return {};
}
- QList<ProblemPointer> problems;
+ QList<ProblemPointer> problems = d->m_staticProblems[ClangString(clang_getFileName(file)).toString()];
// extra clang diagnostics
const uint numDiagnostics = clang_getNumDiagnostics(d->m_unit);
@@ -369,9 +427,7 @@ QList<ProblemPointer> ParseSession::problemsForFile(CXFile file) const
CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
CXFile diagnosticFile;
clang_getFileLocation(location, &diagnosticFile, nullptr, nullptr, nullptr);
- // missing-include problems are so severe in clang that we always propagate
- // them to this document, to ensure that the user will see the error.
- if (diagnosticFile != file && ClangDiagnosticEvaluator::diagnosticType(diagnostic) != ClangDiagnosticEvaluator::IncludeFileNotFoundProblem) {
+ if (diagnosticFile != file) {
continue;
}
@@ -434,9 +490,12 @@ bool ParseSession::reparse(const QVector<UnsavedFile>& unsavedFiles, const Clang
const auto code = clang_reparseTranslationUnit(d->m_unit, unsaved.size(), unsaved.data(),
clang_defaultReparseOptions(d->m_unit));
- if (code != CXError_Success) {
- qWarning() << "clang_reparseTranslationUnit return with error code" << code;
+ if (code == CXError_Success) {
+ d->setUnit(d->m_unit);
+ return true;
+ } else {
// if error code != 0 => clang_reparseTranslationUnit invalidates the old translation unit => clean up
+ qWarning() << "clang_reparseTranslationUnit return with error code" << code;
clang_disposeTranslationUnit(d->m_unit);
d->setUnit(nullptr);
return false;
diff --git a/languages/clang/duchain/parsesession.h b/languages/clang/duchain/parsesession.h
index cd57c8a..e77617f 100644
--- a/languages/clang/duchain/parsesession.h
+++ b/languages/clang/duchain/parsesession.h
@@ -80,6 +80,7 @@ private:
/// TODO: share this file for all TUs that use the same defines (probably most in a project)
/// best would be a PCH, if possible
QTemporaryFile m_definesFile;
+ QMap<QString, QList<KDevelop::ProblemPointer>> m_staticProblems;
};
/**
@@ -127,6 +128,14 @@ public:
bool reparse(const QVector<UnsavedFile>& unsavedFiles, const ClangParsingEnvironment& environment);
+ /**
+ * If an #include was not found, then this adapts the unsaved-file data
+ * so that the problematic #include code line is removed.
+ * @return The corresponding problem-pointer. The problem-pointer is invalid
+ * if no problem as found.
+ */
+ void annihilateMissingIncludes(QVector<UnsavedFile>& unsavedFiles, const ClangParsingEnvironment& environment);
+
ClangParsingEnvironment environment() const;
private:
diff --git a/languages/clang/duchain/unsavedfile.cpp b/languages/clang/duchain/unsavedfile.cpp
index bef86df..8ab7b42 100644
--- a/languages/clang/duchain/unsavedfile.cpp
+++ b/languages/clang/duchain/unsavedfile.cpp
@@ -33,6 +33,17 @@ UnsavedFile::UnsavedFile(const QString& fileName, const QStringList& contents)
{
}
+QStringList UnsavedFile::contents() const
+{
+ Q_ASSERT(m_contentsUtf8.isEmpty() || !m_contents.isEmpty());
+ return m_contents;
+}
+
+QString UnsavedFile::filename() const
+{
+ return m_fileName;
+}
+
CXUnsavedFile UnsavedFile::toClangApi() const
{
if (m_fileNameUtf8.isEmpty()) {
diff --git a/languages/clang/duchain/unsavedfile.h b/languages/clang/duchain/unsavedfile.h
index a3442c7..e2050fa 100644
--- a/languages/clang/duchain/unsavedfile.h
+++ b/languages/clang/duchain/unsavedfile.h
@@ -38,6 +38,10 @@ public:
CXUnsavedFile toClangApi() const;
+ QStringList contents() const;
+
+ QString filename() const;
+
private:
QString m_fileName;
QStringList m_contents;
More information about the KDevelop-devel
mailing list