aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cppeditor
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/cppeditor')
-rw-r--r--src/plugins/cppeditor/compileroptionsbuilder.cpp35
-rw-r--r--src/plugins/cppeditor/compileroptionsbuilder.h1
-rw-r--r--src/plugins/cppeditor/cppcodemodelsettings.cpp3
-rw-r--r--src/plugins/cppeditor/cppcodemodelsettingspage.cpp52
-rw-r--r--src/plugins/cppeditor/cppcompletionassist.cpp34
-rw-r--r--src/plugins/cppeditor/cppfollowsymbolundercursor.cpp17
-rw-r--r--src/plugins/cppeditor/cppmodelmanager.cpp4
-rw-r--r--src/plugins/cppeditor/cppprojectfile.cpp14
-rw-r--r--src/plugins/cppeditor/cppprojectfile.h1
-rw-r--r--src/plugins/cppeditor/cppprojectupdater.h2
-rw-r--r--src/plugins/cppeditor/cppquickfixes.cpp2
-rw-r--r--src/plugins/cppeditor/cpptoolsreuse.cpp40
-rw-r--r--src/plugins/cppeditor/cpptoolsreuse.h6
-rw-r--r--src/plugins/cppeditor/semantichighlighter.cpp1
14 files changed, 156 insertions, 56 deletions
diff --git a/src/plugins/cppeditor/compileroptionsbuilder.cpp b/src/plugins/cppeditor/compileroptionsbuilder.cpp
index 14921c51eb..09f71fa93f 100644
--- a/src/plugins/cppeditor/compileroptionsbuilder.cpp
+++ b/src/plugins/cppeditor/compileroptionsbuilder.cpp
@@ -123,7 +123,7 @@ CompilerOptionsBuilder::~CompilerOptionsBuilder() = default;
QStringList CompilerOptionsBuilder::build(ProjectFile::Kind fileKind,
UsePrecompiledHeaders usePrecompiledHeaders)
{
- m_options.clear();
+ reset();
evaluateCompilerFlags();
if (fileKind == ProjectFile::CHeader || fileKind == ProjectFile::CSource) {
@@ -251,9 +251,12 @@ void CompilerOptionsBuilder::addWordWidth()
void CompilerOptionsBuilder::addTargetTriple()
{
+ const QString target = m_explicitTarget.isEmpty()
+ ? m_projectPart.toolChainTargetTriple : m_explicitTarget;
+
// Only "--target=" style is accepted in both g++ and cl driver modes.
- if (!m_projectPart.toolChainTargetTriple.isEmpty())
- add("--target=" + m_projectPart.toolChainTargetTriple);
+ if (!target.isEmpty())
+ add("--target=" + target);
}
void CompilerOptionsBuilder::addExtraCodeModelFlags()
@@ -771,6 +774,7 @@ void CompilerOptionsBuilder::undefineClangVersionMacrosForMsvc()
void CompilerOptionsBuilder::reset()
{
m_options.clear();
+ m_explicitTarget.clear();
}
// Some example command lines for a "Qt Console Application":
@@ -786,12 +790,18 @@ void CompilerOptionsBuilder::evaluateCompilerFlags()
const Id toolChain = m_projectPart.toolchainType;
bool containsDriverMode = false;
bool skipNext = false;
- const QStringList allFlags = m_projectPart.compilerFlags + m_projectPart.extraCodeModelFlags;
+ bool nextIsTarget = false;
+ const QStringList allFlags = m_projectPart.extraCodeModelFlags + m_projectPart.compilerFlags;
for (const QString &option : allFlags) {
if (skipNext) {
skipNext = false;
continue;
}
+ if (nextIsTarget) {
+ nextIsTarget = false;
+ m_explicitTarget = option;
+ continue;
+ }
if (userBlackList.contains(option))
continue;
@@ -812,14 +822,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags()
continue;
}
- // As we always set the target explicitly, filter out target args.
- if (!m_projectPart.toolChainTargetTriple.isEmpty()) {
- if (option.startsWith("--target="))
- continue;
- if (option == "-target") {
- skipNext = true;
- continue;
- }
+ // An explicit target triple from the build system takes precedence over the generic one
+ // from the toolchain.
+ if (option.startsWith("--target=")) {
+ m_explicitTarget = option.mid(9);
+ continue;
+ }
+ if (option == "-target") {
+ nextIsTarget = true;
+ continue;
}
if (option == includeUserPathOption || option == includeSystemPathOption
diff --git a/src/plugins/cppeditor/compileroptionsbuilder.h b/src/plugins/cppeditor/compileroptionsbuilder.h
index 0211d58a18..cc75e984be 100644
--- a/src/plugins/cppeditor/compileroptionsbuilder.h
+++ b/src/plugins/cppeditor/compileroptionsbuilder.h
@@ -122,6 +122,7 @@ private:
} m_compilerFlags;
QStringList m_options;
+ QString m_explicitTarget;
bool m_clStyle = false;
};
diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp
index 1a7cf1255f..66c07bed7a 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp
@@ -402,7 +402,8 @@ QVariantMap ClangdSettings::Data::toMap() const
{
QVariantMap map;
map.insert(useClangdKey(), useClangd);
- map.insert(clangdPathKey(), executableFilePath.toString());
+ if (executableFilePath != fallbackClangdFilePath())
+ map.insert(clangdPathKey(), executableFilePath.toString());
map.insert(clangdIndexingKey(), enableIndexing);
map.insert(clangdThreadLimitKey(), workerThreadLimit);
map.insert(clangdDocumentThresholdKey(), documentUpdateThreshold);
diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
index 2c775e3843..1c6621e070 100644
--- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
@@ -33,11 +33,14 @@
#include <coreplugin/icore.h>
#include <utils/algorithm.h>
+#include <utils/infolabel.h>
#include <utils/pathchooser.h>
+#include <utils/qtcprocess.h>
#include <QFormLayout>
#include <QSpinBox>
#include <QTextStream>
+#include <QVersionNumber>
namespace CppEditor::Internal {
@@ -197,6 +200,7 @@ public:
QSpinBox threadLimitSpinBox;
QSpinBox documentUpdateThreshold;
Utils::PathChooser clangdChooser;
+ Utils::InfoLabel versionWarningLabel;
};
ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsData)
@@ -230,6 +234,7 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
const auto formLayout = new QFormLayout;
const auto chooserLabel = new QLabel(tr("Path to executable:"));
formLayout->addRow(chooserLabel, &d->clangdChooser);
+ formLayout->addRow(QString(), &d->versionWarningLabel);
const auto indexingLabel = new QLabel(tr("Enable background indexing:"));
formLayout->addRow(indexingLabel, &d->indexingCheckBox);
const auto threadLimitLayout = new QHBoxLayout;
@@ -251,11 +256,58 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
indexingLabel->setEnabled(checked);
d->indexingCheckBox.setEnabled(checked);
d->threadLimitSpinBox.setEnabled(checked);
+ d->versionWarningLabel.setEnabled(checked);
};
connect(&d->useClangdCheckBox, &QCheckBox::toggled, toggleEnabled);
toggleEnabled(d->useClangdCheckBox.isChecked());
d->threadLimitSpinBox.setEnabled(d->useClangdCheckBox.isChecked());
+ d->versionWarningLabel.setType(Utils::InfoLabel::Warning);
+ const auto updateWarningLabel = [this] {
+ class WarningLabelSetter {
+ public:
+ WarningLabelSetter(QLabel &label) : m_label(label) { m_label.clear(); }
+ ~WarningLabelSetter() { m_label.setVisible(!m_label.text().isEmpty()); }
+ void setWarning(const QString &text) { m_label.setText(text); }
+ private:
+ QLabel &m_label;
+ };
+ WarningLabelSetter labelSetter(d->versionWarningLabel);
+
+ if (!d->clangdChooser.isValid())
+ return;
+ const Utils::FilePath clangdPath = d->clangdChooser.filePath();
+ Utils::QtcProcess clangdProc;
+ clangdProc.setCommand({clangdPath, {"--version"}});
+ clangdProc.start();
+ if (!clangdProc.waitForStarted() || !clangdProc.waitForFinished()) {
+ labelSetter.setWarning(tr("Failed to retrieve clangd version: %1")
+ .arg(clangdProc.exitMessage()));
+ return;
+ }
+ const QString output = clangdProc.allOutput();
+ static const QString versionPrefix = "clangd version ";
+ const int prefixOffset = output.indexOf(versionPrefix);
+ QVersionNumber clangdVersion;
+ if (prefixOffset != -1) {
+ clangdVersion = QVersionNumber::fromString(output.mid(prefixOffset
+ + versionPrefix.length()));
+ }
+ if (clangdVersion.isNull()) {
+ labelSetter.setWarning(tr("Failed to retrieve clangd version: "
+ "Unexpected clangd output."));
+ return;
+ }
+ if (clangdVersion < QVersionNumber(13)) {
+ labelSetter.setWarning(tr("The clangd version is %1, but %2 or greater is "
+ "recommended for full functionality.")
+ .arg(clangdVersion.toString()).arg(13));
+ return;
+ }
+ };
+ connect(&d->clangdChooser, &Utils::PathChooser::pathChanged, this, updateWarningLabel);
+ updateWarningLabel();
+
connect(&d->useClangdCheckBox, &QCheckBox::toggled,
this, &ClangdSettingsWidget::settingsDataChanged);
connect(&d->indexingCheckBox, &QCheckBox::toggled,
diff --git a/src/plugins/cppeditor/cppcompletionassist.cpp b/src/plugins/cppeditor/cppcompletionassist.cpp
index cd2c70b78c..ee04a15957 100644
--- a/src/plugins/cppeditor/cppcompletionassist.cpp
+++ b/src/plugins/cppeditor/cppcompletionassist.cpp
@@ -858,38 +858,8 @@ bool InternalCppCompletionAssistProcessor::accepts() const
if (pos - startOfName >= TextEditorSettings::completionSettings().m_characterThreshold) {
const QChar firstCharacter = m_interface->characterAt(startOfName);
if (isValidFirstIdentifierChar(firstCharacter)) {
- // Finally check that we're not inside a comment or string (code copied from startOfOperator)
- QTextCursor tc(m_interface->textDocument());
- tc.setPosition(pos);
-
- SimpleLexer tokenize;
- tokenize.setLanguageFeatures(m_interface->languageFeatures());
- tokenize.setSkipComments(false);
-
- const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block()));
- const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1));
- const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx);
-
- if (!tk.isComment() && !tk.isLiteral()) {
- return true;
- } else if (tk.isLiteral()
- && tokens.size() == 3
- && tokens.at(0).kind() == T_POUND
- && tokens.at(1).kind() == T_IDENTIFIER) {
- const QString &line = tc.block().text();
- const Token &idToken = tokens.at(1);
- QStringView identifier = idToken.utf16charsEnd() > line.size()
- ? QStringView(line).mid(
- idToken.utf16charsBegin())
- : QStringView(line)
- .mid(idToken.utf16charsBegin(),
- idToken.utf16chars());
- if (identifier == QLatin1String("include")
- || identifier == QLatin1String("include_next")
- || (m_interface->languageFeatures().objCEnabled && identifier == QLatin1String("import"))) {
- return true;
- }
- }
+ return !isInCommentOrString(m_interface.data(),
+ m_interface->languageFeatures());
}
}
}
diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
index ac2747cad7..11a3a70be0 100644
--- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
+++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
@@ -417,17 +417,18 @@ bool maybeAppendArgumentOrParameterList(QString *expression, const QTextCursor &
bool isCursorOnTrailingReturnType(const QList<AST *> &astPath)
{
- for (auto it = astPath.cend() - 1, begin = astPath.cbegin(); it >= begin; --it) {
+ if (astPath.size() < 3)
+ return false;
+ for (auto it = astPath.cend() - 3, begin = astPath.cbegin(); it >= begin; --it) {
+ if (!(*it)->asTrailingReturnType())
+ continue;
const auto nextIt = it + 1;
const auto nextNextIt = nextIt + 1;
- if (nextNextIt != astPath.cend() && (*it)->asTrailingReturnType()) {
- return (*nextIt)->asNamedTypeSpecifier()
- && ((*nextNextIt)->asSimpleName()
- || (*nextNextIt)->asQualifiedName()
- || (*nextNextIt)->asTemplateId());
- }
+ return (*nextIt)->asNamedTypeSpecifier()
+ && ((*nextNextIt)->asSimpleName()
+ || (*nextNextIt)->asQualifiedName()
+ || (*nextNextIt)->asTemplateId());
}
-
return false;
}
diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp
index 40b37263d8..4ddd690b42 100644
--- a/src/plugins/cppeditor/cppmodelmanager.cpp
+++ b/src/plugins/cppeditor/cppmodelmanager.cpp
@@ -694,6 +694,10 @@ CppModelManager::CppModelManager()
connect(KitManager::instance(), &KitManager::kitsChanged, this,
&CppModelManager::setupFallbackProjectPart);
+ connect(this, &CppModelManager::projectPartsRemoved, this,
+ &CppModelManager::setupFallbackProjectPart);
+ connect(this, &CppModelManager::projectPartsUpdated, this,
+ &CppModelManager::setupFallbackProjectPart);
setupFallbackProjectPart();
qRegisterMetaType<CPlusPlus::Document::Ptr>("CPlusPlus::Document::Ptr");
diff --git a/src/plugins/cppeditor/cppprojectfile.cpp b/src/plugins/cppeditor/cppprojectfile.cpp
index fa3bf8c023..58196521ca 100644
--- a/src/plugins/cppeditor/cppprojectfile.cpp
+++ b/src/plugins/cppeditor/cppprojectfile.cpp
@@ -87,6 +87,20 @@ bool ProjectFile::isAmbiguousHeader(const QString &filePath)
return filePath.endsWith(".h");
}
+bool ProjectFile::isObjC(const QString &filePath)
+{
+ const Kind kind = classify(filePath);
+ switch (kind) {
+ case CppEditor::ProjectFile::ObjCHeader:
+ case CppEditor::ProjectFile::ObjCXXHeader:
+ case CppEditor::ProjectFile::ObjCSource:
+ case CppEditor::ProjectFile::ObjCXXSource:
+ return true;
+ default:
+ return false;
+ }
+}
+
ProjectFile::Kind ProjectFile::sourceForHeaderKind(ProjectFile::Kind kind)
{
ProjectFile::Kind sourceKind;
diff --git a/src/plugins/cppeditor/cppprojectfile.h b/src/plugins/cppeditor/cppprojectfile.h
index 078b93cce9..1bd80fdf65 100644
--- a/src/plugins/cppeditor/cppprojectfile.h
+++ b/src/plugins/cppeditor/cppprojectfile.h
@@ -61,6 +61,7 @@ public:
static bool isC(Kind kind);
static bool isCxx(Kind kind);
static bool isAmbiguousHeader(const QString &filePath);
+ static bool isObjC(const QString &filePath);
bool isHeader() const;
bool isSource() const;
diff --git a/src/plugins/cppeditor/cppprojectupdater.h b/src/plugins/cppeditor/cppprojectupdater.h
index 165ec27910..b716ef3183 100644
--- a/src/plugins/cppeditor/cppprojectupdater.h
+++ b/src/plugins/cppeditor/cppprojectupdater.h
@@ -47,7 +47,7 @@ public:
CppProjectUpdaterFactory();
// keep the namespace, for the type name in the invokeMethod call
- Q_INVOKABLE CppProjectUpdaterInterface *create();
+ Q_INVOKABLE CppEditor::CppProjectUpdaterInterface *create();
};
} // namespace Internal
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 8b9fdce190..91974761c2 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -2483,7 +2483,7 @@ void CompleteSwitchCaseStatement::match(const CppQuickFixInterface &interface,
AST *ast = path.at(depth);
SwitchStatementAST *switchStatement = ast->asSwitchStatement();
if (switchStatement) {
- if (!switchStatement->statement)
+ if (!switchStatement->statement || !switchStatement->symbol)
return;
CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement();
if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
diff --git a/src/plugins/cppeditor/cpptoolsreuse.cpp b/src/plugins/cppeditor/cpptoolsreuse.cpp
index 15a1bea88a..04f679824a 100644
--- a/src/plugins/cppeditor/cpptoolsreuse.cpp
+++ b/src/plugins/cppeditor/cpptoolsreuse.cpp
@@ -39,11 +39,15 @@
#include <coreplugin/idocument.h>
#include <coreplugin/messagemanager.h>
#include <projectexplorer/session.h>
+#include <texteditor/codeassist/assistinterface.h>
#include <texteditor/textdocument.h>
-#include <cplusplus/Overview.h>
+#include <cplusplus/BackwardsScanner.h>
#include <cplusplus/LookupContext.h>
+#include <cplusplus/Overview.h>
+#include <cplusplus/SimpleLexer.h>
#include <utils/algorithm.h>
+#include <utils/porting.h>
#include <utils/textutils.h>
#include <utils/qtcassert.h>
@@ -300,6 +304,40 @@ const Macro *findCanonicalMacro(const QTextCursor &cursor, Document::Ptr documen
return nullptr;
}
+bool isInCommentOrString(const TextEditor::AssistInterface *interface,
+ CPlusPlus::LanguageFeatures features)
+{
+ QTextCursor tc(interface->textDocument());
+ tc.setPosition(interface->position());
+
+ SimpleLexer tokenize;
+ features.qtMocRunEnabled = true;
+ tokenize.setLanguageFeatures(features);
+ tokenize.setSkipComments(false);
+ const Tokens &tokens = tokenize(tc.block().text(),
+ BackwardsScanner::previousBlockState(tc.block()));
+ const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1));
+ const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx);
+
+ if (tk.isComment())
+ return true;
+ if (!tk.isLiteral())
+ return false;
+ if (tokens.size() == 3 && tokens.at(0).kind() == T_POUND
+ && tokens.at(1).kind() == T_IDENTIFIER) {
+ const QString &line = tc.block().text();
+ const Token &idToken = tokens.at(1);
+ QStringView identifier = Utils::midView(line, idToken.utf16charsBegin(),
+ idToken.utf16chars());
+ if (identifier == QLatin1String("include")
+ || identifier == QLatin1String("include_next")
+ || (features.objCEnabled && identifier == QLatin1String("import"))) {
+ return false;
+ }
+ }
+ return true;
+}
+
CppCodeModelSettings *codeModelSettings()
{
return Internal::CppEditorPlugin::instance()->codeModelSettings();
diff --git a/src/plugins/cppeditor/cpptoolsreuse.h b/src/plugins/cppeditor/cpptoolsreuse.h
index b3fd7a274b..e7023b7be7 100644
--- a/src/plugins/cppeditor/cpptoolsreuse.h
+++ b/src/plugins/cppeditor/cpptoolsreuse.h
@@ -35,6 +35,7 @@
#include <cplusplus/ASTVisitor.h>
#include <cplusplus/CppDocument.h>
+#include <cplusplus/Token.h>
QT_BEGIN_NAMESPACE
class QChar;
@@ -48,6 +49,8 @@ class Symbol;
class LookupContext;
} // namespace CPlusPlus
+namespace TextEditor { class AssistInterface; }
+
namespace CppEditor {
class CppRefactoringFile;
class ProjectInfo;
@@ -71,6 +74,9 @@ bool CPPEDITOR_EXPORT isOwnershipRAIIType(CPlusPlus::Symbol *symbol,
const CPlusPlus::Macro CPPEDITOR_EXPORT *findCanonicalMacro(const QTextCursor &cursor,
CPlusPlus::Document::Ptr document);
+bool CPPEDITOR_EXPORT isInCommentOrString(const TextEditor::AssistInterface *interface,
+ CPlusPlus::LanguageFeatures features);
+
enum class CacheUsage { ReadWrite, ReadOnly };
QString CPPEDITOR_EXPORT correspondingHeaderOrSource(const QString &fileName, bool *wasHeader = nullptr,
diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp
index f3112a725b..eb6e90fb2b 100644
--- a/src/plugins/cppeditor/semantichighlighter.cpp
+++ b/src/plugins/cppeditor/semantichighlighter.cpp
@@ -180,6 +180,7 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to)
QPair<QTextBlock, Parentheses> parentheses;
for (int i = from; i < to; ++i) {
const HighlightingResult &result = m_watcher->future().resultAt(i);
+ QTC_ASSERT(result.line <= m_baseTextDocument->document()->blockCount(), continue);
if (result.kind != AngleBracketOpen && result.kind != AngleBracketClose
&& result.kind != DoubleAngleBracketClose
&& result.kind != TernaryIf && result.kind != TernaryElse) {