diff options
Diffstat (limited to 'src/plugins/cppeditor')
-rw-r--r-- | src/plugins/cppeditor/compileroptionsbuilder.cpp | 35 | ||||
-rw-r--r-- | src/plugins/cppeditor/compileroptionsbuilder.h | 1 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppcodemodelsettings.cpp | 3 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppcodemodelsettingspage.cpp | 52 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppcompletionassist.cpp | 34 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppfollowsymbolundercursor.cpp | 17 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppmodelmanager.cpp | 4 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppprojectfile.cpp | 14 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppprojectfile.h | 1 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppprojectupdater.h | 2 | ||||
-rw-r--r-- | src/plugins/cppeditor/cppquickfixes.cpp | 2 | ||||
-rw-r--r-- | src/plugins/cppeditor/cpptoolsreuse.cpp | 40 | ||||
-rw-r--r-- | src/plugins/cppeditor/cpptoolsreuse.h | 6 | ||||
-rw-r--r-- | src/plugins/cppeditor/semantichighlighter.cpp | 1 |
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) { |