Merge remote-tracking branch 'origin/3.5'

Change-Id: I1ce0fa92e5c469d591d3030d1a4f168dcee232ba
This commit is contained in:
Eike Ziller
2015-08-06 11:36:29 +02:00
34 changed files with 523 additions and 380 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -55,19 +55,20 @@
\endlist \endlist
An IDE needs a parser for the language and the semantic analyzes. The only An IDE needs a parser for the language and the semantic analyzes.
difference between a code model and a compiler is that a code model does not
generate an executable.
As \l{http://clang.llvm.org/}{Clang} is a compiler, as well as a code model, \section1 Using Clang Code Model
it provides accurate information. The feedback you get through warning and
error markers is the same as the compiler will give you, not an incomplete The \l{http://clang.llvm.org/}{Clang} project provides libraries for parsing
C and C++ source files. The feedback you get through warning and
error markers is the same as a compiler will give you, not an incomplete
set or a close approximation, as when using the built-in \QC code model. set or a close approximation, as when using the built-in \QC code model.
Clang focuses on detailed information for diagnostics, which is really Clang focuses on detailed information for diagnostics, which is really
useful if the code contains typos, for example. useful if the code contains typos, for example.
Also, Clang already supports C++98/03, C89 and C99, Objective-C (and Clang keeps up with the development of the C++ language. At the time of this
Objective-C++), and C++11 support is in active development. writing, it supports C++98/03, C++11, C++14, C89, C99, Objective-C, and
Objective-C++.
On the downside, for large projects using Clang as code model is slower than On the downside, for large projects using Clang as code model is slower than
using the built-in code model. Clang does not need to generate object files, using the built-in code model. Clang does not need to generate object files,
@@ -84,14 +85,14 @@
\list \list
\li Highlighting
\li Code completion \li Code completion
\li Syntactic and semantic highlighting
\endlist \endlist
To use the plugin, you must build it and configure it in \QC. To use the plugin, you must build it and configure it in \QC.
\section1 Building Clang Code Model Plugin \section2 Building Clang Code Model Plugin
\list 1 \list 1
@@ -138,7 +139,7 @@
\li Installed via package manager on Linux: \li Installed via package manager on Linux:
\c {LLVM_INSTALL_DIR=/usr/lib/llvm-3.4} \c {LLVM_INSTALL_DIR=/usr/lib/llvm-3.6}
\li Manually built on Unix in release mode: \li Manually built on Unix in release mode:
@@ -154,7 +155,7 @@
\endlist \endlist
\section1 Configuring Clang Code Model Plugin \section2 Configuring Clang Code Model Plugin
\list 1 \list 1

View File

@@ -168,8 +168,8 @@
\key {Ctrl+E,F2} to follow the symbol in the next split. If necessary, the \key {Ctrl+E,F2} to follow the symbol in the next split. If necessary, the
view is automatically split. To change the default behavior, select view is automatically split. To change the default behavior, select
\uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} >
\uicontrol Display, and then select \uicontrol Display > \uicontrol {Always open links in another split}.
\uicontrol {Always Open Links in Next Split}. Additional symbols are Additional symbols are
displayed and switching between definition and declaration is done in displayed and switching between definition and declaration is done in
another split. If you change the default behavior, the shortcuts for opening another split. If you change the default behavior, the shortcuts for opening
link targets in the next split are used to open them in the current split. link targets in the next split are used to open them in the current split.
@@ -197,5 +197,5 @@
\QC underlines semantic errors in olive in the C++ code editor. To check the \QC underlines semantic errors in olive in the C++ code editor. To check the
correct paths for includes that are not resolved or that are resolved to the correct paths for includes that are not resolved or that are resolved to the
wrong file, select \uicontrol {Project Parts} > \uicontrol {Include Paths}. wrong file, select \uicontrol {Project Parts} > \uicontrol {Header Paths}.
*/ */

View File

@@ -787,9 +787,9 @@
Select \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} Select \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor}
> \uicontrol Completion. > \uicontrol Completion.
By default, code completion considers only the first letter case-sensitive. By default, code completion does not consider case. To apply full or
To apply full or no case-sensitivity, select the option in the first-letter case-sensitivity, select \uicontrol Full or
\uicontrol {Case-sensitivity} field. \uicontrol {First Letter} in the \uicontrol {Case-sensitivity} field.
\section2 Summary of Available Types \section2 Summary of Available Types
@@ -1291,7 +1291,8 @@
\section2 Specifying Tabs and Indentation \section2 Specifying Tabs and Indentation
You can specify tab policy and tab size in the \uicontrol Typing group. In You can specify tab policy and tab size in the
\uicontrol {Tabs and Indentation} group. In
the \uicontrol {Tab policy} field, select whether to use only spaces or the \uicontrol {Tab policy} field, select whether to use only spaces or
only tabs for indentation, or to use a mixture of them. only tabs for indentation, or to use a mixture of them.
@@ -1416,7 +1417,7 @@
\li To search only whole words, select \uicontrol {Whole Words Only}. \li To search only whole words, select \uicontrol {Whole Words Only}.
\li To search using regular expressions, select \li To search using regular expressions, select
\uicontrol {Regular Expressions}. Regular expressions used in \QC \uicontrol {Use Regular Expressions}. Regular expressions used in \QC
are modeled on Perl regular expressions. For more information on are modeled on Perl regular expressions. For more information on
using regular expressions, see the documentation for the using regular expressions, see the documentation for the
QRegularExpression Class. QRegularExpression Class.
@@ -1444,7 +1445,7 @@
The \uicontrol {Preserve Case when Replacing} option can be selected to The \uicontrol {Preserve Case when Replacing} option can be selected to
preserve the case of the original text when replacing. This option is not preserve the case of the original text when replacing. This option is not
compatible with the \uicontrol {Regular Expressions} search option, and will compatible with the \uicontrol {Use Regular Expressions} search option, and will
thus be disabled when regular expressions are used. When the option is used, thus be disabled when regular expressions are used. When the option is used,
the case of the occurrence will be conserved, according to the following the case of the occurrence will be conserved, according to the following
rules: rules:
@@ -1469,7 +1470,7 @@
The locations of search hits, breakpoints, and bookmarks in your document The locations of search hits, breakpoints, and bookmarks in your document
are highlighted on the editor scroll bar. To turn highlighting off, select are highlighted on the editor scroll bar. To turn highlighting off, select
\uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} >
\uicontrol {Highlight search results on the scrollbar}. \uicontrol Display > \uicontrol {Highlight search results on the scrollbar}.
\section1 Advanced Search \section1 Advanced Search
@@ -2532,8 +2533,8 @@
\li Specify the prefix string. \li Specify the prefix string.
\li To show only results matching this filter, select \li To implicitly include the filter even when not typing a prefix as a
\uicontrol {Limit to prefix}. part of the search string, select \uicontrol {Include by default}.
\li Specify other available options. For more information, see \li Specify other available options. For more information, see
\l{Adding Web Search Engines}. \l{Adding Web Search Engines}.
@@ -2601,8 +2602,9 @@
\li Specify the prefix string. \li Specify the prefix string.
To show only results matching this filter, select To implicitly include the filter even when not typing a prefix
\uicontrol {Limit to prefix}. as a part of the search string, select
\uicontrol {Include by default}.
\image qtcreator-navigate-customfilter.png \image qtcreator-navigate-customfilter.png

