diff --git a/src/plugins/cpptools/cpppreprocessor.cpp b/src/plugins/cpptools/cpppreprocessor.cpp index f8d14bf123c..229d06885f1 100644 --- a/src/plugins/cpptools/cpppreprocessor.cpp +++ b/src/plugins/cpptools/cpppreprocessor.cpp @@ -355,7 +355,7 @@ void CppPreprocessor::mergeEnvironment(Document::Ptr doc) if (Document::Ptr includedDoc = m_snapshot.document(includedFile)) mergeEnvironment(includedDoc); - else + else if (!m_included.contains(includedFile)) run(includedFile); } diff --git a/src/plugins/cpptools/cpppreprocessor_test.cpp b/src/plugins/cpptools/cpppreprocessor_test.cpp index 5f6729bb0c0..17ab615b025 100644 --- a/src/plugins/cpptools/cpppreprocessor_test.cpp +++ b/src/plugins/cpptools/cpppreprocessor_test.cpp @@ -32,8 +32,12 @@ #include "cppmodelmanager.h" #include "cpppreprocessertesthelper.h" #include "cpppreprocessor.h" +#include "cppsnapshotupdater.h" +#include "cpptoolseditorsupport.h" #include "cpptoolstestcase.h" +#include + #include #include @@ -117,3 +121,43 @@ void CppToolsPlugin::test_cpppreprocessor_includes_resolvedUnresolved() QCOMPARE(unresolvedIncludes.at(0).unresolvedFileName(), QLatin1String("notresolvable.h")); QVERIFY(unresolvedIncludes.at(0).resolvedFileName().isEmpty()); } + +/// Check: Avoid self-include entries due to cyclic includes. +void CppToolsPlugin::test_cpppreprocessor_includes_cyclic() +{ + const QString fileName1 = TestIncludePaths::testFilePath(QLatin1String("cyclic1.h")); + const QString fileName2 = TestIncludePaths::testFilePath(QLatin1String("cyclic2.h")); + const QStringList sourceFiles = QStringList() << fileName1 << fileName2; + + // Create global snapshot (needed in SnapshotUpdater) + TestCase testCase; + testCase.parseFiles(sourceFiles); + + // Open editor + TextEditor::BaseTextEditor *editor; + QVERIFY(testCase.openBaseTextEditor(fileName1, &editor)); + testCase.closeEditorAtEndOfTestCase(editor); + + // Get editor snapshot + CppEditorSupport *cppEditorSupport = CppModelManagerInterface::instance() + ->cppEditorSupport(editor); + QVERIFY(cppEditorSupport); + QSharedPointer snapshotUpdater = cppEditorSupport->snapshotUpdater(); + QVERIFY(snapshotUpdater); + Snapshot snapshot = snapshotUpdater->snapshot(); + QCOMPARE(snapshot.size(), 3); // Configuration file included + + // Check includes + Document::Ptr doc1 = snapshot.document(fileName1); + QVERIFY(doc1); + Document::Ptr doc2 = snapshot.document(fileName2); + QVERIFY(doc2); + + QCOMPARE(doc1->unresolvedIncludes().size(), 0); + QCOMPARE(doc1->resolvedIncludes().size(), 1); + QCOMPARE(doc1->resolvedIncludes().first().resolvedFileName(), fileName2); + + QCOMPARE(doc2->unresolvedIncludes().size(), 0); + QCOMPARE(doc2->resolvedIncludes().size(), 1); + QCOMPARE(doc2->resolvedIncludes().first().resolvedFileName(), fileName1); +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 4e9c024ad12..05a137dc6ea 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -123,6 +123,7 @@ private slots: void test_format_pointerdeclaration_macros_data(); void test_cpppreprocessor_includes_resolvedUnresolved(); + void test_cpppreprocessor_includes_cyclic(); void test_functionutils_virtualFunctions(); void test_functionutils_virtualFunctions_data(); diff --git a/src/plugins/cpptools/cpptoolstestcase.cpp b/src/plugins/cpptools/cpptoolstestcase.cpp index 7c46ec84b0b..12c0218270d 100644 --- a/src/plugins/cpptools/cpptoolstestcase.cpp +++ b/src/plugins/cpptools/cpptoolstestcase.cpp @@ -30,6 +30,7 @@ #include "cpptoolstestcase.h" #include +#include #include #include @@ -100,6 +101,18 @@ bool TestCase::succeededSoFar() const return m_succeededSoFar; } +bool TestCase::openBaseTextEditor(const QString &fileName, TextEditor::BaseTextEditor **editor) +{ + typedef TextEditor::BaseTextEditor BTEditor; + if (BTEditor *e = qobject_cast(Core::EditorManager::openEditor(fileName))) { + if (editor) { + *editor = e; + return true; + } + } + return false; +} + CPlusPlus::Snapshot TestCase::globalSnapshot() { return CppModelManagerInterface::instance()->snapshot(); diff --git a/src/plugins/cpptools/cpptoolstestcase.h b/src/plugins/cpptools/cpptoolstestcase.h index 7fac75f5e3f..a3c2529568a 100644 --- a/src/plugins/cpptools/cpptoolstestcase.h +++ b/src/plugins/cpptools/cpptoolstestcase.h @@ -42,6 +42,7 @@ class Document; class Snapshot; } namespace Core { class IEditor; } +namespace TextEditor { class BaseTextEditor; } namespace CppTools { namespace Tests { @@ -69,6 +70,7 @@ public: ~TestCase(); bool succeededSoFar() const; + bool openBaseTextEditor(const QString &fileName, TextEditor::BaseTextEditor **editor); void closeEditorAtEndOfTestCase(Core::IEditor *editor); static bool closeEditorWithoutGarbageCollectorInvocation(Core::IEditor *editor); diff --git a/tests/auto/cplusplus/preprocessor/data/include-data/local/cyclic1.h b/tests/auto/cplusplus/preprocessor/data/include-data/local/cyclic1.h new file mode 100644 index 00000000000..759a36b8011 --- /dev/null +++ b/tests/auto/cplusplus/preprocessor/data/include-data/local/cyclic1.h @@ -0,0 +1 @@ +#include "cyclic2.h" diff --git a/tests/auto/cplusplus/preprocessor/data/include-data/local/cyclic2.h b/tests/auto/cplusplus/preprocessor/data/include-data/local/cyclic2.h new file mode 100644 index 00000000000..680b4ebf7da --- /dev/null +++ b/tests/auto/cplusplus/preprocessor/data/include-data/local/cyclic2.h @@ -0,0 +1 @@ +#include "cyclic1.h"