View File

@@ -50,19 +50,20 @@
and integrated into \QC. The correct folder to place the plugins depends on and integrated into \QC. The correct folder to place the plugins depends on
whether you use the standalone \QD or the integrated \QD. whether you use the standalone \QD or the integrated \QD.
The integrated \QD fetches plugins from the \c {%SDK%\bin\designer} folder The integrated \QD fetches plugins from the \c {\bin\plugins\designer}
on Windows and Linux. For information about how to configure plugins on directory in the \QC installation directory on Windows and Linux. For
OS X, see \l{Configuring Qt Designer Plugins on OS X}. information about how to configure plugins on OS X, see
\l{Configuring Qt Designer Plugins on OS X}.
To check which plugins To check which plugins were loaded successfully and which failed, choose
were loaded successfully and which failed, choose \uicontrol{Tools > Form Editor > \uicontrol Tools > \uicontrol {Form Editor} >
About Qt Designer Plugins}. \uicontrol {About Qt Designer Plugins}.
The standalone \QD is part of the Qt library used for building projects, The standalone \QD is part of the Qt library used for building projects,
located under \c {%SDK%\qt}. Therefore, it fetches plugins from the located in \c {<Qt_version>\<compiler>\bin} in the Qt installation
following folder: \c {%SDK%\qt\plugins\designer}. To check which plugins directory. It fetches plugins from the \c {\plugins\designer} subdirectory
were loaded successfully and which failed, choose \uicontrol{Help > of \c bin. To check which plugins were loaded successfully and which failed,
About Plugins}. choose \uicontrol Help > \uicontrol {About Plugins}.
\section2 Configuring Qt Designer Plugins on OS X \section2 Configuring Qt Designer Plugins on OS X

150
scripts/clangCompleteAt.sh Executable file
View File

@@ -0,0 +1,150 @@
#!/bin/sh
################################################################################
# Copyright (C) 2015 The Qt Company Ltd.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of The Qt Company Ltd, nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
################################################################################
# --- helpers -----------------------------------------------------------------
printUsage()
{
echo "Usage: $0 [-v] [-c clang-executable] file line column"
echo
echo "Options:"
echo " -v Run c-index-test instead of clang to get more details."
echo " -c clang-executable Use the provided clang-executable."
echo
echo "The clang executable is determined by this order:"
echo " 1. Use clang from the -c option."
echo " 2. Use clang from environment variable CLANG_FOR_COMPLETION."
echo " 3. Use clang from \$PATH."
echo
echo "Path to c-index-test will be determined with the help of the clang executable."
}
# There is no readlink on cygwin.
hasReadLink()
{
return $(command -v readlink >/dev/null 2>&1)
}
checkIfFileExistsOrDie()
{
[ ! -f "$1" ] && echo "'$1' is not a file or does not exist." && exit 1
}
checkIfFileExistsAndIsExecutableOrDie()
{
checkIfFileExistsOrDie "$1"
[ ! -x "$1" ] && echo "'$1' is not executable." && exit 2
}
findClangOrDie()
{
if [ -z "$CLANG_EXEC" ]; then
if [ -n "${CLANG_FOR_COMPLETION}" ]; then
CLANG_EXEC=${CLANG_FOR_COMPLETION}
else
CLANG_EXEC=$(which clang)
fi
fi
hasReadLink && CLANG_EXEC=$(readlink -e "$CLANG_EXEC")
checkIfFileExistsAndIsExecutableOrDie "$CLANG_EXEC"
}
findCIndexTestOrDie()
{
if [ -n "$RUN_WITH_CINDEXTEST" ]; then
CINDEXTEST_EXEC=$(echo $CLANG_EXEC | sed -e 's/clang/c-index-test/g')
hasReadLink && CINDEXTEST_EXEC=$(readlink -e "$CINDEXTEST_EXEC")
checkIfFileExistsAndIsExecutableOrDie "$CINDEXTEST_EXEC"
fi
}
printClangVersion()
{
command="${CLANG_EXEC} --version"
echo "Command: $command"
eval $command
}
runCodeCompletion()
{
if [ -n "${CINDEXTEST_EXEC}" ]; then
command="${CINDEXTEST_EXEC} -code-completion-at=${FILE}:${LINE}:${COLUMN} ${FILE}"
else
command="${CLANG_EXEC} -cc1 -code-completion-at ${FILE}:${LINE}:${COLUMN} ${FILE}"
fi
echo "Command: $command"
eval $command
}
# --- Process arguments -------------------------------------------------------
CLANG_EXEC=
RUN_WITH_CINDEXTEST=
FILE=
LINE=
COLUMN=
while [ -n "$1" ]; do
param=$1
shift
case $param in
-h | -help | --help)
printUsage
exit 0
;;
-v | -verbose | --verbose)
RUN_WITH_CINDEXTEST=1
;;
-c | -clang | --clang)
CLANG_EXEC=$1
shift
;;
*)
break;
;;
esac
done
[ "$#" -ne 2 ] && printUsage && exit 1
checkIfFileExistsOrDie "$param"
FILE=$param
LINE=$1
COLUMN=$2
# --- main --------------------------------------------------------------------
findClangOrDie
findCIndexTestOrDie
printClangVersion
echo
runCodeCompletion

View File

@@ -56,6 +56,6 @@ QtcProduct {
Group { Group {
fileTagsFilter: product.type fileTagsFilter: product.type
qbs.install: true qbs.install: true
qbs.installDir: project.ide_app_path qbs.installDir: project.ide_bin_path
} }
} }

View File

@@ -847,7 +847,6 @@ void PluginManagerPrivate::nextDelayedInitialize()
\internal \internal
*/ */
PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) : PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) :
m_failedTests(0),
delayedInitializeTimer(0), delayedInitializeTimer(0),
shutdownEventLoop(0), shutdownEventLoop(0),
m_profileElapsedMS(0), m_profileElapsedMS(0),
@@ -1127,6 +1126,7 @@ void PluginManagerPrivate::startTests()
return; return;
} }
int failedTests = 0;
foreach (const PluginManagerPrivate::TestSpec &testSpec, testSpecs) { foreach (const PluginManagerPrivate::TestSpec &testSpec, testSpecs) {
IPlugin *plugin = testSpec.pluginSpec->plugin(); IPlugin *plugin = testSpec.pluginSpec->plugin();
if (!plugin) if (!plugin)
@@ -1144,10 +1144,10 @@ void PluginManagerPrivate::startTests()
? generateCompleteTestPlan(plugin, testObjects) ? generateCompleteTestPlan(plugin, testObjects)
: generateCustomTestPlan(plugin, testObjects, testSpec.testFunctionsOrObjects); : generateCustomTestPlan(plugin, testObjects, testSpec.testFunctionsOrObjects);
m_failedTests += executeTestPlan(testPlan); failedTests += executeTestPlan(testPlan);
} }
if (!testSpecs.isEmpty())
QTimer::singleShot(1, this, SLOT(exitWithNumberOfFailedTests())); QTimer::singleShot(0, this, [failedTests]() { emit m_instance->testsFinished(failedTests); });
} }
#endif #endif
@@ -1270,14 +1270,6 @@ void PluginManagerPrivate::asyncShutdownFinished()
shutdownEventLoop->exit(); shutdownEventLoop->exit();
} }
/*!
\internal
*/
void PluginManagerPrivate::exitWithNumberOfFailedTests()
{
QCoreApplication::exit(m_failedTests);
}
/*! /*!
\internal \internal
*/ */

View File

@@ -158,6 +158,7 @@ signals:
void pluginsChanged(); void pluginsChanged();
void initializationDone(); void initializationDone();
void testsFinished(int failedTests);
public slots: public slots:
void remoteArguments(const QString &serializedArguments, QObject *socket); void remoteArguments(const QString &serializedArguments, QObject *socket);

View File

@@ -102,7 +102,6 @@ public:
QHash<QString, PluginCollection *> pluginCategories; QHash<QString, PluginCollection *> pluginCategories;
QList<PluginSpec *> pluginSpecs; QList<PluginSpec *> pluginSpecs;
QList<TestSpec> testSpecs; QList<TestSpec> testSpecs;
int m_failedTests;
QStringList pluginPaths; QStringList pluginPaths;
QString pluginIID; QString pluginIID;
QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ? QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ?
@@ -138,7 +137,6 @@ public:
private slots: private slots:
void nextDelayedInitialize(); void nextDelayedInitialize();
void asyncShutdownFinished(); void asyncShutdownFinished();
void exitWithNumberOfFailedTests();
private: private:
PluginCollection *defaultCollection; PluginCollection *defaultCollection;

View File

@@ -440,6 +440,8 @@ Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInf
"Import paths:\n" "Import paths:\n"
"%1\n\n" "%1\n\n"
"For qmake projects, use the QML_IMPORT_PATH variable to add import paths.\n" "For qmake projects, use the QML_IMPORT_PATH variable to add import paths.\n"
"For qbs projects, declare and set a qmlImportPaths property in your product "
"to add import paths.\n"
"For qmlproject projects, use the importPaths property to add import paths.").arg( "For qmlproject projects, use the importPaths property to add import paths.").arg(
importPaths.join(QLatin1Char('\n')))); importPaths.join(QLatin1Char('\n'))));
} }

View File

@@ -1,59 +1 @@
The ClangCodeModel plugin See ../../../doc/src/editors/creator-clang-codemodel.qdoc
=========================
The ClangCodeModel plugin integrates the clang frontend into Qt Creator. Clang
is "a C language family frontend for LLVM". You can find more information at
http://clang.llvm.org/.
At the time of writing the plugin can replace the following functionality of
the built-in code model:
* Highlighting
* Completion
All other functionality relies on the built-in code model (indexing, quick
fixes, follow symbol, find usages, ...).
Setup
=====
Compile the plugin
------------------
1. Get libclang
You need to have libclang (and thus llvm) installed on your system. Either
build llvm/clang yourself [1], install some ready-to-use package [2] or use the
package manager of your system.
[1] http://clang.llvm.org/get_started.html
See http://llvm.org/docs/GettingStarted.html#git-mirror for git mirrors.
[2] http://llvm.org/releases/ or http://llvm.org/builds/
If you are building llvm/clang yourself, make sure to build it in release mode.
2. Set LLVM_INSTALL_DIR and (re)build Qt Creator
Point the LLVM_INSTALL_DIR variable to the build/installation directory of
llvm, e.g.:
Installed via package manager on GNU/Linux:
LLVM_INSTALL_DIR=/usr/lib/llvm-3.4
Manually build on Unix in release mode:
LLVM_INSTALL_DIR=$HOME/llvm-build/Release+Asserts
Installed a snapshot on Windows:
LLVM_INSTALL_DIR=C:\llvm
Set the variable either as part of the build environment or pass it directly to
qmake and rebuild Qt Creator.
Enable the plugin
-----------------
Enable the "ClangCodeModel" plugin in the dialog "Menu: Help -> About Plugins"
and restart Qt Creator.
Select the file types you want to use the ClangCodeModel for in "Menu: Tools ->
Options -> C++ -> Tab: Code Model". For the next opened file matching the
selected file types the ClangCodeModel will be used (see limitations at the
start of this README).

View File

@@ -44,6 +44,7 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QRegExp>
#include <QSet> #include <QSet>
#include <QString> #include <QString>
@@ -147,7 +148,17 @@ private:
bool excludeHeaderPath(const QString &path) const override bool excludeHeaderPath(const QString &path) const override
{ {
return path.contains(QLatin1String("lib/gcc/i686-apple-darwin")); if (path.contains(QLatin1String("lib/gcc/i686-apple-darwin")))
return true;
// We already provide a custom clang include path matching the used libclang version,
// so better ignore the clang include paths from the system as this might lead to an
// unfavorable order with regard to include_next.
static QRegExp clangIncludeDir(QLatin1String(".*/lib/clang/\\d+\\.\\d+\\.\\d+/include"));
if (clangIncludeDir.exactMatch(path))
return true;
return false;
} }
void addResourceDirOptions() void addResourceDirOptions()

View File

@@ -79,6 +79,16 @@ void CompletionChunksToTextConverter::setAddExtraVerticalSpaceBetweenBraces(bool
m_addExtraVerticalSpaceBetweenBraces = addExtraVerticalSpaceBetweenBraces; m_addExtraVerticalSpaceBetweenBraces = addExtraVerticalSpaceBetweenBraces;
} }
void CompletionChunksToTextConverter::setAddHtmlTags(bool addHtmlTags)
{
m_addHtmlTags = addHtmlTags;
}
void CompletionChunksToTextConverter::setAddOptional(bool addOptional)
{
m_addOptional = addOptional;
}
const QString &CompletionChunksToTextConverter::text() const const QString &CompletionChunksToTextConverter::text() const
{ {
return m_text; return m_text;
@@ -99,6 +109,7 @@ QString CompletionChunksToTextConverter::convertToFunctionSignature(const ClangB
CompletionChunksToTextConverter converter; CompletionChunksToTextConverter converter;
converter.setAddPlaceHolderText(true); converter.setAddPlaceHolderText(true);
converter.setAddResultType(true); converter.setAddResultType(true);
converter.setAddOptional(true);
converter.parseChunks(codeCompletionChunks); converter.parseChunks(codeCompletionChunks);
@@ -120,6 +131,9 @@ QString CompletionChunksToTextConverter::convertToToolTip(const ClangBackEnd::Co
converter.setAddPlaceHolderText(true); converter.setAddPlaceHolderText(true);
converter.setAddSpaces(true); converter.setAddSpaces(true);
converter.setAddExtraVerticalSpaceBetweenBraces(true); converter.setAddExtraVerticalSpaceBetweenBraces(true);
converter.setAddOptional(true);
converter.setAddHtmlTags(true);
converter.setAddResultType(true);
converter.parseChunks(codeCompletionChunks); converter.parseChunks(codeCompletionChunks);
@@ -158,11 +172,15 @@ void CompletionChunksToTextConverter::parseText(const Utf8String &text)
void CompletionChunksToTextConverter::parseOptional(const ClangBackEnd::CodeCompletionChunk &optionalCodeCompletionChunk) void CompletionChunksToTextConverter::parseOptional(const ClangBackEnd::CodeCompletionChunk &optionalCodeCompletionChunk)
{ {
if (m_addOptional) {
if (m_addHtmlTags)
m_text += QStringLiteral("<i>"); m_text += QStringLiteral("<i>");
m_text += convertToFunctionSignature(optionalCodeCompletionChunk.optionalChunks()); m_text += convertToFunctionSignature(optionalCodeCompletionChunk.optionalChunks());
if (m_addHtmlTags)
m_text += QStringLiteral("</i>"); m_text += QStringLiteral("</i>");
}
} }
void CompletionChunksToTextConverter::parsePlaceHolder(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) void CompletionChunksToTextConverter::parsePlaceHolder(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)

View File

@@ -52,6 +52,8 @@ public:
void setAddResultType(bool addResultType); void setAddResultType(bool addResultType);
void setAddSpaces(bool addSpaces); void setAddSpaces(bool addSpaces);
void setAddExtraVerticalSpaceBetweenBraces(bool addExtraVerticalSpaceBetweenBraces); void setAddExtraVerticalSpaceBetweenBraces(bool addExtraVerticalSpaceBetweenBraces);
void setAddHtmlTags(bool addHtmlTags);
void setAddOptional(bool addOptional);
const QString &text() const; const QString &text() const;
const std::vector<int> &placeholderPositions() const; const std::vector<int> &placeholderPositions() const;
@@ -83,6 +85,8 @@ private:
bool m_addResultType = false; bool m_addResultType = false;
bool m_addSpaces = false; bool m_addSpaces = false;
bool m_addExtraVerticalSpaceBetweenBraces = false; bool m_addExtraVerticalSpaceBetweenBraces = false;
bool m_addHtmlTags = false;
bool m_addOptional = false;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -868,8 +868,8 @@ void ClangCodeCompletionTest::testCompleteFunctions()
QVERIFY(hasItem(t.proposal, "void f()")); QVERIFY(hasItem(t.proposal, "void f()"));
QVERIFY(hasItem(t.proposal, "void f(int a)")); QVERIFY(hasItem(t.proposal, "void f(int a)"));
QVERIFY(hasItem(t.proposal, "void f(const QString &s)")); QVERIFY(hasItem(t.proposal, "void f(const QString &s)"));
QVERIFY(hasItem(t.proposal, "void f(char c<i>, int optional</i>)")); // TODO: No default argument? QVERIFY(hasItem(t.proposal, "void f(char c, int optional)")); // TODO: No default argument?
QVERIFY(hasItem(t.proposal, "void f(char c<i>, int optional1, int optional2</i>)")); // TODO: No default argument? QVERIFY(hasItem(t.proposal, "void f(char c, int optional1, int optional2)")); // TODO: No default argument?
QVERIFY(hasItem(t.proposal, "void f(const TType<QString> *t)")); QVERIFY(hasItem(t.proposal, "void f(const TType<QString> *t)"));
QVERIFY(hasItem(t.proposal, "TType<QString> f(bool)")); QVERIFY(hasItem(t.proposal, "TType<QString> f(bool)"));
} }

View File

@@ -323,6 +323,10 @@ ICore::ICore(MainWindow *mainwindow)
// Save settings once after all plugins are initialized: // Save settings once after all plugins are initialized:
connect(PluginManager::instance(), SIGNAL(initializationDone()), connect(PluginManager::instance(), SIGNAL(initializationDone()),
this, SLOT(saveSettings())); this, SLOT(saveSettings()));
connect(PluginManager::instance(), &PluginManager::testsFinished, [this] (int failedTests) {
emit coreAboutToClose();
QCoreApplication::exit(failedTests);
});
connect(m_mainwindow, SIGNAL(newItemDialogRunningChanged()), connect(m_mainwindow, SIGNAL(newItemDialogRunningChanged()),
this, SIGNAL(newItemDialogRunningChanged())); this, SIGNAL(newItemDialogRunningChanged()));
} }

View File

@@ -100,7 +100,7 @@ bool DirectoryFilter::openConfigDialog(QWidget *parent, bool &needsRefresh)
m_ui.prefixLabel->setText(ILocatorFilter::msgPrefixLabel()); m_ui.prefixLabel->setText(ILocatorFilter::msgPrefixLabel());
m_ui.prefixLabel->setToolTip(ILocatorFilter::msgPrefixToolTip()); m_ui.prefixLabel->setToolTip(ILocatorFilter::msgPrefixToolTip());
m_ui.defaultFlag->setText(ILocatorFilter::msgIncludeByDefault()); m_ui.defaultFlag->setText(ILocatorFilter::msgIncludeByDefault());
m_ui.defaultFlag->setText(ILocatorFilter::msgIncludeByDefaultToolTip()); m_ui.defaultFlag->setToolTip(ILocatorFilter::msgIncludeByDefaultToolTip());
connect(m_ui.addButton, &QPushButton::clicked, connect(m_ui.addButton, &QPushButton::clicked,
this, &DirectoryFilter::addDirectory, Qt::DirectConnection); this, &DirectoryFilter::addDirectory, Qt::DirectConnection);
connect(m_ui.editButton, &QPushButton::clicked, connect(m_ui.editButton, &QPushButton::clicked,

View File

@@ -230,6 +230,9 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
const QString toolchainPrefix = extractToolchainPrefix(&compilerName); const QString toolchainPrefix = extractToolchainPrefix(&compilerName);
if (!toolchainPrefix.isEmpty()) if (!toolchainPrefix.isEmpty())
data.insert(QLatin1String(CPP_TOOLCHAINPREFIX), toolchainPrefix); data.insert(QLatin1String(CPP_TOOLCHAINPREFIX), toolchainPrefix);
if (toolchain.contains(QLatin1String("msvc")))
data.insert(QLatin1String(CPP_COMPILERNAME), compilerName);
else
data.insert(QLatin1String(CPP_CXXCOMPILERNAME), compilerName); data.insert(QLatin1String(CPP_CXXCOMPILERNAME), compilerName);
if (targetAbi.os() != ProjectExplorer::Abi::WindowsOS if (targetAbi.os() != ProjectExplorer::Abi::WindowsOS
|| targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) { || targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
@@ -237,6 +240,13 @@ QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplor
} }
data.insert(QLatin1String(CPP_TOOLCHAINPATH), cxxFileInfo.absolutePath()); data.insert(QLatin1String(CPP_TOOLCHAINPATH), cxxFileInfo.absolutePath());
// TODO: Remove this once compiler version properties are set for MSVC
if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2013Flavor
|| targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvc2015Flavor) {
const QLatin1String flags("/FS");
data.insert(QLatin1String(CPP_PLATFORMCFLAGS), flags);
data.insert(QLatin1String(CPP_PLATFORMCXXFLAGS), flags);
}
return data; return data;
} }

View File

@@ -41,8 +41,11 @@ const char QBS_ARCHITECTURE[] = "qbs.architecture";
const char QBS_TOOLCHAIN[] = "qbs.toolchain"; const char QBS_TOOLCHAIN[] = "qbs.toolchain";
const char CPP_TOOLCHAINPATH[] = "cpp.toolchainInstallPath"; const char CPP_TOOLCHAINPATH[] = "cpp.toolchainInstallPath";
const char CPP_TOOLCHAINPREFIX[] = "cpp.toolchainPrefix"; const char CPP_TOOLCHAINPREFIX[] = "cpp.toolchainPrefix";
const char CPP_COMPILERNAME[] = "cpp.compilerName";
const char CPP_CXXCOMPILERNAME[] = "cpp.cxxCompilerName"; const char CPP_CXXCOMPILERNAME[] = "cpp.cxxCompilerName";
const char CPP_LINKERNAME[] = "cpp.linkerName"; const char CPP_LINKERNAME[] = "cpp.linkerName";
const char CPP_PLATFORMCFLAGS[] = "cpp.platformCFlags";
const char CPP_PLATFORMCXXFLAGS[] = "cpp.platformCxxFlags";
const char CPP_PLATFORMPATH[] = "cpp.platformPath"; const char CPP_PLATFORMPATH[] = "cpp.platformPath";
const char CPP_XCODESDKNAME[] = "cpp.xcodeSdkName"; const char CPP_XCODESDKNAME[] = "cpp.xcodeSdkName";
const char CPP_XCODESDKVERSION[] = "cpp.xcodeSdkVersion"; const char CPP_XCODESDKVERSION[] = "cpp.xcodeSdkVersion";

View File

@@ -858,6 +858,13 @@ void QbsProject::updateQmlJsCodeModel()
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
modelManager->defaultProjectInfoForProject(this); modelManager->defaultProjectInfoForProject(this);
foreach (const qbs::ProductData &product, m_projectData.allProducts()) {
static const QString propertyName = QLatin1String("qmlImportPaths");
foreach (const QString &path, product.properties().value(propertyName).toStringList()) {
projectInfo.importPaths.maybeInsert(Utils::FileName::fromString(path),
QmlJS::Dialect::Qml);
}
}
setProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS, !projectInfo.sourceFiles.isEmpty()); setProjectLanguage(ProjectExplorer::Constants::LANG_QMLJS, !projectInfo.sourceFiles.isEmpty());
modelManager->updateProjectInfo(projectInfo, this); modelManager->updateProjectInfo(projectInfo, this);

View File

@@ -366,7 +366,7 @@ TEST_F(CodeCompletionsExtractor, Enumerator)
CodeCompletion::Available)); CodeCompletion::Available));
} }
TEST_F(CodeCompletionsExtractor, Constructor) TEST_F(CodeCompletionsExtractor, DISABLED_Constructor)
{ {
ClangCodeCompleteResults completeResults(getResults(constructorTranslationUnit, 20)); ClangCodeCompleteResults completeResults(getResults(constructorTranslationUnit, 20));

View File

@@ -28,107 +28,200 @@
** **
****************************************************************************/ ****************************************************************************/
#include "gtest/gtest.h"
#include "gmock/gmock-matchers.h"
#include "gtest-qt-printing.h"
#include <codecompleter.h> #include <codecompleter.h>
#include <filecontainer.h> #include <filecontainer.h>
#include <projectpart.h>
#include <translationunit.h> #include <translationunit.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <utf8stringvector.h> #include <utf8stringvector.h>
#include <projectpart.h>
#include <QFile> #include <QFile>
#include <QTemporaryDir>
#include <gmock/gmock.h>
#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include "gtest-qt-printing.h"
using ::testing::ElementsAreArray; using ::testing::ElementsAreArray;
using ::testing::Contains; using ::testing::Contains;
using ::testing::AllOf; using ::testing::AllOf;
using ::testing::Not; using ::testing::Not;
using ::testing::PrintToString;
using ClangBackEnd::CodeCompletion; using ClangBackEnd::CodeCompletion;
using ClangBackEnd::CodeCompleter; using ClangBackEnd::CodeCompleter;
namespace { namespace {
MATCHER_P2(IsCodeCompletion, text, completionKind,
std::string(negation ? "isn't" : "is") + " code completion with text "
+ PrintToString(text) + " and kind " + PrintToString(completionKind)
)
{
if (arg.text() != text) {
*result_listener << "text is " + PrintToString(arg.text()) + " and not " + PrintToString(text);
return false;
}
if (arg.completionKind() != completionKind) {
*result_listener << "kind is " + PrintToString(arg.completionKind()) + " and not " + PrintToString(completionKind);
return false;
}
return true;
}
class CodeCompleter : public ::testing::Test class CodeCompleter : public ::testing::Test
{ {
public: protected:
static void SetUpTestCase(); void SetUp();
static void TearDownTestCase(); void copyTargetHeaderToTemporaryIncludeDirecory();
void copyChangedTargetHeaderToTemporaryIncludeDirecory();
static Utf8String readFileContent(const QString &fileName);
protected: protected:
static ClangBackEnd::ProjectPart projectPart; QTemporaryDir includeDirectory;
static ClangBackEnd::UnsavedFiles unsavedFiles; QString targetHeaderPath{includeDirectory.path() + QStringLiteral("/complete_target_header.h")};
static ClangBackEnd::TranslationUnit translationUnit; ClangBackEnd::ProjectPart projectPart{Utf8StringLiteral("projectPartId")};
static ClangBackEnd::CodeCompleter completer; ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_completer_main.cpp"),
unsavedFiles,
projectPart};
ClangBackEnd::CodeCompleter completer{translationUnit};
ClangBackEnd::FileContainer unsavedMainFileContainer{translationUnit.filePath(),
projectPart.projectPartId(),
readFileContent(QStringLiteral("/complete_completer_main_unsaved.cpp")),
true};
ClangBackEnd::FileContainer unsavedTargetHeaderFileContainer{targetHeaderPath,
projectPart.projectPartId(),
readFileContent(QStringLiteral("/complete_target_header_unsaved.h")),
true};
}; };
ClangBackEnd::ProjectPart CodeCompleter::projectPart(Utf8StringLiteral("projectPartId")); Utf8String CodeCompleter::readFileContent(const QString &fileName)
ClangBackEnd::UnsavedFiles CodeCompleter::unsavedFiles;
ClangBackEnd::TranslationUnit CodeCompleter::translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_completer.cpp"), unsavedFiles, projectPart);
ClangBackEnd::CodeCompleter CodeCompleter::completer = translationUnit;
void CodeCompleter::SetUpTestCase()
{ {
QFile unsavedFileContentFile(QStringLiteral(TESTDATA_DIR) + QStringLiteral("/complete_completer_unsaved.cpp")); QFile readFileContentFile(QStringLiteral(TESTDATA_DIR) + fileName);
unsavedFileContentFile.open(QIODevice::ReadOnly); bool hasOpened = readFileContentFile.open(QIODevice::ReadOnly | QIODevice::Text);
const Utf8String unsavedFileContent = Utf8String::fromByteArray(unsavedFileContentFile.readAll()); EXPECT_TRUE(hasOpened);
const ClangBackEnd::FileContainer unsavedDataFileContainer(translationUnit.filePath(),
projectPart.projectPartId(),
unsavedFileContent,
true);
unsavedFiles.createOrUpdate({unsavedDataFileContainer}); return Utf8String::fromByteArray(readFileContentFile.readAll());
} }
void CodeCompleter::TearDownTestCase() void CodeCompleter::copyTargetHeaderToTemporaryIncludeDirecory()
{ {
translationUnit.reset(); QFile::remove(targetHeaderPath);
completer = ClangBackEnd::CodeCompleter(); bool hasCopied = QFile::copy(QStringLiteral(TESTDATA_DIR "/complete_target_header.h"),
targetHeaderPath);
EXPECT_TRUE(hasCopied);
} }
void CodeCompleter::copyChangedTargetHeaderToTemporaryIncludeDirecory()
{
QFile::remove(targetHeaderPath);
bool hasCopied = QFile::copy(QStringLiteral(TESTDATA_DIR "/complete_target_header_changed.h"),
targetHeaderPath);
EXPECT_TRUE(hasCopied);
}
void CodeCompleter::SetUp()
{
EXPECT_TRUE(includeDirectory.isValid());
Utf8String includePath(QStringLiteral("-I") + includeDirectory.path());
projectPart.setArguments({includePath});
copyTargetHeaderToTemporaryIncludeDirecory();
translationUnit.cxTranslationUnit(); // initialize translation unit so we check changes
}
TEST_F(CodeCompleter, FunctionInUnsavedFile) TEST_F(CodeCompleter, FunctionInUnsavedFile)
{ {
ASSERT_THAT(completer.complete(100, 1), unsavedFiles.createOrUpdate({unsavedMainFileContainer});
AllOf(Contains(CodeCompletion(Utf8StringLiteral("functionWithArguments"),
0, ASSERT_THAT(completer.complete(27, 1),
AllOf(Contains(IsCodeCompletion(Utf8StringLiteral("FunctionWithArguments"),
CodeCompletion::FunctionCompletionKind)), CodeCompletion::FunctionCompletionKind)),
Contains(CodeCompletion(Utf8StringLiteral("function"), Contains(IsCodeCompletion(Utf8StringLiteral("Function"),
0,
CodeCompletion::FunctionCompletionKind)), CodeCompletion::FunctionCompletionKind)),
Contains(CodeCompletion(Utf8StringLiteral("newFunction"), Contains(IsCodeCompletion(Utf8StringLiteral("UnsavedFunction"),
0,
CodeCompletion::FunctionCompletionKind)), CodeCompletion::FunctionCompletionKind)),
Contains(CodeCompletion(Utf8StringLiteral("f"), Contains(IsCodeCompletion(Utf8StringLiteral("f"),
0,
CodeCompletion::FunctionCompletionKind)), CodeCompletion::FunctionCompletionKind)),
Not(Contains(CodeCompletion(Utf8StringLiteral("otherFunction"), Not(Contains(IsCodeCompletion(Utf8StringLiteral("SavedFunction"),
0,
CodeCompletion::FunctionCompletionKind))))); CodeCompletion::FunctionCompletionKind)))));
} }
TEST_F(CodeCompleter, VariableInUnsavedFile)
{
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("VariableInUnsavedFile"),
CodeCompletion::VariableCompletionKind)));
}
TEST_F(CodeCompleter, GlobalVariableInUnsavedFile)
{
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("GlobalVariableInUnsavedFile"),
CodeCompletion::VariableCompletionKind)));
}
TEST_F(CodeCompleter, Macro) TEST_F(CodeCompleter, Macro)
{ {
ASSERT_THAT(completer.complete(100, 1), unsavedFiles.createOrUpdate({unsavedMainFileContainer});
Contains(CodeCompletion(Utf8StringLiteral("Macro"),
0, ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("Macro"),
CodeCompletion::PreProcessorCompletionKind))); CodeCompletion::PreProcessorCompletionKind)));
} }
TEST_F(CodeCompleter, Keyword) TEST_F(CodeCompleter, Keyword)
{ {
ASSERT_THAT(completer.complete(100, 1), ASSERT_THAT(completer.complete(27, 1),
Contains(CodeCompletion(Utf8StringLiteral("switch"), Contains(IsCodeCompletion(Utf8StringLiteral("switch"),
0,
CodeCompletion::KeywordCompletionKind))); CodeCompletion::KeywordCompletionKind)));
} }
TEST_F(CodeCompleter, FunctionInIncludedHeader)
{
ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeader"),
CodeCompletion::FunctionCompletionKind)));
} }
TEST_F(CodeCompleter, FunctionInUnsavedIncludedHeader)
{
unsavedFiles.createOrUpdate({unsavedTargetHeaderFileContainer});
ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeaderUnsaved"),
CodeCompletion::FunctionCompletionKind)));
}
TEST_F(CodeCompleter, FunctionInChangedIncludedHeader)
{
copyChangedTargetHeaderToTemporaryIncludeDirecory();
ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeaderChanged"),
CodeCompletion::FunctionCompletionKind)));
}
TEST_F(CodeCompleter, FunctionInChangedIncludedHeaderWithUnsavedContentInMainFile)
{
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
copyChangedTargetHeaderToTemporaryIncludeDirecory();
ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeaderChanged"),
CodeCompletion::FunctionCompletionKind)));
}
}

View File

@@ -81,6 +81,9 @@ protected:
CodeCompletionChunk ifName{CodeCompletionChunk::TypedText, Utf8StringLiteral("if")}; CodeCompletionChunk ifName{CodeCompletionChunk::TypedText, Utf8StringLiteral("if")};
CodeCompletionChunk horizontalSpace{CodeCompletionChunk::HorizontalSpace, Utf8StringLiteral(" ")}; CodeCompletionChunk horizontalSpace{CodeCompletionChunk::HorizontalSpace, Utf8StringLiteral(" ")};
CodeCompletionChunk optional{CodeCompletionChunk::Optional, Utf8String(), {comma, functionArgumentY, comma, functionArgumentZ}}; CodeCompletionChunk optional{CodeCompletionChunk::Optional, Utf8String(), {comma, functionArgumentY, comma, functionArgumentZ}};
CodeCompletionChunk enableIfT{CodeCompletionChunk::TypedText, Utf8StringLiteral("enable_if_t")};
CodeCompletionChunk enableIfTCondition{CodeCompletionChunk::Placeholder, Utf8StringLiteral("_Cond")};
CodeCompletionChunk enableIfTType{CodeCompletionChunk::Placeholder, Utf8StringLiteral("_Tp")};
}; };
TEST_F(CompletionChunksToTextConverter, ParseIsClearingText) TEST_F(CompletionChunksToTextConverter, ParseIsClearingText)
@@ -117,12 +120,9 @@ TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithParameters)
TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithOptionalParameter) TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithOptionalParameter)
{ {
CodeCompletionChunks completionChunks({integerResultType, functionName, leftParen, functionArgumentX, optional,rightParen}); CodeCompletionChunks completionChunks({integerResultType, functionName, leftParen, functionArgumentX, optional,rightParen});
converter.setAddResultType(true);
converter.setAddPlaceHolderText(true);
converter.parseChunks(completionChunks); ASSERT_THAT(Converter::convertToToolTip(completionChunks),
QStringLiteral("int Function (char x<i>, int y, int z</i>)"));
ASSERT_THAT(converter.text(), QStringLiteral("int Function(char x<i>, int y, int z</i>)"));
} }
TEST_F(CompletionChunksToTextConverter, ConvertVariable) TEST_F(CompletionChunksToTextConverter, ConvertVariable)
@@ -227,7 +227,6 @@ TEST_F(CompletionChunksToTextConverter, ElseIf)
statements, statements,
verticalSpace, verticalSpace,
rightBrace}); rightBrace});
setupConverterForKeywords(); setupConverterForKeywords();
converter.parseChunks(completionChunks); converter.parseChunks(completionChunks);
@@ -235,6 +234,20 @@ TEST_F(CompletionChunksToTextConverter, ElseIf)
ASSERT_THAT(converter.text(), QStringLiteral("else if {\n\n}")); ASSERT_THAT(converter.text(), QStringLiteral("else if {\n\n}"));
} }
TEST_F(CompletionChunksToTextConverter, EnableIfT)
{
CodeCompletionChunks completionChunks({enableIfT,
leftAngle,
enableIfTCondition,
CodeCompletionChunk(CodeCompletionChunk::Optional, Utf8String(), {comma, enableIfTType}),
rightAngle});
setupConverterForKeywords();
converter.parseChunks(completionChunks);
ASSERT_THAT(converter.text(), QStringLiteral("enable_if_t<>"));
}
void CompletionChunksToTextConverter::setupConverterForKeywords() void CompletionChunksToTextConverter::setupConverterForKeywords()
{ {
converter.setAddPlaceHolderPositions(true); converter.setAddPlaceHolderPositions(true);

View File

@@ -1,101 +0,0 @@
void function()
{
}
class Foo;
void functionWithArguments(int i, char *c, const Foo &ref)
{
}
void otherFunction()
{
}
void f()
{
}

View File

@@ -0,0 +1,28 @@
#include "complete_forwarding_header_1.h"
void Function()
{
}
class Foo;
void FunctionWithArguments(int i, char *c, const Foo &ref)
{
}
void SavedFunction()
{
}
void f()
{
}

View File

@@ -0,0 +1,28 @@
#include "complete_forwarding_header_2.h"
void Function()
{
}
class Foo;
void FunctionWithArguments(int i, char *c, const Foo &ref)
{
}
void UnsavedFunction()
{
}
#define Macro
int GlobalVariableInUnsavedFile;
void f()
{
int VariableInUnsavedFile;
}

View File

@@ -1,100 +0,0 @@
void function()
{
}
class Foo;
void functionWithArguments(int i, char *c, const Foo &ref)
{
}
void newFunction()
{
}
#define Macro
void f()
{
}

View File

@@ -0,0 +1,6 @@
#ifndef COMPLETE_FORWARDING_HEADER_1_H
#define COMPLETE_FORWARDING_HEADER_1_H
#include <complete_target_header.h>
#endif // COMPLETE_FORWARDING_HEADER_1_H

View File

@@ -0,0 +1,7 @@
#ifndef COMPLETE_FORWARDING_HEADER_2_H
#define COMPLETE_FORWARDING_HEADER_2_H
#include <complete_target_header.h>
#endif // COMPLETE_FORWARDING_HEADER_2_H

View File

@@ -0,0 +1,7 @@
#ifndef COMPLETE_TARGET_HEADER_H
#define COMPLETE_TARGET_HEADER_H
void FunctionInIncludedHeader();
#endif // COMPLETE_TARGET_HEADER_H

View File

@@ -0,0 +1,8 @@
#ifndef COMPLETE_TARGET_HEADER_CHANGED_H
#define COMPLETE_TARGET_HEADER_CHANGED_H
void FunctionInIncludedHeader();
void FunctionInIncludedHeaderChanged();
#endif // COMPLETE_TARGET_HEADER_CHANGED_H

View File

@@ -0,0 +1,8 @@
#ifndef COMPLETE_TARGET_HEADER_UNSAVED_H
#define COMPLETE_TARGET_HEADER_UNSAVED_H
void FunctionInIncludedHeader();
void FunctionInIncludedHeaderUnsaved();
#endif // COMPLETE_TARGET_HEADER_UNSAVED_H