diff options
132 files changed, 6279 insertions, 2307 deletions
diff --git a/doc/src/editors/creator-coding-edit-mode.qdoc b/doc/src/editors/creator-coding-edit-mode.qdoc index f80aec704d..4693ae1ac4 100644 --- a/doc/src/editors/creator-coding-edit-mode.qdoc +++ b/doc/src/editors/creator-coding-edit-mode.qdoc @@ -64,7 +64,11 @@ To show the file encoding of the current file on the editor toolbar (4), select \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > - \uicontrol Display > \uicontrol {Display file encoding}. + \uicontrol Display > \uicontrol {Display file encoding}. To change the + encoding, click it on the toolbar and select new encoding in the + \uicontrol {Text Encoding} dialog. To reload the file with the selected + encoding, select \uicontrol {Reload with Encoding}. To save the file with + the new encoding, select \uicontrol {Save with Encoding}. \note Other convenient ways of navigating in \QC are provided by the \l{Searching with the Locator}{locator}, \l{Keyboard Shortcuts} diff --git a/doc/src/editors/creator-coding.qdoc b/doc/src/editors/creator-coding.qdoc index 49e6480982..9fcb5e18a8 100644 --- a/doc/src/editors/creator-coding.qdoc +++ b/doc/src/editors/creator-coding.qdoc @@ -26,7 +26,7 @@ \contentspage {Qt Creator Manual} \previouspage creator-usability.html \page creator-coding.html - \nextpage creator-modeling.html + \nextpage creator-editor-functions.html \title Coding @@ -34,12 +34,6 @@ \list - \li \l{Modeling} - - You can use the experimental model editor to create Universal - Modeling Language (UML) style models with structured diagrams and - store them in XML format. - \li \l{Writing Code} Writing, editing, and navigating in source code are core tasks in @@ -85,18 +79,11 @@ to use for opening the file. If your files do not match the predefined MIME types, you can edit the MIME types. - \li \l{Comparing Files} - - You can use a diff editor to compare two versions of a file and - view the differences side-by-side in the \uicontrol Edit mode. - - \li \l{Parsing C++ Files} + \li \l{Modeling} - An experimental Clang code model plugin enables you to replace the - built-in \QC code model with the Clang code model. Clang is a C - language family front end for LLVM. Clang provides you with more - accurate information than the built-in code model but can be slower - to use for large projects. + You can use the experimental model editor to create Universal + Modeling Language (UML) style models with structured diagrams and + store them in XML format. \endlist diff --git a/doc/src/editors/creator-editors-writing-code.qdoc b/doc/src/editors/creator-editors-writing-code.qdoc index d30e89716a..78d1ece352 100644 --- a/doc/src/editors/creator-editors-writing-code.qdoc +++ b/doc/src/editors/creator-editors-writing-code.qdoc @@ -24,7 +24,7 @@ /*! \contentspage {Qt Creator Manual} - \previouspage creator-modeling.html + \previouspage creator-coding.html \page creator-editor-functions.html \nextpage creator-coding-navigating.html @@ -93,4 +93,23 @@ \endlist + \section1 Related Topics + + \list + + \li \l{Comparing Files} + + You can use a diff editor to compare two versions of a file and + view the differences side-by-side in the \uicontrol Edit mode. + + \li \l{Parsing C++ Files} + + An experimental Clang code model plugin enables you to replace the + built-in \QC code model with the Clang code model. Clang is a C + language family front end for LLVM. Clang provides you with more + accurate information than the built-in code model but can be slower + to use for large projects. + + \endlist + */ diff --git a/doc/src/editors/creator-mime-types.qdoc b/doc/src/editors/creator-mime-types.qdoc index e1f7544a4c..c2f8fff8ba 100644 --- a/doc/src/editors/creator-mime-types.qdoc +++ b/doc/src/editors/creator-mime-types.qdoc @@ -26,7 +26,7 @@ \contentspage {Qt Creator Manual} \previouspage creator-editor-fakevim.html \page creator-mime-types.html - \nextpage creator-building-running.html + \nextpage creator-modeling.html \title Editing MIME Types diff --git a/doc/src/editors/creator-modeling.qdoc b/doc/src/editors/creator-modeling.qdoc index 77f9681a24..36200a11d1 100644 --- a/doc/src/editors/creator-modeling.qdoc +++ b/doc/src/editors/creator-modeling.qdoc @@ -24,9 +24,9 @@ /*! \contentspage {Qt Creator Manual} - \previouspage creator-coding.html + \previouspage creator-mime-types.html \page creator-modeling.html - \nextpage creator-editor-functions.html + \nextpage creator-building-running.html \title Modeling diff --git a/doc/src/overview/creator-target-platforms.qdocinc b/doc/src/overview/creator-target-platforms.qdocinc index 34cfdc0a2f..812564c93e 100644 --- a/doc/src/overview/creator-target-platforms.qdocinc +++ b/doc/src/overview/creator-target-platforms.qdocinc @@ -29,7 +29,7 @@ For more information about the supported device groups and reference devices, see \l{http://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html} - {Supported Platforms} in the {http://doc.qt.io/QtForDeviceCreation/index.html} + {Supported Platforms} in the \l{http://doc.qt.io/QtForDeviceCreation/index.html} {Qt for Device Creation} documentation. \section2 Mobile Devices diff --git a/doc/src/projects/creator-projects-building-running.qdoc b/doc/src/projects/creator-projects-building-running.qdoc index 047c4764d1..0159b79da3 100644 --- a/doc/src/projects/creator-projects-building-running.qdoc +++ b/doc/src/projects/creator-projects-building-running.qdoc @@ -24,7 +24,7 @@ /*! \contentspage {Qt Creator Manual} - \previouspage creator-mime-types.html + \previouspage creator-modeling.html \page creator-building-running.html \nextpage creator-building-targets.html diff --git a/doc/src/qtcreator.qdoc b/doc/src/qtcreator.qdoc index 7f33c68dc5..27316fc87c 100644 --- a/doc/src/qtcreator.qdoc +++ b/doc/src/qtcreator.qdoc @@ -72,11 +72,11 @@ \endlist \li \b {\l{Coding}} \list - \li \l{Modeling} \li \l{Writing Code} \li \l{Finding} \li \l{Refactoring} \li \l{Configuring the Editor} + \li \l{Modeling} \endlist \row \li \inlineimage creator_buildingrunning.png @@ -113,7 +113,6 @@ \li \l{Known Issues} \li \l{Glossary} \endlist - \li \row \li {4,1} \note To report bugs and suggestions to the Qt Bug Tracker, select \uicontrol {Help > Report Bug}. @@ -194,7 +193,6 @@ \endlist \li \l{Coding} \list - \li \l{Modeling} \li \l{Writing Code} \list \li \l{Working in Edit Mode} @@ -221,6 +219,7 @@ \li \l{Using FakeVim Mode} \endlist \li \l{Editing MIME Types} + \li \l{Modeling} \endlist \li \l{Building and Running} \list diff --git a/doc/src/qtquick/qtquick-components.qdoc b/doc/src/qtquick/qtquick-components.qdoc index 6b946f3de7..86b0a1e36e 100644 --- a/doc/src/qtquick/qtquick-components.qdoc +++ b/doc/src/qtquick/qtquick-components.qdoc @@ -25,7 +25,7 @@ /*! \contentspage {Qt Creator Manual} - \previouspage creator-using-qt-quick-designer.html + \previouspage qmldesigner-connections.html \page quick-components.html \nextpage quick-buttons.html diff --git a/doc/src/qtquick/qtquick-connection-editor.qdoc b/doc/src/qtquick/qtquick-connection-editor.qdoc index f57dc9be21..a84022136e 100644 --- a/doc/src/qtquick/qtquick-connection-editor.qdoc +++ b/doc/src/qtquick/qtquick-connection-editor.qdoc @@ -31,7 +31,7 @@ \contentspage {Qt Creator Manual} \previouspage qmldesigner-pathview-editor.html \page qmldesigner-connections.html - \nextpage quick-export-to-qml.html + \nextpage quick-components.html \title Adding Connections diff --git a/doc/src/qtquick/qtquick-designer.qdoc b/doc/src/qtquick/qtquick-designer.qdoc index 6b8e5cb03e..b9da283ba3 100644 --- a/doc/src/qtquick/qtquick-designer.qdoc +++ b/doc/src/qtquick/qtquick-designer.qdoc @@ -26,7 +26,7 @@ \contentspage {Qt Creator Manual} \previouspage creator-quick-ui-forms.html \page creator-using-qt-quick-designer.html - \nextpage quick-components.html + \nextpage qmldesigner-pathview-editor.html \title Using Qt Quick Designer diff --git a/doc/src/qtquick/qtquick-pathview-editor.qdoc b/doc/src/qtquick/qtquick-pathview-editor.qdoc index 55424c92ef..8e20f3613d 100644 --- a/doc/src/qtquick/qtquick-pathview-editor.qdoc +++ b/doc/src/qtquick/qtquick-pathview-editor.qdoc @@ -29,7 +29,7 @@ /*! \contentspage {Qt Creator Manual} - \previouspage creator-qtquick-designer-extensions.html + \previouspage creator-using-qt-quick-designer.html \page qmldesigner-pathview-editor.html \nextpage qmldesigner-connections.html diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 07fac84980..8a5b51ddca 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -1034,9 +1034,8 @@ class DumperBase: # We cannot use str(addr) as it yields rubbish for char pointers # that might trigger Unicode encoding errors. #return addr.cast(lookupType("void").pointer()) - # We do not use "hex(...)" as it (sometimes?) adds a "L" suffix. try: - return "0x%x" % toInteger(addr) + return "0x%x" % toInteger(hex(addr), 16) except: warn("CANNOT CONVERT TYPE: %s" % type(addr)) try: diff --git a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/wizard.json index c97ae596df..6b3a288347 100644 --- a/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmake/qtcanvas3dapplication/wizard.json @@ -8,7 +8,7 @@ "trDisplayCategory": "Application", "icon": "3dapplication.png", "featuresRequired": [ "QtSupport.Wizards.FeatureQtCanvas3d" ], - "enabled": "${JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0}", + "enabled": "%{JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0}", "options": [ diff --git a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json index 68476a9357..29a51b8e41 100644 --- a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickapplication/wizard.json @@ -5,7 +5,7 @@ "category": "H.Project", "trDescription": "Creates a Qt Quick 2 UI project with a QML entry point. To use it, you need to have a QML runtime environment such as qmlscene set up. Consider using a Qt Quick Application project instead.", "trDisplayName": "Qt Quick UI", - "trDisplayCategory": "Application", + "trDisplayCategory": "Other Project", "icon": "../../qmake/qtquickapplication/qml_wizard.png", "enabled": "%{JS: [ %{Plugins} ].indexOf('QmlProjectManager') >= 0}", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQuick.Controls.1.3", "QtSupport.Wizards.FeatureQtQuickProject", "QtSupport.Wizards.FeatureQt" ], diff --git a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json index 57b5377750..7d601d3dbd 100644 --- a/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qmlproject/qtquickcontrolsapplication/wizard.json @@ -5,7 +5,7 @@ "category": "H.Project", "trDescription": "Creates a Qt Quick 2 UI project using Qt Quick Controls with a QML entry point. To use it, you need to have a QML runtime environment such as qmlscene set up. Consider using a Qt Quick Controls Application project instead.", "trDisplayName": "Qt Quick Controls UI", - "trDisplayCategory": "Application", + "trDisplayCategory": "Other Project", "icon": "../../qmake/qtquickapplication/qml_wizard.png", "enabled": "%{JS: [ %{Plugins} ].indexOf('QmlProjectManager') >= 0}", "featuresRequired": [ "QtSupport.Wizards.FeatureQtQuick.Controls.1.3", "QtSupport.Wizards.FeatureQtQuickProject", "QtSupport.Wizards.FeatureQt" ], diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 51559890fa..2090cf9481 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -1390,10 +1390,6 @@ Deploying local Qt libraries is incompatible with Android 5.</source> <source>Core plugin is disabled.</source> <translation>Базовый модуль отключён.</translation> </message> - <message> - <source>No valid theme "%1"</source> - <translation>Подходящая тема «%1» не обнаружена</translation> - </message> </context> <context> <name>ApplicationWindowSpecifics</name> @@ -5383,6 +5379,10 @@ Continue?</source> <context> <name>Core::Internal::CorePlugin</name> <message> + <source>No themes found in installation.</source> + <translation>Темы не установлены.</translation> + </message> + <message> <source>The current date (ISO).</source> <translation>Текущая дата (ISO).</translation> </message> @@ -8286,26 +8286,6 @@ In addition, Shift+Enter inserts an escape character at the cursor position and <translation></translation> </message> <message> - <source>Code Completion and Semantic Highlighting</source> - <translation>Дополнение и подсветка кода</translation> - </message> - <message> - <source>C</source> - <translation>C</translation> - </message> - <message> - <source>C++</source> - <translation>C++</translation> - </message> - <message> - <source>Objective C</source> - <translation>Objective C</translation> - </message> - <message> - <source>Objective C++</source> - <translation>Objective C++</translation> - </message> - <message> <source>Pre-compiled Headers</source> <translation>Прекомпилированные заголовки</translation> </message> @@ -8318,8 +8298,20 @@ In addition, Shift+Enter inserts an escape character at the cursor position and <translation>Игнорировать прекомпилированные заголовки</translation> </message> <message> - <source>Headers</source> - <translation>Заголовочные</translation> + <source><i>Activate the Clang Code Model plugin to enable the options here.</i></source> + <translation><i>Включите модуль Clang Code Model, чтобы менять настройки.</i></translation> + </message> + <message> + <source>Use Clang Code Model</source> + <translation>Использовать модель кода Clang</translation> + </message> + <message> + <source>Append additional command line options to Clang, one per line. <i>Use this with care.</i></source> + <translation>Дополнительные параметры командной строки Clang, по одной на строке.<br><i>Используйте их с осторожностью.</i></translation> + </message> + <message> + <source>Reset Options</source> + <translation>Сбросить</translation> </message> </context> <context> @@ -10438,14 +10430,6 @@ Flags: %3</source> <translation>Менять размер шрифта в окне отладчика при изменении его в основном окне редактора.</translation> </message> <message> - <source>Populates the source file view automatically. This might slow down debugger startup considerably.</source> - <translation>Автоматическое заполнение просмотра файлов исходных текстов. Может замедлить процесс запуска отладчика.</translation> - </message> - <message> - <source>Populate source file view automatically</source> - <translation>Автоматически заполнять представление исходных текстов</translation> - </message> - <message> <source>Switch to previous mode on debugger exit</source> <translation>Переключаться в предыдущий режим при завершении отладчика</translation> </message> @@ -11365,10 +11349,6 @@ Qt Creator не может подключиться к нему.</translation> <translation>Подсказки в обзоре стека при отладке</translation> </message> <message> - <source>List Source Files</source> - <translation>Показать файлы исходников</translation> - </message> - <message> <source>Skip Known Frames</source> <translation>Пропустить известные кадры</translation> </message> @@ -22143,6 +22123,10 @@ Ids must begin with a lowercase letter.</source> <context> <name>ProjectExplorer::Internal::DependenciesWidget</name> <message> + <source>Synchronize configuration</source> + <translation>Синхронизировать конфигурацию</translation> + </message> + <message> <source>Synchronize active kit, build, and deploy configuration between projects.</source> <translation>Сихронизировать у проектов текущий комплект и конфигурации сборки и установки.</translation> </message> @@ -34043,7 +34027,7 @@ with a password, which you can enter below.</source> <context> <name>TextEditor::FindInFiles</name> <message> - <source>Files on File System</source> + <source>Files in File System</source> <translation>Файлы в системе</translation> </message> <message> @@ -38741,6 +38725,10 @@ should a repository require SSH-authentication (see documentation on SSH and the <context> <name>WinRt::Internal::WinRtDebugSupport</name> <message> + <source>Not enough free ports for QML debugging.</source> + <translation>Недостаточно свободных портов для отладки QML.</translation> + </message> + <message> <source>The WinRT debugging helper is missing from your Qt Creator installation. It was assumed to be located at %1</source> <translation>Помощник отладчика WinRT отсутствует в составе установки вашего Qt Creator. Предполагается, что он находится в %1</translation> </message> diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 8c3ceca968..bcdf043362 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -3349,7 +3349,7 @@ public: DeclarationAST *declaration; public: // annotations - Scope *symbol; + Template *symbol; public: TemplateDeclarationAST() diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 0deb19dd54..63940d19dd 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -1917,19 +1917,9 @@ bool Bind::visit(SimpleDeclarationAST *ast) methodKey = methodKeyForInvokableToken(tokenKind(ast->qt_invokable_token)); // unsigned qt_invokable_token = ast->qt_invokable_token; - const ExpressionAST *declTypeExpression = 0; - bool isTypedef = false; FullySpecifiedType type; for (SpecifierListAST *it = ast->decl_specifier_list; it; it = it->next) { type = this->specifier(it->value, type); - if (type.isTypedef()) - isTypedef = true; - - type.setTypedef(isTypedef); - if (type.isDecltype()) { - if (DecltypeSpecifierAST *decltypeSpec = it->value->asDecltypeSpecifier()) - declTypeExpression = decltypeSpec->expression; - } } List<Symbol *> **symbolTail = &ast->symbols; @@ -1985,8 +1975,6 @@ bool Bind::visit(SimpleDeclarationAST *ast) translationUnit()->error(location(declaratorId->name, ast->firstToken()), "auto-initialized variable must have an initializer"); else if (initializer) decl->setInitializer(asStringLiteral(initializer)); - } else if (declTy.isDecltype()) { - decl->setInitializer(asStringLiteral(declTypeExpression)); } if (_scope->isClass()) { @@ -2367,15 +2355,11 @@ bool Bind::visit(ParameterDeclarationAST *ast) bool Bind::visit(TemplateDeclarationAST *ast) { - Scope *scope = 0; - if (ast->less_token) - scope = control()->newTemplate(ast->firstToken(), 0); - else - scope = control()->newExplicitInstantiation(ast->firstToken(), 0); - scope->setStartOffset(tokenAt(ast->firstToken()).utf16charsBegin()); - scope->setEndOffset(tokenAt(ast->lastToken() - 1).utf16charsEnd()); - ast->symbol = scope; - Scope *previousScope = switchScope(scope); + Template *templ = control()->newTemplate(ast->firstToken(), 0); + templ->setStartOffset(tokenAt(ast->firstToken()).utf16charsBegin()); + templ->setEndOffset(tokenAt(ast->lastToken() - 1).utf16charsEnd()); + ast->symbol = templ; + Scope *previousScope = switchScope(templ); for (DeclarationListAST *it = ast->template_parameter_list; it; it = it->next) { this->declaration(it->value); @@ -2384,17 +2368,12 @@ bool Bind::visit(TemplateDeclarationAST *ast) this->declaration(ast->declaration); (void) switchScope(previousScope); - Symbol *decl = 0; - if (Template *templ = scope->asTemplate()) - decl = templ->declaration(); - else if (ExplicitInstantiation *inst = scope->asExplicitInstantiation()) - decl = inst->declaration(); - if (decl) { - scope->setSourceLocation(decl->sourceLocation(), translationUnit()); - scope->setName(decl->name()); + if (Symbol *decl = templ->declaration()) { + templ->setSourceLocation(decl->sourceLocation(), translationUnit()); + templ->setName(decl->name()); } - _scope->addMember(scope); + _scope->addMember(templ); return false; } @@ -3039,7 +3018,6 @@ bool Bind::visit(TypeofSpecifierAST *ast) bool Bind::visit(DecltypeSpecifierAST *ast) { _type = this->expression(ast->expression); - _type.setDecltype(true); return false; } diff --git a/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h b/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h index 54f9db96da..9b1c5a30cf 100644 --- a/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h +++ b/src/libs/3rdparty/cplusplus/CPlusPlusForwardDeclarations.h @@ -112,7 +112,6 @@ class Function; class Namespace; class NamespaceAlias; class Template; -class ExplicitInstantiation; class BaseClass; class Block; class Class; diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp index 463a2f88f6..afdd679056 100644 --- a/src/libs/3rdparty/cplusplus/Control.cpp +++ b/src/libs/3rdparty/cplusplus/Control.cpp @@ -366,16 +366,9 @@ public: Template *newTemplate(unsigned sourceLocation, const Name *name) { - Template *templ = new Template(translationUnit, sourceLocation, name); - symbols.push_back(templ); - return templ; - } - - ExplicitInstantiation *newExplicitInstantiation(unsigned sourceLocation, const Name *name) - { - ExplicitInstantiation *inst = new ExplicitInstantiation(translationUnit, sourceLocation, name); - symbols.push_back(inst); - return inst; + Template *ns = new Template(translationUnit, sourceLocation, name); + symbols.push_back(ns); + return ns; } NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name) @@ -699,9 +692,6 @@ Namespace *Control::newNamespace(unsigned sourceLocation, const Name *name) Template *Control::newTemplate(unsigned sourceLocation, const Name *name) { return d->newTemplate(sourceLocation, name); } -ExplicitInstantiation *Control::newExplicitInstantiation(unsigned sourceLocation, const Name *name) -{ return d->newExplicitInstantiation(sourceLocation, name); } - NamespaceAlias *Control::newNamespaceAlias(unsigned sourceLocation, const Name *name) { return d->newNamespaceAlias(sourceLocation, name); } diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h index bb2bf9cd10..85b8c3d3d7 100644 --- a/src/libs/3rdparty/cplusplus/Control.h +++ b/src/libs/3rdparty/cplusplus/Control.h @@ -120,9 +120,6 @@ public: /// Creates a new Template symbol. Template *newTemplate(unsigned sourceLocation, const Name *name = 0); - /// Creates a new ExplicitInstantiation symbol. - ExplicitInstantiation *newExplicitInstantiation(unsigned sourceLocation, const Name *name = 0); - /// Creates a new Namespace symbol. NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name = 0); diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp index ea88140314..f78e4e9338 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.cpp @@ -100,12 +100,6 @@ bool FullySpecifiedType::isAuto() const void FullySpecifiedType::setAuto(bool isAuto) { f._isAuto = isAuto; } -bool FullySpecifiedType::isDecltype() const -{ return f._isDecltype; } - -void FullySpecifiedType::setDecltype(bool isDecltype) -{ f._isDecltype = isDecltype; } - bool FullySpecifiedType::isRegister() const { return f._isRegister; } diff --git a/src/libs/3rdparty/cplusplus/FullySpecifiedType.h b/src/libs/3rdparty/cplusplus/FullySpecifiedType.h index 4c7a21ddc3..8f20018465 100644 --- a/src/libs/3rdparty/cplusplus/FullySpecifiedType.h +++ b/src/libs/3rdparty/cplusplus/FullySpecifiedType.h @@ -58,9 +58,6 @@ public: bool isAuto() const; void setAuto(bool isAuto); - bool isDecltype() const; - void setDecltype(bool isDecltype); - bool isRegister() const; void setRegister(bool isRegister); @@ -128,7 +125,6 @@ private: // storage class specifiers unsigned _isFriend: 1; unsigned _isAuto: 1; - unsigned _isDecltype: 1; unsigned _isRegister: 1; unsigned _isStatic: 1; unsigned _isExtern: 1; diff --git a/src/libs/3rdparty/cplusplus/Matcher.cpp b/src/libs/3rdparty/cplusplus/Matcher.cpp index 379ed59586..7a3c21cafc 100644 --- a/src/libs/3rdparty/cplusplus/Matcher.cpp +++ b/src/libs/3rdparty/cplusplus/Matcher.cpp @@ -218,17 +218,6 @@ bool Matcher::match(const Template *type, const Template *otherType) return true; } -bool Matcher::match(const ExplicitInstantiation *type, const ExplicitInstantiation *otherType) -{ - if (type == otherType) - return true; - - if (! Matcher::match(type->name(), otherType->name(), this)) - return false; - - return true; -} - bool Matcher::match(const ForwardClassDeclaration *type, const ForwardClassDeclaration *otherType) { if (type == otherType) diff --git a/src/libs/3rdparty/cplusplus/Matcher.h b/src/libs/3rdparty/cplusplus/Matcher.h index 4d2b40b64d..1a9d9d3511 100644 --- a/src/libs/3rdparty/cplusplus/Matcher.h +++ b/src/libs/3rdparty/cplusplus/Matcher.h @@ -61,7 +61,6 @@ public: virtual bool match(const Enum *type, const Enum *otherType); virtual bool match(const Namespace *type, const Namespace *otherType); virtual bool match(const Template *type, const Template *otherType); - virtual bool match(const ExplicitInstantiation *type, const ExplicitInstantiation *otherType); virtual bool match(const ForwardClassDeclaration *type, const ForwardClassDeclaration *otherType); virtual bool match(const Class *type, const Class *otherType); virtual bool match(const ObjCClass *type, const ObjCClass *otherType); diff --git a/src/libs/3rdparty/cplusplus/Names.h b/src/libs/3rdparty/cplusplus/Names.h index 7b49190f8e..33f40d523d 100644 --- a/src/libs/3rdparty/cplusplus/Names.h +++ b/src/libs/3rdparty/cplusplus/Names.h @@ -100,7 +100,7 @@ public: TemplateArgumentIterator firstTemplateArgument() const { return _templateArguments.begin(); } TemplateArgumentIterator lastTemplateArgument() const { return _templateArguments.end(); } bool isSpecialization() const { return _isSpecialization; } - // this is temporary solution needed in LookupScope::nestedType + // this is temporary solution needed in ClassOrNamespace::nestedType // when we try to find correct specialization for instantiation void setIsSpecialization(bool isSpecialization) { _isSpecialization = isSpecialization; } diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 6fccebb015..901f5ac2c1 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1789,6 +1789,11 @@ bool Parser::parseEnumSpecifier(SpecifierListAST *&node) if (_languageFeatures.cxx11Enabled && (LA() == T_CLASS || LA() == T_STRUCT)) ast->key_token = consumeToken(); + + if (tok().isKeyword()) { + error(cursor(), "expected identifier before '%s'", tok().spell()); + return false; + } parseName(ast->name); if (_languageFeatures.cxx11Enabled && LA() == T_COLON) { diff --git a/src/libs/3rdparty/cplusplus/Scope.cpp b/src/libs/3rdparty/cplusplus/Scope.cpp index 783eff77ae..406a794c7e 100644 --- a/src/libs/3rdparty/cplusplus/Scope.cpp +++ b/src/libs/3rdparty/cplusplus/Scope.cpp @@ -215,7 +215,7 @@ unsigned SymbolTable::symbolCount() const Symbol *SymbolTable::symbolAt(unsigned index) const { - if (! _symbols || index >= symbolCount()) + if (! _symbols) return 0; return _symbols[index]; } diff --git a/src/libs/3rdparty/cplusplus/Symbol.cpp b/src/libs/3rdparty/cplusplus/Symbol.cpp index 0ddd4ffbb2..ae20b14bb7 100644 --- a/src/libs/3rdparty/cplusplus/Symbol.cpp +++ b/src/libs/3rdparty/cplusplus/Symbol.cpp @@ -361,9 +361,6 @@ bool Symbol::isNamespace() const bool Symbol::isTemplate() const { return asTemplate() != 0; } -bool Symbol::isExplicitInstantiation() const -{ return asExplicitInstantiation() != 0; } - bool Symbol::isClass() const { return asClass() != 0; } diff --git a/src/libs/3rdparty/cplusplus/Symbol.h b/src/libs/3rdparty/cplusplus/Symbol.h index cbed45f461..919268b14b 100644 --- a/src/libs/3rdparty/cplusplus/Symbol.h +++ b/src/libs/3rdparty/cplusplus/Symbol.h @@ -135,7 +135,7 @@ public: /// Returns true if this Symbol is an Enum. bool isEnum() const; - /// Returns true if this Symbol is a Function. + /// Returns true if this Symbol is an Function. bool isFunction() const; /// Returns true if this Symbol is a Namespace. @@ -144,9 +144,6 @@ public: /// Returns true if this Symbol is a Template. bool isTemplate() const; - /// Returns true if this Symbol is an ExplicitInstantiation. - bool isExplicitInstantiation() const; - /// Returns true if this Symbol is a Class. bool isClass() const; @@ -206,7 +203,6 @@ public: virtual const Function *asFunction() const { return 0; } virtual const Namespace *asNamespace() const { return 0; } virtual const Template *asTemplate() const { return 0; } - virtual const ExplicitInstantiation *asExplicitInstantiation() const { return 0; } virtual const NamespaceAlias *asNamespaceAlias() const { return 0; } virtual const Class *asClass() const { return 0; } virtual const Block *asBlock() const { return 0; } @@ -233,7 +229,6 @@ public: virtual Function *asFunction() { return 0; } virtual Namespace *asNamespace() { return 0; } virtual Template *asTemplate() { return 0; } - virtual ExplicitInstantiation *asExplicitInstantiation() { return 0; } virtual NamespaceAlias *asNamespaceAlias() { return 0; } virtual Class *asClass() { return 0; } virtual Block *asBlock() { return 0; } diff --git a/src/libs/3rdparty/cplusplus/SymbolVisitor.h b/src/libs/3rdparty/cplusplus/SymbolVisitor.h index 5331525e9f..4311672eca 100644 --- a/src/libs/3rdparty/cplusplus/SymbolVisitor.h +++ b/src/libs/3rdparty/cplusplus/SymbolVisitor.h @@ -51,7 +51,6 @@ public: virtual bool visit(Function *) { return true; } virtual bool visit(Namespace *) { return true; } virtual bool visit(Template *) { return true; } - virtual bool visit(ExplicitInstantiation *) { return true; } virtual bool visit(Class *) { return true; } virtual bool visit(Block *) { return true; } virtual bool visit(ForwardClassDeclaration *) { return true; } diff --git a/src/libs/3rdparty/cplusplus/Symbols.cpp b/src/libs/3rdparty/cplusplus/Symbols.cpp index 3c632f1cd7..f8a8440c09 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.cpp +++ b/src/libs/3rdparty/cplusplus/Symbols.cpp @@ -481,12 +481,10 @@ void Enum::visitSymbol0(SymbolVisitor *visitor) Template::Template(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Scope(translationUnit, sourceLocation, name) - , _isExplicitInstantiation(false) { } Template::Template(Clone *clone, Subst *subst, Template *original) : Scope(clone, subst, original) - , _isExplicitInstantiation(original->_isExplicitInstantiation) { } Template::~Template() @@ -539,56 +537,6 @@ bool Template::match0(const Type *otherType, Matcher *matcher) const return false; } -ExplicitInstantiation::ExplicitInstantiation(TranslationUnit *translationUnit, - unsigned sourceLocation, const Name *name) - : Scope(translationUnit, sourceLocation, name) -{ } - -ExplicitInstantiation::ExplicitInstantiation(Clone *clone, Subst *subst, ExplicitInstantiation *original) - : Scope(clone, subst, original) -{ } - -ExplicitInstantiation::~ExplicitInstantiation() -{ } - -Symbol *ExplicitInstantiation::declaration() const -{ - if (isEmpty()) - return 0; - - if (Symbol *s = memberAt(memberCount() - 1)) { - if (s->isClass() || s->isForwardClassDeclaration() || - s->isTemplate() || s->isExplicitInstantiation() || - s->isFunction() || s->isDeclaration()) { - return s; - } - } - - return 0; -} - -FullySpecifiedType ExplicitInstantiation::type() const -{ return FullySpecifiedType(const_cast<ExplicitInstantiation *>(this)); } - -void ExplicitInstantiation::visitSymbol0(SymbolVisitor *visitor) -{ - if (visitor->visit(this)) { - for (unsigned i = 0; i < memberCount(); ++i) { - visitSymbol(memberAt(i), visitor); - } - } -} - -void ExplicitInstantiation::accept0(TypeVisitor *visitor) -{ visitor->visit(this); } - -bool ExplicitInstantiation::match0(const Type *otherType, Matcher *matcher) const -{ - if (const ExplicitInstantiation *otherTy = otherType->asExplicitInstantiationType()) - return matcher->match(this, otherTy); - return false; -} - Namespace::Namespace(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name) : Scope(translationUnit, sourceLocation, name) , _isInline(false) diff --git a/src/libs/3rdparty/cplusplus/Symbols.h b/src/libs/3rdparty/cplusplus/Symbols.h index f2d92c23f2..257bdb8682 100644 --- a/src/libs/3rdparty/cplusplus/Symbols.h +++ b/src/libs/3rdparty/cplusplus/Symbols.h @@ -423,41 +423,8 @@ protected: virtual void visitSymbol0(SymbolVisitor *visitor); virtual void accept0(TypeVisitor *visitor); virtual bool match0(const Type *otherType, Matcher *matcher) const; - -private: - bool _isExplicitInstantiation; }; -class CPLUSPLUS_EXPORT ExplicitInstantiation : public Scope, public Type -{ -public: - ExplicitInstantiation(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name); - ExplicitInstantiation(Clone *clone, Subst *subst, ExplicitInstantiation *original); - virtual ~ExplicitInstantiation(); - - Symbol *declaration() const; - - // Symbol's interface - virtual FullySpecifiedType type() const; - - virtual const ExplicitInstantiation *asExplicitInstantiation() const - { return this; } - - virtual ExplicitInstantiation *asExplicitInstantiation() - { return this; } - - // Type's interface - virtual const ExplicitInstantiation *asExplicitInstantiationType() const - { return this; } - - virtual ExplicitInstantiation *asExplicitInstantiationType() - { return this; } - -protected: - virtual void visitSymbol0(SymbolVisitor *visitor); - virtual void accept0(TypeVisitor *visitor); - virtual bool match0(const Type *otherType, Matcher *matcher) const; -}; class CPLUSPLUS_EXPORT Namespace: public Scope, public Type { diff --git a/src/libs/3rdparty/cplusplus/Templates.cpp b/src/libs/3rdparty/cplusplus/Templates.cpp index 41e462a3b8..3b8ae9a23f 100644 --- a/src/libs/3rdparty/cplusplus/Templates.cpp +++ b/src/libs/3rdparty/cplusplus/Templates.cpp @@ -125,12 +125,6 @@ void CloneType::visit(Template *type) _type = templ; } -void CloneType::visit(ExplicitInstantiation *type) -{ - ExplicitInstantiation *inst = _clone->symbol(type, _subst)->asExplicitInstantiation(); - _type = inst; -} - void CloneType::visit(Class *type) { Class *klass = _clone->symbol(type, _subst)->asClass(); @@ -194,8 +188,10 @@ Symbol *CloneSymbol::cloneSymbol(Symbol *symbol, Subst *subst) SymbolSubstPair symbolSubstPair = std::make_pair(symbol, subst); auto it = _cache.find(symbolSubstPair); - if (it != _cache.end()) - return it->second; + if (it != _cache.end()) { + if (it->second->enclosingScope() == symbol->enclosingScope()) + return it->second; + } Symbol *r = 0; std::swap(_subst, subst); @@ -297,14 +293,6 @@ bool CloneSymbol::visit(Template *symbol) return false; } -bool CloneSymbol::visit(ExplicitInstantiation *symbol) -{ - ExplicitInstantiation *inst = new ExplicitInstantiation(_clone, _subst, symbol); - _symbol = inst; - _control->addSymbol(inst); - return false; -} - bool CloneSymbol::visit(Class *symbol) { Class *klass = new Class(_clone, _subst, symbol); diff --git a/src/libs/3rdparty/cplusplus/Templates.h b/src/libs/3rdparty/cplusplus/Templates.h index e39f79a7a6..9db69084f7 100644 --- a/src/libs/3rdparty/cplusplus/Templates.h +++ b/src/libs/3rdparty/cplusplus/Templates.h @@ -85,7 +85,6 @@ protected: virtual void visit(Function *type); virtual void visit(Namespace *type); virtual void visit(Template *type); - virtual void visit(ExplicitInstantiation *type); virtual void visit(Class *type); virtual void visit(Enum *type); virtual void visit(ForwardClassDeclaration *type); @@ -153,7 +152,6 @@ protected: virtual bool visit(Function *symbol); virtual bool visit(Namespace *symbol); virtual bool visit(Template *symbol); - virtual bool visit(ExplicitInstantiation *symbol); virtual bool visit(Class *symbol); virtual bool visit(Block *symbol); virtual bool visit(ForwardClassDeclaration *symbol); diff --git a/src/libs/3rdparty/cplusplus/Type.cpp b/src/libs/3rdparty/cplusplus/Type.cpp index 69ffb5030a..bad4d42eeb 100644 --- a/src/libs/3rdparty/cplusplus/Type.cpp +++ b/src/libs/3rdparty/cplusplus/Type.cpp @@ -68,9 +68,6 @@ bool Type::isNamespaceType() const bool Type::isTemplateType() const { return asTemplateType() != 0; } -bool Type::isExplicitInstantiationType() const -{ return asExplicitInstantiationType() != 0; } - bool Type::isClassType() const { return asClassType() != 0; } diff --git a/src/libs/3rdparty/cplusplus/Type.h b/src/libs/3rdparty/cplusplus/Type.h index 2661628f76..958ba15efd 100644 --- a/src/libs/3rdparty/cplusplus/Type.h +++ b/src/libs/3rdparty/cplusplus/Type.h @@ -43,7 +43,6 @@ public: bool isFunctionType() const; bool isNamespaceType() const; bool isTemplateType() const; - bool isExplicitInstantiationType() const; bool isClassType() const; bool isEnumType() const; bool isForwardClassDeclarationType() const; @@ -65,7 +64,6 @@ public: virtual const Function *asFunctionType() const { return 0; } virtual const Namespace *asNamespaceType() const { return 0; } virtual const Template *asTemplateType() const { return 0; } - virtual const ExplicitInstantiation *asExplicitInstantiationType() const { return 0; } virtual const Class *asClassType() const { return 0; } virtual const Enum *asEnumType() const { return 0; } virtual const ForwardClassDeclaration *asForwardClassDeclarationType() const { return 0; } @@ -87,7 +85,6 @@ public: virtual Function *asFunctionType() { return 0; } virtual Namespace *asNamespaceType() { return 0; } virtual Template *asTemplateType() { return 0; } - virtual ExplicitInstantiation *asExplicitInstantiationType() { return 0; } virtual Class *asClassType() { return 0; } virtual Enum *asEnumType() { return 0; } virtual ForwardClassDeclaration *asForwardClassDeclarationType() { return 0; } diff --git a/src/libs/3rdparty/cplusplus/TypeVisitor.h b/src/libs/3rdparty/cplusplus/TypeVisitor.h index 86568dcebc..b3a24b1572 100644 --- a/src/libs/3rdparty/cplusplus/TypeVisitor.h +++ b/src/libs/3rdparty/cplusplus/TypeVisitor.h @@ -51,7 +51,6 @@ public: virtual void visit(Function *) {} virtual void visit(Namespace *) {} virtual void visit(Template *) {} - virtual void visit(ExplicitInstantiation *) {} virtual void visit(Class *) {} virtual void visit(Enum *) {} virtual void visit(ForwardClassDeclaration *) {} diff --git a/src/libs/3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp b/src/libs/3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp index 641b303d2b..bb8d11ebdd 100644 --- a/src/libs/3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp +++ b/src/libs/3rdparty/modeling/qmt/model_widgets_ui/classmembersedit.cpp @@ -490,7 +490,8 @@ QList<MClassMember> ClassMembersEdit::parse(const QString &text, bool *ok) member.setProperties(member.properties() | MClassMember::PropertyQslot); word = cursor.readWord().toLower(); } else if (word == QStringLiteral("invokable") || word == QStringLiteral("qInvokable")) { - member.setProperties(member.properties() | MClassMember::PropertyQinvokable); + member.setProperties(member.getProperties() | MClassMember::PROPERTY_QINVOKABLE); + word = cursor.readWord().toLower(); } else if (word == QStringLiteral(":")) { word = cursor.readWord().toLower(); } else { diff --git a/src/libs/clangbackendipc/clangbackendipc_global.h b/src/libs/clangbackendipc/clangbackendipc_global.h index 544a5b15ac..c9851069b5 100644 --- a/src/libs/clangbackendipc/clangbackendipc_global.h +++ b/src/libs/clangbackendipc/clangbackendipc_global.h @@ -53,5 +53,28 @@ enum class DiagnosticSeverity // one to one mapping of the clang enum numbers Error = 3, Fatal = 4 }; + +enum class HighlightingType +{ + Invalid, + Keyword, + StringLiteral, + NumberLiteral, + Comment, + Function, + VirtualFunction, + Type, + LocalVariable, + Field, + GlobalVariable, + Enumeration, + Operator, + Preprocessor, + PreprocessorDefinition, + PreprocessorExpansion, + Label, + OutputArgument +}; + } #endif // CLANGBACKENDIPC_GLOBAL_H diff --git a/src/libs/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp index fa66e3b4e3..63eadd912c 100644 --- a/src/libs/cplusplus/CppRewriter.cpp +++ b/src/libs/cplusplus/CppRewriter.cpp @@ -379,7 +379,7 @@ FullySpecifiedType SubstitutionMap::apply(const Name *name, Rewrite *) const } -UseMinimalNames::UseMinimalNames(LookupScope *target) +UseMinimalNames::UseMinimalNames(ClassOrNamespace *target) : _target(target) { diff --git a/src/libs/cplusplus/CppRewriter.h b/src/libs/cplusplus/CppRewriter.h index cb307a9401..cc68f662a5 100644 --- a/src/libs/cplusplus/CppRewriter.h +++ b/src/libs/cplusplus/CppRewriter.h @@ -89,13 +89,13 @@ private: class CPLUSPLUS_EXPORT UseMinimalNames: public Substitution { public: - UseMinimalNames(LookupScope *target); + UseMinimalNames(ClassOrNamespace *target); virtual ~UseMinimalNames(); virtual FullySpecifiedType apply(const Name *name, Rewrite *rewrite) const; private: - LookupScope *_target; + ClassOrNamespace *_target; }; class CPLUSPLUS_EXPORT UseQualifiedNames: public UseMinimalNames diff --git a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp new file mode 100644 index 0000000000..e037f87c58 --- /dev/null +++ b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp @@ -0,0 +1,430 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "DeprecatedGenTemplateInstance.h" +#include "Overview.h" + +#include <cplusplus/Control.h> +#include <cplusplus/Scope.h> +#include <cplusplus/Names.h> +#include <cplusplus/Symbols.h> +#include <cplusplus/CoreTypes.h> +#include <cplusplus/Literals.h> + +#include <QVarLengthArray> +#include <QDebug> + +using namespace CPlusPlus; + +namespace { + +class ApplySubstitution +{ +public: + ApplySubstitution(Control *control, Symbol *symbol, const DeprecatedGenTemplateInstance::Substitution &substitution); + ~ApplySubstitution(); + + inline Control *control() const { return _control; } + + FullySpecifiedType apply(const Name *name); + FullySpecifiedType apply(const FullySpecifiedType &type); + + int findSubstitution(const Identifier *id) const; + FullySpecifiedType applySubstitution(int index) const; + +private: + class ApplyToType: protected TypeVisitor + { + public: + ApplyToType(ApplySubstitution *q) + : q(q) {} + + FullySpecifiedType operator()(const FullySpecifiedType &ty) + { + FullySpecifiedType previousType = switchType(ty); + accept(ty.type()); + return switchType(previousType); + } + + protected: + using TypeVisitor::visit; + + Control *control() const + { return q->control(); } + + FullySpecifiedType switchType(const FullySpecifiedType &type) + { + FullySpecifiedType previousType = _type; + _type = type; + return previousType; + } + + virtual void visit(VoidType *) + { + // nothing to do + } + + virtual void visit(IntegerType *) + { + // nothing to do + } + + virtual void visit(FloatType *) + { + // nothing to do + } + + virtual void visit(PointerToMemberType *) + { + qDebug() << Q_FUNC_INFO; // ### TODO + } + + virtual void visit(PointerType *ptrTy) + { + _type.setType(control()->pointerType(q->apply(ptrTy->elementType()))); + } + + virtual void visit(ReferenceType *refTy) + { + _type.setType(control()->referenceType(q->apply(refTy->elementType()), refTy->isRvalueReference())); + } + + virtual void visit(ArrayType *arrayTy) + { + _type.setType(control()->arrayType(q->apply(arrayTy->elementType()), arrayTy->size())); + } + + virtual void visit(NamedType *ty) + { + FullySpecifiedType n = q->apply(ty->name()); + _type.setType(n.type()); + } + + virtual void visit(Function *funTy) + { + Function *fun = control()->newFunction(/*sourceLocation=*/ 0, funTy->name()); + fun->setEnclosingScope(funTy->enclosingScope()); + fun->setConst(funTy->isConst()); + fun->setVolatile(funTy->isVolatile()); + fun->setVirtual(funTy->isVirtual()); + fun->setOverride(funTy->isOverride()); + fun->setFinal(funTy->isFinal()); + fun->setAmbiguous(funTy->isAmbiguous()); + fun->setVariadic(funTy->isVariadic()); + + fun->setReturnType(q->apply(funTy->returnType())); + + for (unsigned i = 0, argc = funTy->argumentCount(); i < argc; ++i) { + Argument *originalArgument = funTy->argumentAt(i)->asArgument(); + Argument *arg = control()->newArgument(/*sourceLocation*/ 0, + originalArgument->name()); + + arg->setType(q->apply(originalArgument->type())); + arg->setInitializer(originalArgument->initializer()); + fun->addMember(arg); + } + + _type.setType(fun); + } + + virtual void visit(Namespace *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(Class *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(Enum *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(ForwardClassDeclaration *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(ObjCClass *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(ObjCProtocol *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(ObjCMethod *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(ObjCForwardClassDeclaration *) + { + qDebug() << Q_FUNC_INFO; + } + + virtual void visit(ObjCForwardProtocolDeclaration *) + { + qDebug() << Q_FUNC_INFO; + } + + private: + ApplySubstitution *q; + FullySpecifiedType _type; + QHash<Symbol *, FullySpecifiedType> _processed; + }; + + class ApplyToName: protected NameVisitor + { + public: + ApplyToName(ApplySubstitution *q): q(q) {} + + FullySpecifiedType operator()(const Name *name) + { + FullySpecifiedType previousType = switchType(FullySpecifiedType()); + accept(name); + return switchType(previousType); + } + + protected: + Control *control() const + { return q->control(); } + + int findSubstitution(const Identifier *id) const + { return q->findSubstitution(id); } + + FullySpecifiedType applySubstitution(int index) const + { return q->applySubstitution(index); } + + FullySpecifiedType switchType(const FullySpecifiedType &type) + { + FullySpecifiedType previousType = _type; + _type = type; + return previousType; + } + + virtual void visit(const Identifier *name) + { + int index = findSubstitution(name->identifier()); + + if (index != -1) + _type = applySubstitution(index); + + else + _type = control()->namedType(name); + } + + virtual void visit(const TemplateNameId *name) + { + QVarLengthArray<FullySpecifiedType, 8> arguments(name->templateArgumentCount()); + for (unsigned i = 0; i < name->templateArgumentCount(); ++i) { + FullySpecifiedType argTy = name->templateArgumentAt(i); + arguments[i] = q->apply(argTy); + } + + const TemplateNameId *templId = control()->templateNameId(name->identifier(), + name->isSpecialization(), + arguments.data(), + arguments.size()); + _type = control()->namedType(templId); + } + + const Name *instantiate(const Name *name) + { + if (! name) + return name; + + if (const Identifier *nameId = name->asNameId()) { + const Identifier *id = control()->identifier(nameId->chars(), nameId->size()); + return id; + + } else if (const TemplateNameId *templId = name->asTemplateNameId()) { + QVarLengthArray<FullySpecifiedType, 8> arguments(templId->templateArgumentCount()); + for (unsigned templateArgIndex = 0; templateArgIndex < templId->templateArgumentCount(); + ++templateArgIndex) { + FullySpecifiedType argTy = templId->templateArgumentAt(templateArgIndex); + arguments[templateArgIndex] = q->apply(argTy); + } + const Identifier *id = control()->identifier(templId->identifier()->chars(), + templId->identifier()->size()); + return control()->templateNameId(id, templId->isSpecialization(), arguments.data(), + arguments.size()); + + } else if (const QualifiedNameId *qq = name->asQualifiedNameId()) { + const Name *base = instantiate(qq->base()); + const Name *name = instantiate(qq->name()); + + return control()->qualifiedNameId(base, name); + + } else if (const OperatorNameId *op = name->asOperatorNameId()) { + return control()->operatorNameId(op->kind()); + + } else if (const ConversionNameId *c = name->asConversionNameId()) { + FullySpecifiedType ty = q->apply(c->type()); + return control()->conversionNameId(ty); + + } + + return 0; + } + + virtual void visit(const QualifiedNameId *name) + { + if (const Name *n = instantiate(name)) + _type = control()->namedType(n); + } + + virtual void visit(const DestructorNameId *name) + { + Overview oo; + qWarning() << "ignored name:" << oo.prettyName(name); + } + + virtual void visit(const OperatorNameId *name) + { + Overview oo; + qWarning() << "ignored name:" << oo.prettyName(name); + } + + virtual void visit(const ConversionNameId *name) + { + Overview oo; + qWarning() << "ignored name:" << oo.prettyName(name); + } + + virtual void visit(const SelectorNameId *name) + { + Overview oo; + qWarning() << "ignored name:" << oo.prettyName(name); + } + + private: + ApplySubstitution *q; + FullySpecifiedType _type; + }; + +public: // attributes + Control *_control; + Symbol *symbol; + DeprecatedGenTemplateInstance::Substitution substitution; + ApplyToType applyToType; + ApplyToName applyToName; +}; + +ApplySubstitution::ApplySubstitution(Control *control, Symbol *symbol, + const DeprecatedGenTemplateInstance::Substitution &substitution) + : _control(control), symbol(symbol), + substitution(substitution), + applyToType(this), applyToName(this) +{ } + +ApplySubstitution::~ApplySubstitution() +{ +} + +FullySpecifiedType ApplySubstitution::apply(const Name *name) +{ + FullySpecifiedType ty = applyToName(name); + return ty; +} + +FullySpecifiedType ApplySubstitution::apply(const FullySpecifiedType &type) +{ + FullySpecifiedType ty = applyToType(type); + return ty; +} + +int ApplySubstitution::findSubstitution(const Identifier *id) const +{ + Q_ASSERT(id != 0); + + for (int index = 0; index < substitution.size(); ++index) { + QPair<const Identifier *, FullySpecifiedType> s = substitution.at(index); + + if (id->match(s.first)) + return index; + } + + return -1; +} + +FullySpecifiedType ApplySubstitution::applySubstitution(int index) const +{ + Q_ASSERT(index != -1); + Q_ASSERT(index < substitution.size()); + + return substitution.at(index).second; +} + +} // end of anonymous namespace + +DeprecatedGenTemplateInstance::DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution) + : _control(control), + _substitution(substitution) +{ } + +FullySpecifiedType DeprecatedGenTemplateInstance::gen(Symbol *symbol) +{ + ApplySubstitution o(_control.data(), symbol, _substitution); + return o.apply(symbol->type()); +} + +FullySpecifiedType DeprecatedGenTemplateInstance::instantiate(const Name *className, Symbol *candidate, + QSharedPointer<Control> control) +{ + if (className) { + if (const TemplateNameId *templId = className->asTemplateNameId()) { + if (Template *templ = candidate->enclosingTemplate()) { + DeprecatedGenTemplateInstance::Substitution subst; + + for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) { + FullySpecifiedType templArgTy = templId->templateArgumentAt(i); + + if (i < templ->templateParameterCount()) { + const Name *templArgName = templ->templateParameterAt(i)->name(); + + if (templArgName && templArgName->identifier()) { + const Identifier *templArgId = templArgName->identifier(); + subst.append(qMakePair(templArgId, templArgTy)); + } + } + } + + DeprecatedGenTemplateInstance inst(control, subst); + return inst.gen(candidate); + } + } + } + return candidate->type(); +} diff --git a/src/libs/cplusplus/TypeResolver.h b/src/libs/cplusplus/DeprecatedGenTemplateInstance.h index bf25e468c6..9e488478c6 100644 --- a/src/libs/cplusplus/TypeResolver.h +++ b/src/libs/cplusplus/DeprecatedGenTemplateInstance.h @@ -28,41 +28,36 @@ ** ****************************************************************************/ -#ifndef TYPERESOLVER_H -#define TYPERESOLVER_H +#ifndef CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H +#define CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H -#include "LookupContext.h" +#include <cplusplus/TypeVisitor.h> +#include <cplusplus/NameVisitor.h> +#include <cplusplus/FullySpecifiedType.h> + +#include <QList> +#include <QPair> +#include <QSharedPointer> namespace CPlusPlus { -class TypeResolver +class CPLUSPLUS_EXPORT DeprecatedGenTemplateInstance { public: - TypeResolver(CreateBindings &factory) : _factory(factory) {} - void resolve(FullySpecifiedType *type, Scope **scope, LookupScope *binding); - static QList<LookupItem> resolveDeclInitializer( - CreateBindings &factory, const Declaration *decl, - const QSet<const Declaration *> &declarationsBeingResolved, - const Identifier *id = 0); - -private: - NamedType *getNamedType(FullySpecifiedType& type) const; - - QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope, - LookupScope *binding) const; + typedef QList< QPair<const Identifier *, FullySpecifiedType> > Substitution; - static QList<LookupItem> typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope); - - static bool isTypedefWithName(const Declaration *declaration, const Name *name); +public: + static FullySpecifiedType instantiate(const Name *className, Symbol *candidate, QSharedPointer<Control> control); - bool findTypedef(const QList<LookupItem>& namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet<Symbol *>& visited); +private: + DeprecatedGenTemplateInstance(QSharedPointer<Control> control, const Substitution &substitution); + FullySpecifiedType gen(Symbol *symbol); - CreateBindings &_factory; - // binding has to be remembered in case of resolving typedefs for templates - LookupScope *_binding; +private: + QSharedPointer<Control> _control; + const Substitution _substitution; }; } // namespace CPlusPlus -#endif // TYPERESOLVER_H +#endif // CPLUSPLUS_DEPRECATEDGENTEMPLATEINSTANCE_H diff --git a/src/libs/cplusplus/FindUsages.cpp b/src/libs/cplusplus/FindUsages.cpp index b9d34bd00c..0640fab537 100644 --- a/src/libs/cplusplus/FindUsages.cpp +++ b/src/libs/cplusplus/FindUsages.cpp @@ -532,7 +532,7 @@ void FindUsages::memInitializer(MemInitializerAST *ast) if (_currentScope->isFunction()) { Class *classScope = _currentScope->enclosingClass(); if (! classScope) { - if (LookupScope *binding = _context.lookupType(_currentScope)) { + if (ClassOrNamespace *binding = _context.lookupType(_currentScope)) { foreach (Symbol *s, binding->symbols()) { if (Class *k = s->asClass()) { classScope = k; diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 401d54f48b..be1968733e 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -32,8 +32,8 @@ #include "ResolveExpression.h" #include "Overview.h" +#include "DeprecatedGenTemplateInstance.h" #include "CppRewriter.h" -#include "TypeResolver.h" #include <cplusplus/CoreTypes.h> #include <cplusplus/Symbols.h> @@ -41,18 +41,15 @@ #include <cplusplus/Names.h> #include <cplusplus/Scope.h> #include <cplusplus/Control.h> -#include <cplusplus/cppassert.h> #include <QStack> #include <QHash> #include <QVarLengthArray> #include <QDebug> -static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty(); - -namespace CPlusPlus { +using namespace CPlusPlus; -typedef QSet<Internal::LookupScopePrivate *> ProcessedSet; +static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty(); static void addNames(const Name *name, QList<const Name *> *names, bool addAllNames = false) { @@ -92,6 +89,24 @@ static void path_helper(Symbol *symbol, QList<const Name *> *names) } } +static bool isNestedInstantiationEnclosingTemplate( + ClassOrNamespace *nestedClassOrNamespaceInstantiation, + ClassOrNamespace *enclosingTemplateClassInstantiation) +{ + QList<ClassOrNamespace *> processed; + while (enclosingTemplateClassInstantiation + && !processed.contains(enclosingTemplateClassInstantiation)) { + processed.append(enclosingTemplateClassInstantiation); + if (enclosingTemplateClassInstantiation == nestedClassOrNamespaceInstantiation) + return false; + enclosingTemplateClassInstantiation = enclosingTemplateClassInstantiation->parent(); + } + + return true; +} + +namespace CPlusPlus { + static inline bool compareName(const Name *name, const Name *other) { if (name == other) @@ -121,6 +136,9 @@ bool compareFullyQualifiedName(const QList<const Name *> &path, const QList<cons return true; } +} + +namespace CPlusPlus { namespace Internal { bool operator==(const FullyQualifiedName &left, const FullyQualifiedName &right) @@ -142,6 +160,7 @@ uint qHash(const FullyQualifiedName &fullyQualifiedName) return h; } } +} ///////////////////////////////////////////////////////////////////// // LookupContext @@ -163,7 +182,7 @@ LookupContext::LookupContext(Document::Ptr thisDocument, LookupContext::LookupContext(Document::Ptr expressionDocument, Document::Ptr thisDocument, const Snapshot &snapshot, - CreateBindings::Ptr bindings) + QSharedPointer<CreateBindings> bindings) : _expressionDocument(expressionDocument) , _thisDocument(thisDocument) , _snapshot(snapshot) @@ -216,7 +235,7 @@ static bool symbolIdentical(Symbol *s1, Symbol *s2) return QByteArray(s1->fileName()) == QByteArray(s2->fileName()); } -const Name *LookupContext::minimalName(Symbol *symbol, LookupScope *target, Control *control) +const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control) { const Name *n = 0; QList<const Name *> names = LookupContext::fullyQualifiedName(symbol); @@ -241,7 +260,7 @@ const Name *LookupContext::minimalName(Symbol *symbol, LookupScope *target, Cont } QList<LookupItem> LookupContext::lookupByUsing(const Name *name, - LookupScope *bindingScope) const + ClassOrNamespace *bindingScope) const { QList<LookupItem> candidates; // if it is a nameId there can be a using declaration for it @@ -275,7 +294,7 @@ QList<LookupItem> LookupContext::lookupByUsing(const Name *name, } else if (const QualifiedNameId *q = name->asQualifiedNameId()) { foreach (Symbol *s, bindingScope->symbols()) { if (Scope *scope = s->asScope()) { - LookupScope *base = lookupType(q->base(), scope); + ClassOrNamespace *base = lookupType(q->base(), scope); if (base) candidates = lookupByUsing(q->name(), base); if (!candidates.isEmpty()) @@ -299,14 +318,14 @@ Document::Ptr LookupContext::document(const QString &fileName) const Snapshot LookupContext::snapshot() const { return _snapshot; } -LookupScope *LookupContext::globalNamespace() const +ClassOrNamespace *LookupContext::globalNamespace() const { return bindings()->globalNamespace(); } -LookupScope *LookupContext::lookupType(const Name *name, Scope *scope, - LookupScope *enclosingBinding, - QSet<const Declaration *> typedefsBeingResolved) const +ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope, + ClassOrNamespace *enclosingBinding, + QSet<const Declaration *> typedefsBeingResolved) const { if (! scope || ! name) { return 0; @@ -314,8 +333,8 @@ LookupScope *LookupContext::lookupType(const Name *name, Scope *scope, for (unsigned i = 0; i < block->memberCount(); ++i) { Symbol *m = block->memberAt(i); if (UsingNamespaceDirective *u = m->asUsingNamespaceDirective()) { - if (LookupScope *uu = lookupType(u->name(), scope->enclosingNamespace())) { - if (LookupScope *r = uu->lookupType(name)) + if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) { + if (ClassOrNamespace *r = uu->lookupType(name)) return r; } } else if (Declaration *d = m->asDeclaration()) { @@ -348,20 +367,20 @@ LookupScope *LookupContext::lookupType(const Name *name, Scope *scope, } // try to find it in block (rare case but has priority before enclosing scope) // e.g.: void foo() { struct S {}; S s; } - if (LookupScope *b = bindings()->lookupType(scope, enclosingBinding)) { - if (LookupScope *lookupScopeNestedInNestedBlock = b->lookupType(name, block)) - return lookupScopeNestedInNestedBlock; + if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingBinding)) { + if (ClassOrNamespace *classOrNamespaceNestedInNestedBlock = b->lookupType(name, block)) + return classOrNamespaceNestedInNestedBlock; } // try to find type in enclosing scope(typical case) - if (LookupScope *found = lookupType(name, scope->enclosingScope())) + if (ClassOrNamespace *found = lookupType(name, scope->enclosingScope())) return found; - } else if (LookupScope *b = bindings()->lookupType(scope, enclosingBinding)) { + } else if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingBinding)) { return b->lookupType(name); } else if (Class *scopeAsClass = scope->asClass()) { if (scopeAsClass->enclosingScope()->isBlock()) { - if (LookupScope *b = lookupType(scopeAsClass->name(), + if (ClassOrNamespace *b = lookupType(scopeAsClass->name(), scopeAsClass->enclosingScope(), enclosingBinding, typedefsBeingResolved)) { @@ -373,7 +392,8 @@ LookupScope *LookupContext::lookupType(const Name *name, Scope *scope, return 0; } -LookupScope *LookupContext::lookupType(Symbol *symbol, LookupScope *enclosingBinding) const +ClassOrNamespace *LookupContext::lookupType(Symbol *symbol, + ClassOrNamespace *enclosingBinding) const { return bindings()->lookupType(symbol, enclosingBinding); } @@ -387,7 +407,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const for (; scope; scope = scope->enclosingScope()) { if (name->identifier() != 0 && scope->isBlock()) { - bindings()->lookupInScope(name, scope, &candidates); + bindings()->lookupInScope(name, scope, &candidates, /*templateId = */ 0, /*binding=*/ 0); if (! candidates.isEmpty()) { // it's a local. @@ -400,7 +420,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const for (unsigned i = 0; i < scope->memberCount(); ++i) { if (UsingNamespaceDirective *u = scope->memberAt(i)->asUsingNamespaceDirective()) { - if (LookupScope *uu = lookupType(u->name(), scope->enclosingNamespace())) { + if (ClassOrNamespace *uu = lookupType(u->name(), scope->enclosingNamespace())) { candidates = uu->find(name); if (! candidates.isEmpty()) @@ -409,8 +429,8 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const } } - if (LookupScope *bindingScope = bindings()->lookupType(scope)) { - if (LookupScope *bindingBlock = bindingScope->findBlock(scope->asBlock())) { + if (ClassOrNamespace *bindingScope = bindings()->lookupType(scope)) { + if (ClassOrNamespace *bindingBlock = bindingScope->findBlock(scope->asBlock())) { candidates = lookupByUsing(name, bindingBlock); if (! candidates.isEmpty()) return candidates; @@ -423,7 +443,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const } } else if (Function *fun = scope->asFunction()) { - bindings()->lookupInScope(name, fun, &candidates); + bindings()->lookupInScope(name, fun, &candidates, /*templateId = */ 0, /*binding=*/ 0); if (! candidates.isEmpty()) { // it's an argument or a template parameter. @@ -435,7 +455,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const } if (fun->name() && fun->name()->isQualifiedNameId()) { - if (LookupScope *binding = bindings()->lookupType(fun)) { + if (ClassOrNamespace *binding = bindings()->lookupType(fun)) { candidates = binding->find(name); // try find this name in parent class @@ -450,13 +470,13 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const // continue, and look at the enclosing scope. } else if (ObjCMethod *method = scope->asObjCMethod()) { - bindings()->lookupInScope(name, method, &candidates); + bindings()->lookupInScope(name, method, &candidates, /*templateId = */ 0, /*binding=*/ 0); if (! candidates.isEmpty()) break; // it's a formal argument. } else if (Template *templ = scope->asTemplate()) { - bindings()->lookupInScope(name, templ, &candidates); + bindings()->lookupInScope(name, templ, &candidates, /*templateId = */ 0, /*binding=*/ 0); if (! candidates.isEmpty()) { // it's a template parameter. @@ -471,7 +491,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const || scope->asClass() || (scope->asEnum() && scope->asEnum()->isScoped())) { - if (LookupScope *bindingScope = bindings()->lookupType(scope)) { + if (ClassOrNamespace *bindingScope = bindings()->lookupType(scope)) { candidates = bindingScope->find(name); if (! candidates.isEmpty()) @@ -484,9 +504,9 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const // the scope can be defined inside a block, try to find it if (Block *block = scope->enclosingBlock()) { - if (LookupScope *b = bindings()->lookupType(block)) { - if (LookupScope *lookupScopeNestedInNestedBlock = b->lookupType(scope->name(), block)) - candidates = lookupScopeNestedInNestedBlock->find(name); + if (ClassOrNamespace *b = bindings()->lookupType(block)) { + if (ClassOrNamespace *classOrNamespaceNestedInNestedBlock = b->lookupType(scope->name(), block)) + candidates = classOrNamespaceNestedInNestedBlock->find(name); } } @@ -494,7 +514,7 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const return candidates; } else if (scope->isObjCClass() || scope->isObjCProtocol()) { - if (LookupScope *binding = bindings()->lookupType(scope)) + if (ClassOrNamespace *binding = bindings()->lookupType(scope)) candidates = binding->find(name); if (! candidates.isEmpty()) @@ -505,10 +525,10 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const return candidates; } -LookupScope *LookupContext::lookupParent(Symbol *symbol) const +ClassOrNamespace *LookupContext::lookupParent(Symbol *symbol) const { QList<const Name *> fqName = path(symbol); - LookupScope *binding = globalNamespace(); + ClassOrNamespace *binding = globalNamespace(); foreach (const Name *name, fqName) { binding = binding->findType(name); if (!binding) @@ -518,193 +538,59 @@ LookupScope *LookupContext::lookupParent(Symbol *symbol) const return binding; } -namespace Internal { - -class LookupScopePrivate -{ -public: - LookupScopePrivate(LookupScope *q, CreateBindings *factory, LookupScope *parent); - ~LookupScopePrivate(); - - typedef std::map<const Name *, LookupScopePrivate *, Name::Compare> Table; - typedef std::map<const Name *, Declaration *, Name::Compare> TypedefTable; - typedef std::map<const TemplateNameId *, - LookupScopePrivate *, - TemplateNameId::Compare> TemplateNameIdTable; - typedef QHash<const AnonymousNameId *, LookupScopePrivate *> Anonymouses; - - LookupScopePrivate *allocateChild(const Name *name); - - void flush(); - - LookupScope *globalNamespace() const; - - Symbol *lookupInScope(const QList<const Name *> &fullName); - - LookupScope *findOrCreateType(const Name *name, LookupScopePrivate *origin = 0, - Class *clazz = 0); - - LookupScopePrivate *findOrCreateNestedAnonymousType(const AnonymousNameId *anonymousNameId); - - void addTodo(Symbol *symbol); - void addSymbol(Symbol *symbol); - void addUnscopedEnum(Enum *e); - void addTypedef(const Name *identifier, Declaration *d); - void addUsing(LookupScope *u); - void addNestedType(const Name *alias, LookupScope *e); - - QList<LookupItem> lookup_helper(const Name *name, bool searchInEnclosingScope); - - void lookup_helper(const Name *name, LookupScopePrivate *binding, - QList<LookupItem> *result, - ProcessedSet *processed); - - LookupScope *lookupType_helper(const Name *name, ProcessedSet *processed, - bool searchInEnclosingScope, LookupScopePrivate *origin); - - LookupScope *findBlock_helper(Block *block, ProcessedSet *processed, - bool searchInEnclosingScope); - -private: - LookupScopePrivate *findNestedType(const Name *name, LookupScopePrivate *origin); - - LookupScopePrivate *nestedType(const Name *name, LookupScopePrivate *origin); - - LookupScopePrivate *findSpecialization(const TemplateNameId *templId, - const TemplateNameIdTable &specializations, - LookupScopePrivate *origin); - -public: - LookupScope *q; - - CreateBindings *_factory; - LookupScopePrivate *_parent; - QList<Symbol *> _symbols; - QList<LookupScope *> _usings; - Table _nestedScopes; - TypedefTable _typedefs; - QHash<Block *, LookupScope *> _blocks; - QList<Enum *> _enums; - QList<Symbol *> _todo; - QSharedPointer<Control> _control; - TemplateNameIdTable _specializations; - QMap<const TemplateNameId *, LookupScopePrivate *> _instantiations; - Anonymouses _anonymouses; - QSet<const AnonymousNameId *> _declaredOrTypedefedAnonymouses; - - QHash<Internal::FullyQualifiedName, Symbol *> *_scopeLookupCache; - - // it's an instantiation. - LookupScopePrivate *_instantiationOrigin; - - AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses; - AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates; - QSet<const Declaration *> _alreadyConsideredTypedefs; - - Class *_rootClass; - const Name *_name; - bool _hasTypedefs; -}; - -class Instantiator -{ -public: - Instantiator(Clone &cloner, Subst &subst) - : _cloner(cloner) - , _subst(subst) - {} - void doInstantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *instantiation); - LookupScopePrivate *instantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *origin); - -private: - ProcessedSet _alreadyConsideredInstantiations; - Clone &_cloner; - Subst &_subst; -}; - -LookupScopePrivate::LookupScopePrivate(LookupScope *q, CreateBindings *factory, LookupScope *parent) - : q(q) - , _factory(factory) - , _parent(parent ? parent->d : 0) +ClassOrNamespace::ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent) + : _factory(factory) + , _parent(parent) , _scopeLookupCache(0) + , _templateId(0) , _instantiationOrigin(0) , _rootClass(0) , _name(0) - , _hasTypedefs(false) { Q_ASSERT(factory); } -LookupScopePrivate::~LookupScopePrivate() +ClassOrNamespace::~ClassOrNamespace() { delete _scopeLookupCache; } -LookupScopePrivate *LookupScopePrivate::allocateChild(const Name *name) +const TemplateNameId *ClassOrNamespace::templateId() const { - LookupScope *e = _factory->allocLookupScope(q, name); - return e->d; + return _templateId; } -} // namespace Internal - -LookupScope::LookupScope(CreateBindings *factory, LookupScope *parent) - : d(new Internal::LookupScopePrivate(this, factory, parent)) +ClassOrNamespace *ClassOrNamespace::instantiationOrigin() const { + return _instantiationOrigin; } -LookupScope::~LookupScope() +ClassOrNamespace *ClassOrNamespace::parent() const { - delete d; + return _parent; } -LookupScope *LookupScope::instantiationOrigin() const +QList<ClassOrNamespace *> ClassOrNamespace::usings() const { - if (Internal::LookupScopePrivate *i = d->_instantiationOrigin) - return i->q; - return 0; + const_cast<ClassOrNamespace *>(this)->flush(); + return _usings; } -LookupScope *LookupScope::parent() const +QList<Enum *> ClassOrNamespace::unscopedEnums() const { - if (Internal::LookupScopePrivate *p = d->_parent) - return p->q; - return 0; + const_cast<ClassOrNamespace *>(this)->flush(); + return _enums; } -QList<LookupScope *> LookupScope::usings() const +QList<Symbol *> ClassOrNamespace::symbols() const { - const_cast<LookupScope *>(this)->d->flush(); - return d->_usings; + const_cast<ClassOrNamespace *>(this)->flush(); + return _symbols; } -QList<Enum *> LookupScope::unscopedEnums() const +ClassOrNamespace *ClassOrNamespace::globalNamespace() const { - const_cast<LookupScope *>(this)->d->flush(); - return d->_enums; -} - -QList<Symbol *> LookupScope::symbols() const -{ - const_cast<LookupScope *>(this)->d->flush(); - return d->_symbols; -} - -QList<LookupItem> LookupScope::find(const Name *name) -{ - return d->lookup_helper(name, false); -} - -QList<LookupItem> LookupScope::lookup(const Name *name) -{ - return d->lookup_helper(name, true); -} - -namespace Internal { - -LookupScope *LookupScopePrivate::globalNamespace() const -{ - const LookupScopePrivate *e = this; + ClassOrNamespace *e = const_cast<ClassOrNamespace *>(this); do { if (! e->_parent) @@ -713,20 +599,30 @@ LookupScope *LookupScopePrivate::globalNamespace() const e = e->_parent; } while (e); - return e ? e->q : 0; + return e; } -QList<LookupItem> LookupScopePrivate::lookup_helper(const Name *name, bool searchInEnclosingScope) +QList<LookupItem> ClassOrNamespace::find(const Name *name) +{ + return lookup_helper(name, false); +} + +QList<LookupItem> ClassOrNamespace::lookup(const Name *name) +{ + return lookup_helper(name, true); +} + +QList<LookupItem> ClassOrNamespace::lookup_helper(const Name *name, bool searchInEnclosingScope) { QList<LookupItem> result; if (name) { - if (const QualifiedNameId *qName = name->asQualifiedNameId()) { - if (! qName->base()) { // e.g. ::std::string - result = globalNamespace()->find(qName->name()); - } else if (LookupScope *binding = q->lookupType(qName->base())) { - result = binding->find(qName->name()); + if (const QualifiedNameId *q = name->asQualifiedNameId()) { + if (! q->base()) { // e.g. ::std::string + result = globalNamespace()->find(q->name()); + } else if (ClassOrNamespace *binding = lookupType(q->base())) { + result = binding->find(q->name()); QList<const Name *> fullName; addNames(name, &fullName); @@ -735,10 +631,10 @@ QList<LookupItem> LookupScopePrivate::lookup_helper(const Name *name, bool searc // a qualified name. For instance, a nested class which is forward declared // in the class but defined outside it - we should capture both. Symbol *match = 0; - ProcessedSet processed; - for (LookupScopePrivate *parentBinding = binding->d->_parent; + QSet<ClassOrNamespace *> processed; + for (ClassOrNamespace *parentBinding = binding->parent(); parentBinding && !match; - parentBinding = parentBinding->_parent) { + parentBinding = parentBinding->parent()) { if (processed.contains(parentBinding)) break; processed.insert(parentBinding); @@ -756,14 +652,14 @@ QList<LookupItem> LookupScopePrivate::lookup_helper(const Name *name, bool searc return result; } - ProcessedSet processed; - ProcessedSet processedOwnParents; - LookupScopePrivate *binding = this; + QSet<ClassOrNamespace *> processed; + QSet<ClassOrNamespace *> processedOwnParents; + ClassOrNamespace *binding = this; do { if (processedOwnParents.contains(binding)) break; processedOwnParents.insert(binding); - lookup_helper(name, binding, &result, &processed); + lookup_helper(name, binding, &result, &processed, /*templateId = */ 0); binding = binding->_parent; } while (searchInEnclosingScope && binding); } @@ -771,60 +667,59 @@ QList<LookupItem> LookupScopePrivate::lookup_helper(const Name *name, bool searc return result; } -void LookupScopePrivate::lookup_helper( - const Name *name, LookupScopePrivate *binding, QList<LookupItem> *result, - ProcessedSet *processed) +void ClassOrNamespace::lookup_helper(const Name *name, ClassOrNamespace *binding, + QList<LookupItem> *result, + QSet<ClassOrNamespace *> *processed, + const TemplateNameId *templateId) { - if (!binding || processed->contains(binding)) - return; - processed->insert(binding); + if (binding && ! processed->contains(binding)) { + processed->insert(binding); - binding->flush(); - const Identifier *nameId = name->identifier(); + const Identifier *nameId = name->identifier(); - foreach (Symbol *s, binding->_symbols) { - if (s->isFriend()) - continue; - else if (s->isUsingNamespaceDirective()) - continue; + foreach (Symbol *s, binding->symbols()) { + if (s->isFriend()) + continue; + else if (s->isUsingNamespaceDirective()) + continue; - if (Scope *scope = s->asScope()) { - if (Class *klass = scope->asClass()) { - if (const Identifier *id = klass->identifier()) { - if (nameId && nameId->match(id)) { - LookupItem item; - item.setDeclaration(klass); - item.setBinding(binding->q); - result->append(item); + if (Scope *scope = s->asScope()) { + if (Class *klass = scope->asClass()) { + if (const Identifier *id = klass->identifier()) { + if (nameId && nameId->match(id)) { + LookupItem item; + item.setDeclaration(klass); + item.setBinding(binding); + result->append(item); + } } } + _factory->lookupInScope(name, scope, result, templateId, binding); } - _factory->lookupInScope(name, scope, result, binding->q); } - } - foreach (Enum *e, binding->_enums) - _factory->lookupInScope(name, e, result, binding->q); + foreach (Enum *e, binding->unscopedEnums()) + _factory->lookupInScope(name, e, result, templateId, binding); - foreach (LookupScope *u, binding->_usings) - lookup_helper(name, u->d, result, processed); + foreach (ClassOrNamespace *u, binding->usings()) + lookup_helper(name, u, result, processed, binding->_templateId); - Anonymouses::const_iterator cit = binding->_anonymouses.constBegin(); - Anonymouses::const_iterator citEnd = binding->_anonymouses.constEnd(); - for (; cit != citEnd; ++cit) { - const AnonymousNameId *anonymousNameId = cit.key(); - LookupScopePrivate *a = cit.value(); - if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId)) - lookup_helper(name, a, result, processed); + Anonymouses::const_iterator cit = binding->_anonymouses.constBegin(); + Anonymouses::const_iterator citEnd = binding->_anonymouses.constEnd(); + for (; cit != citEnd; ++cit) { + const AnonymousNameId *anonymousNameId = cit.key(); + ClassOrNamespace *a = cit.value(); + if (!binding->_declaredOrTypedefedAnonymouses.contains(anonymousNameId)) + lookup_helper(name, a, result, processed, binding->_templateId); + } } } -} - void CreateBindings::lookupInScope(const Name *name, Scope *scope, QList<LookupItem> *result, - LookupScope *binding) + const TemplateNameId *templateId, + ClassOrNamespace *binding) { if (! name) { return; @@ -858,7 +753,7 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, if (Q_UNLIKELY(debug)) { Overview oo; qDebug() << "Found" << id->chars() << "in" - << (binding ? oo(binding->d->_name) : QString::fromLatin1("<null>")); + << (binding ? oo(binding->_name) : QString::fromLatin1("<null>")); } LookupItem item; @@ -866,7 +761,7 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, item.setBinding(binding); if (s->asNamespaceAlias() && binding) { - LookupScope *targetNamespaceBinding = binding->lookupType(name); + ClassOrNamespace *targetNamespaceBinding = binding->lookupType(name); //there can be many namespace definitions if (targetNamespaceBinding && targetNamespaceBinding->symbols().size() > 0) { Symbol *resolvedSymbol = targetNamespaceBinding->symbols().first(); @@ -874,19 +769,19 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, } } + if (templateId && (s->isDeclaration() || s->isFunction())) { + FullySpecifiedType ty = DeprecatedGenTemplateInstance::instantiate(templateId, s, control()); + item.setType(ty); // override the type. + } + // instantiate function template - if (const TemplateNameId *instantiation = name->asTemplateNameId()) { - if (Template *specialization = s->asTemplate()) { - if (Symbol *decl = specialization->declaration()) { - if (decl->isFunction() || decl->isDeclaration()) { - Clone cloner(_control.data()); - Subst subst(_control.data()); - initializeSubst(cloner, subst, binding, specialization, instantiation); - Symbol *instantiatedFunctionTemplate = cloner.symbol(decl, &subst); - item.setType(instantiatedFunctionTemplate->type()); // override the type - } - } - } + if (name->isTemplateNameId() && s->isTemplate() && s->asTemplate()->declaration() + && s->asTemplate()->declaration()->isFunction()) { + const TemplateNameId *instantiation = name->asTemplateNameId(); + Template *specialization = s->asTemplate(); + Symbol *instantiatedFunctionTemplate = instantiateTemplateFunction(instantiation, + specialization); + item.setType(instantiatedFunctionTemplate->type()); // override the type. } result->append(item); @@ -894,50 +789,51 @@ void CreateBindings::lookupInScope(const Name *name, Scope *scope, } } -LookupScope *LookupScope::lookupType(const Name *name) +ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name) { if (! name) return 0; - ProcessedSet processed; - return d->lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, d); + QSet<ClassOrNamespace *> processed; + return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, this); } -LookupScope *LookupScope::lookupType(const Name *name, Block *block) +ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name, Block *block) { - d->flush(); + flush(); - QHash<Block *, LookupScope *>::const_iterator citBlock = d->_blocks.constFind(block); - if (citBlock != d->_blocks.constEnd()) { - LookupScope *nestedBlock = citBlock.value(); - ProcessedSet processed; - if (LookupScope *foundInNestedBlock - = nestedBlock->d->lookupType_helper(name, - &processed, - /*searchInEnclosingScope = */ true, - nestedBlock->d)) { + QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.constFind(block); + if (citBlock != _blocks.constEnd()) { + ClassOrNamespace *nestedBlock = citBlock.value(); + QSet<ClassOrNamespace *> processed; + if (ClassOrNamespace *foundInNestedBlock + = nestedBlock->lookupType_helper(name, + &processed, + /*searchInEnclosingScope = */ true, + this)) { return foundInNestedBlock; } } - for (citBlock = d->_blocks.constBegin(); citBlock != d->_blocks.constEnd(); ++citBlock) { - if (LookupScope *foundNestedBlock = citBlock.value()->lookupType(name, block)) + for (citBlock = _blocks.constBegin(); citBlock != _blocks.constEnd(); ++citBlock) { + if (ClassOrNamespace *foundNestedBlock = citBlock.value()->lookupType(name, block)) return foundNestedBlock; } return 0; } -LookupScope *LookupScope::findType(const Name *name) +ClassOrNamespace *ClassOrNamespace::findType(const Name *name) { - ProcessedSet processed; - return d->lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, d); + QSet<ClassOrNamespace *> processed; + return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false, this); } -LookupScope *Internal::LookupScopePrivate::findBlock_helper( - Block *block, ProcessedSet *processed, bool searchInEnclosingScope) +ClassOrNamespace *ClassOrNamespace::findBlock_helper(Block *block, + QSet<ClassOrNamespace *> *processed, + bool searchInEnclosingScope) { - for (LookupScopePrivate *binding = this; binding; binding = binding->_parent) { + for (ClassOrNamespace *binding = this; binding; binding = binding->_parent) { if (processed->contains(binding)) break; processed->insert(binding); @@ -948,8 +844,8 @@ LookupScope *Internal::LookupScopePrivate::findBlock_helper( return citBlock.value(); for (citBlock = binding->_blocks.begin(); citBlock != end; ++citBlock) { - if (LookupScope *foundNestedBlock = - citBlock.value()->d->findBlock_helper(block, processed, false)) { + if (ClassOrNamespace *foundNestedBlock = + citBlock.value()->findBlock_helper(block, processed, false)) { return foundNestedBlock; } } @@ -959,20 +855,19 @@ LookupScope *Internal::LookupScopePrivate::findBlock_helper( return 0; } -LookupScope *LookupScope::findBlock(Block *block) +ClassOrNamespace *ClassOrNamespace::findBlock(Block *block) { - ProcessedSet processed; - return d->findBlock_helper(block, &processed, true); + QSet<ClassOrNamespace *> processed; + return findBlock_helper(block, &processed, true); } -Symbol *Internal::LookupScopePrivate::lookupInScope(const QList<const Name *> &fullName) +Symbol *ClassOrNamespace::lookupInScope(const QList<const Name *> &fullName) { if (!_scopeLookupCache) { _scopeLookupCache = new QHash<Internal::FullyQualifiedName, Symbol *>; - flush(); - for (int j = 0; j < _symbols.size(); ++j) { - if (Scope *scope = _symbols.at(j)->asScope()) { + for (int j = 0; j < symbols().size(); ++j) { + if (Scope *scope = symbols().at(j)->asScope()) { for (unsigned i = 0; i < scope->memberCount(); ++i) { Symbol *s = scope->memberAt(i); _scopeLookupCache->insert(LookupContext::fullyQualifiedName(s), s); @@ -984,30 +879,24 @@ Symbol *Internal::LookupScopePrivate::lookupInScope(const QList<const Name *> &f return _scopeLookupCache->value(fullName, 0); } -Class *LookupScope::rootClass() const -{ - return d->_rootClass; -} - -namespace Internal { - -LookupScope *LookupScopePrivate::lookupType_helper( - const Name *name, ProcessedSet *processed, - bool searchInEnclosingScope, LookupScopePrivate *origin) +ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name, + QSet<ClassOrNamespace *> *processed, + bool searchInEnclosingScope, + ClassOrNamespace *origin) { if (Q_UNLIKELY(debug)) { Overview oo; qDebug() << "Looking up" << oo(name) << "in" << oo(_name); } - if (const QualifiedNameId *qName = name->asQualifiedNameId()) { + if (const QualifiedNameId *q = name->asQualifiedNameId()) { - ProcessedSet innerProcessed; - if (! qName->base()) - return globalNamespace()->d->lookupType_helper(qName->name(), &innerProcessed, true, origin); + QSet<ClassOrNamespace *> innerProcessed; + if (! q->base()) + return globalNamespace()->lookupType_helper(q->name(), &innerProcessed, true, origin); - if (LookupScope *binding = lookupType_helper(qName->base(), processed, true, origin)) - return binding->d->lookupType_helper(qName->name(), &innerProcessed, false, origin); + if (ClassOrNamespace *binding = lookupType_helper(q->base(), processed, true, origin)) + return binding->lookupType_helper(q->name(), &innerProcessed, false, origin); return 0; @@ -1017,32 +906,41 @@ LookupScope *LookupScopePrivate::lookupType_helper( if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) { flush(); - foreach (Symbol *s, _symbols) { + foreach (Symbol *s, symbols()) { if (Class *klass = s->asClass()) { if (klass->identifier() && klass->identifier()->match(name->identifier())) - return q; + return this; } } - foreach (Enum *e, _enums) { + foreach (Enum *e, unscopedEnums()) { if (e->identifier() && e->identifier()->match(name->identifier())) - return q; + return this; } - if (LookupScopePrivate *e = nestedType(name, origin)) - return e->q; + if (ClassOrNamespace *e = nestedType(name, origin)) + return e; - foreach (LookupScope *u, _usings) { - if (LookupScope *r = u->d->lookupType_helper( - name, processed, /*searchInEnclosingScope =*/ false, origin)) { - return r; + if (_templateId) { + if (_usings.size() == 1) { + ClassOrNamespace *delegate = _usings.first(); + + if (ClassOrNamespace *r = delegate->lookupType_helper(name, + processed, + /*searchInEnclosingScope = */ true, + origin)) + return r; + } else if (Q_UNLIKELY(debug)) { + qWarning() << "expected one using declaration. Number of using declarations is:" + << _usings.size(); } } - if (_instantiationOrigin) { - if (LookupScope *o = _instantiationOrigin->lookupType_helper( - name, processed, /*searchInEnclosingScope =*/ true, origin)) { - return o; - } + foreach (ClassOrNamespace *u, usings()) { + if (ClassOrNamespace *r = u->lookupType_helper(name, + processed, + /*searchInEnclosingScope =*/ false, + origin)) + return r; } } @@ -1053,10 +951,10 @@ LookupScope *LookupScopePrivate::lookupType_helper( return 0; } -static LookupScopePrivate *findSpecializationWithMatchingTemplateArgument( - const Name *argumentName, LookupScopePrivate *reference) +static ClassOrNamespace *findSpecializationWithMatchingTemplateArgument(const Name *argumentName, + ClassOrNamespace *reference) { - foreach (Symbol *s, reference->_symbols) { + foreach (Symbol *s, reference->symbols()) { if (Class *clazz = s->asClass()) { if (Template *templateSpecialization = clazz->enclosingTemplate()) { const unsigned argumentCountOfSpecialization @@ -1076,127 +974,95 @@ static LookupScopePrivate *findSpecializationWithMatchingTemplateArgument( return 0; } -LookupScopePrivate *LookupScopePrivate::findSpecialization( - const TemplateNameId *templId, - const TemplateNameIdTable &specializations, - LookupScopePrivate *origin) +ClassOrNamespace *ClassOrNamespace::findSpecialization(const TemplateNameId *templId, + const TemplateNameIdTable &specializations) { + // we go through all specialization and try to find that one with template argument as pointer for (TemplateNameIdTable::const_iterator cit = specializations.begin(); cit != specializations.end(); ++cit) { const TemplateNameId *specializationNameId = cit->first; const unsigned specializationTemplateArgumentCount = specializationNameId->templateArgumentCount(); - const unsigned initializationTemplateArgumentCount = templId->templateArgumentCount(); + const unsigned initializationTemplateArgumentCount + = templId->templateArgumentCount(); // for now it works only when we have the same number of arguments in specialization // and initialization(in future it should be more clever) - if (specializationTemplateArgumentCount != initializationTemplateArgumentCount) - continue; - for (unsigned i = 0; i < initializationTemplateArgumentCount; ++i) { - const FullySpecifiedType &specializationTemplateArgument - = specializationNameId->templateArgumentAt(i); - FullySpecifiedType initializationTemplateArgument = templId->templateArgumentAt(i); - TypeResolver typeResolver(*_factory); - Scope *scope = 0; - typeResolver.resolve(&initializationTemplateArgument, &scope, origin ? origin->q : 0); - PointerType *specPointer = specializationTemplateArgument.type()->asPointerType(); - // specialization and initialization argument have to be a pointer - // additionally type of pointer argument of specialization has to be namedType - if (specPointer && initializationTemplateArgument.type()->isPointerType() - && specPointer->elementType().type()->isNamedType()) { - return cit->second; - } + if (specializationTemplateArgumentCount == initializationTemplateArgumentCount) { + for (unsigned i = 0; i < initializationTemplateArgumentCount; ++i) { + const FullySpecifiedType &specializationTemplateArgument + = specializationNameId->templateArgumentAt(i); + const FullySpecifiedType &initializationTemplateArgument + = templId->templateArgumentAt(i); + PointerType *specPointer + = specializationTemplateArgument.type()->asPointerType(); + // specialization and initialization argument have to be a pointer + // additionally type of pointer argument of specialization has to be namedType + if (specPointer && initializationTemplateArgument.type()->isPointerType() + && specPointer->elementType().type()->isNamedType()) { + return cit->second; + } - ArrayType *specArray = specializationTemplateArgument.type()->asArrayType(); - if (specArray && initializationTemplateArgument.type()->isArrayType()) { - if (const NamedType *argumentNamedType - = specArray->elementType().type()->asNamedType()) { - if (const Name *argumentName = argumentNamedType->name()) { - if (LookupScopePrivate *reference - = findSpecializationWithMatchingTemplateArgument( - argumentName, cit->second)) { - return reference; + ArrayType *specArray + = specializationTemplateArgument.type()->asArrayType(); + if (specArray && initializationTemplateArgument.type()->isArrayType()) { + if (const NamedType *argumentNamedType + = specArray->elementType().type()->asNamedType()) { + if (const Name *argumentName = argumentNamedType->name()) { + if (ClassOrNamespace *reference + = findSpecializationWithMatchingTemplateArgument( + argumentName, cit->second)) { + return reference; + } } } } } - - if (const NamedType *specName = specializationTemplateArgument->asNamedType()) { - if (const NamedType *initName = initializationTemplateArgument->asNamedType()) { - if (specName->name()->identifier() == initName->name()->identifier()) - return cit->second; - } - } } } return 0; } -LookupScopePrivate *LookupScopePrivate::findOrCreateNestedAnonymousType( +ClassOrNamespace *ClassOrNamespace::findOrCreateNestedAnonymousType( const AnonymousNameId *anonymousNameId) { - auto cit = _anonymouses.constFind(anonymousNameId); + QHash<const AnonymousNameId *, ClassOrNamespace *>::const_iterator cit + = _anonymouses.constFind(anonymousNameId); if (cit != _anonymouses.constEnd()) { return cit.value(); } else { - LookupScopePrivate *newAnonymous = allocateChild(anonymousNameId); + ClassOrNamespace *newAnonymous = _factory->allocClassOrNamespace(this); + if (Q_UNLIKELY(debug)) + newAnonymous->_name = anonymousNameId; _anonymouses[anonymousNameId] = newAnonymous; return newAnonymous; } } -LookupScopePrivate *LookupScopePrivate::findNestedType(const Name *name, LookupScopePrivate *origin) -{ - TypedefTable::const_iterator typedefit = _typedefs.find(name); - if (typedefit != _typedefs.end()) { - Declaration *decl = typedefit->second; - if (_alreadyConsideredTypedefs.contains(decl)) - return 0; - LookupScopePrivate *binding = 0; - _alreadyConsideredTypedefs.insert(decl); - if (const NamedType *namedTy = decl->type()->asNamedType()) { - if (LookupScope *e = q->lookupType(namedTy->name())) { - binding = e->d; - } else if (origin) { - if (LookupScope *e = origin->q->lookupType(namedTy->name())) - binding = e->d; - } - } - _alreadyConsideredTypedefs.remove(decl); - if (binding) - return binding; - } - - auto it = _nestedScopes.find(name); - if (it != _nestedScopes.end()) - return it->second; - - return 0; -} - -LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScopePrivate *origin) +ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin) { Q_ASSERT(name != 0); Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()); - const_cast<LookupScopePrivate *>(this)->flush(); + const_cast<ClassOrNamespace *>(this)->flush(); if (const AnonymousNameId *anonymousNameId = name->asAnonymousNameId()) return findOrCreateNestedAnonymousType(anonymousNameId); - LookupScopePrivate *reference = findNestedType(name, origin); - if (!reference) + Table::const_iterator it = _classOrNamespaces.find(name); + if (it == _classOrNamespaces.end()) return 0; - reference->flush(); - LookupScopePrivate *baseTemplateClassReference = reference; + + ClassOrNamespace *reference = it->second; + ClassOrNamespace *baseTemplateClassReference = reference; const TemplateNameId *templId = name->asTemplateNameId(); if (templId) { - // for "using" we should use the real one LookupScope(it should be the first + // for "using" we should use the real one ClassOrNamespace(it should be the first // one item from usings list) // we indicate that it is a 'using' by checking number of symbols(it should be 0) - if (reference->_symbols.count() == 0 && reference->_usings.count() != 0) - reference = reference->_usings[0]->d; + if (reference->symbols().count() == 0 && reference->usings().count() != 0) + reference = reference->_usings[0]; // if it is a TemplateNameId it could be a specialization(full or partial) or // instantiation of one of the specialization(reference->_specialization) or @@ -1209,12 +1075,15 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope if (cit != reference->_specializations.end()) { return cit->second; } else { - LookupScopePrivate *newSpecialization = reference->allocateChild(templId); + ClassOrNamespace *newSpecialization = _factory->allocClassOrNamespace(reference); + if (Q_UNLIKELY(debug)) + newSpecialization->_name = templId; reference->_specializations[templId] = newSpecialization; return newSpecialization; } } else { - auto citInstantiation = reference->_instantiations.constFind(templId); + QMap<const TemplateNameId *, ClassOrNamespace *>::const_iterator citInstantiation + = reference->_instantiations.constFind(templId); if (citInstantiation != reference->_instantiations.constEnd()) return citInstantiation.value(); TemplateNameId *nonConstTemplId = const_cast<TemplateNameId *>(templId); @@ -1227,14 +1096,11 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope // we found full specialization reference = cit->second; } else { - if (LookupScopePrivate *specialization = - findSpecialization(templId, specializations, origin)) { - reference = specialization; - if (Q_UNLIKELY(debug)) { - Overview oo; - qDebug() << "picked specialization" << oo(specialization->_name); - } - } + ClassOrNamespace *specializationWithPointer + = findSpecialization(templId, specializations); + if (specializationWithPointer) + reference = specializationWithPointer; + // TODO: find the best specialization(probably partial) for this instantiation } // let's instantiation be instantiation nonConstTemplId->setIsSpecialization(false); @@ -1247,7 +1113,7 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope Class *referenceClass = 0; QList<const Name *> allBases; - foreach (Symbol *s, reference->_symbols) { + foreach (Symbol *s, reference->symbols()) { if (Class *clazz = s->asClass()) { for (unsigned i = 0; i < clazz->baseClassCount(); ++i) { BaseClass *baseClass = clazz->baseClassAt(i); @@ -1271,106 +1137,163 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope if (!name->isTemplateNameId()) _alreadyConsideredClasses.insert(referenceClass); - QSet<LookupScope *> knownUsings = reference->_usings.toSet(); + QSet<ClassOrNamespace *> knownUsings = reference->usings().toSet(); // If we are dealling with a template type, more work is required, since we need to // construct all instantiation data. if (templId) { - if (!_factory->expandTemplates()) - return reference; - Template *templateSpecialization = referenceClass->enclosingTemplate(); - if (!templateSpecialization) - return reference; - - // It gets a bit complicated if the reference is actually a class template because we - // now must worry about dependent names in base classes. _alreadyConsideredTemplates.insert(templId); - const unsigned argumentCountOfInitialization = templId->templateArgumentCount(); - const unsigned argumentCountOfSpecialization - = templateSpecialization->templateParameterCount(); + ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(baseTemplateClassReference); + if (Q_UNLIKELY(debug)) + instantiation->_name = templId; + instantiation->_templateId = templId; - Clone cloner(_control.data()); - Subst subst(_control.data()); - _factory->initializeSubst(cloner, subst, origin ? origin->q : 0, - templateSpecialization, templId); - - LookupScopePrivate *instantiation = baseTemplateClassReference->allocateChild(templId); + while (!origin->_symbols.isEmpty() && origin->_symbols[0]->isBlock()) + origin = origin->parent(); instantiation->_instantiationOrigin = origin; - instantiation->_rootClass = reference->_rootClass; - Instantiator instantiator(cloner, subst); - instantiator.doInstantiate(reference, instantiation); - - QHash<const Name*, unsigned> templParams; - for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) - templParams.insert(templateSpecialization->templateParameterAt(i)->name(), i); - - foreach (const Name *baseName, allBases) { - LookupScope *baseBinding = 0; - - if (const Identifier *nameId = baseName->asNameId()) { - // This is the simple case in which a template parameter is itself a base. - // Ex.: template <class T> class A : public T {}; - if (templParams.contains(nameId)) { - const unsigned parameterIndex = templParams.value(nameId); - if (parameterIndex < argumentCountOfInitialization) { - const FullySpecifiedType &fullType = - templId->templateArgumentAt(parameterIndex); - if (fullType.isValid()) { - if (NamedType *namedType = fullType.type()->asNamedType()) - baseBinding = q->lookupType(namedType->name()); - } - } - } - if (!baseBinding && subst.contains(baseName)) { - const FullySpecifiedType &fullType = subst[baseName]; - if (fullType.isValid()) { - if (NamedType *namedType = fullType.type()->asNamedType()) - baseBinding = q->lookupType(namedType->name()); - } - } - } else { - SubstitutionMap map; + // The instantiation should have all symbols, enums, and usings from the reference. + instantiation->_enums.append(reference->unscopedEnums()); + instantiation->_usings.append(reference->usings()); + + instantiation->_rootClass = reference->rootClass(); + + // It gets a bit complicated if the reference is actually a class template because we + // now must worry about dependent names in base classes. + if (Template *templateSpecialization = referenceClass->enclosingTemplate()) { + const unsigned argumentCountOfInitialization = templId->templateArgumentCount(); + const unsigned argumentCountOfSpecialization + = templateSpecialization->templateParameterCount(); + + Subst subst(_control.data()); + if (_factory->expandTemplates()) { + const TemplateNameId *templSpecId + = templateSpecialization->name()->asTemplateNameId(); + const unsigned templSpecArgumentCount = templSpecId ? + templSpecId->templateArgumentCount() : 0; + Clone cloner(_control.data()); for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) { - const Name *name = templateSpecialization->templateParameterAt(i)->name(); + const TypenameArgument *tParam + = templateSpecialization->templateParameterAt(i)->asTypenameArgument(); + if (!tParam) + continue; + const Name *name = tParam->name(); + if (!name) + continue; + FullySpecifiedType ty = (i < argumentCountOfInitialization) ? templId->templateArgumentAt(i): - templateSpecialization->templateParameterAt(i)->type(); + cloner.type(tParam->type(), &subst); + + if (i < templSpecArgumentCount + && templSpecId->templateArgumentAt(i)->isPointerType()) { + if (PointerType *pointerType = ty->asPointerType()) + ty = pointerType->elementType(); + } - map.bind(name, ty); + subst.bind(cloner.name(name, &subst), ty); } - SubstitutionEnvironment env; - env.enter(&map); - baseName = rewriteName(baseName, &env, _control.data()); + foreach (Symbol *s, reference->symbols()) { + Symbol *clone = cloner.symbol(s, &subst); + clone->setEnclosingScope(s->enclosingScope()); + instantiation->_symbols.append(clone); + if (Q_UNLIKELY(debug)) { + Overview oo; + oo.showFunctionSignatures = true; + oo.showReturnTypes = true; + oo.showTemplateParameters = true; + qDebug() << "cloned" << oo(clone->type()); + if (Class *klass = clone->asClass()) { + const unsigned klassMemberCount = klass->memberCount(); + for (unsigned i = 0; i < klassMemberCount; ++i){ + Symbol *klassMemberAsSymbol = klass->memberAt(i); + if (klassMemberAsSymbol->isTypedef()) { + if (Declaration *declaration = klassMemberAsSymbol->asDeclaration()) + qDebug() << "Member: " << oo(declaration->type(), declaration->name()); + } + } + } + } + } + instantiateNestedClasses(reference, cloner, subst, instantiation); + } else { + instantiation->_symbols.append(reference->symbols()); + } - if (const TemplateNameId *baseTemplId = baseName->asTemplateNameId()) { - // Another template that uses the dependent name. - // Ex.: template <class T> class A : public B<T> {}; - if (baseTemplId->identifier() != templId->identifier()) { - if (LookupScopePrivate *nested = nestedType(baseName, origin)) - baseBinding = nested->q; + QHash<const Name*, unsigned> templParams; + for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) + templParams.insert(templateSpecialization->templateParameterAt(i)->name(), i); + + foreach (const Name *baseName, allBases) { + ClassOrNamespace *baseBinding = 0; + + if (const Identifier *nameId = baseName->asNameId()) { + // This is the simple case in which a template parameter is itself a base. + // Ex.: template <class T> class A : public T {}; + if (templParams.contains(nameId)) { + const unsigned parameterIndex = templParams.value(nameId); + if (parameterIndex < argumentCountOfInitialization) { + const FullySpecifiedType &fullType = + templId->templateArgumentAt(parameterIndex); + if (fullType.isValid()) { + if (NamedType *namedType = fullType.type()->asNamedType()) + baseBinding = lookupType(namedType->name()); + } + } } - } else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { - // Qualified names in general. - // Ex.: template <class T> class A : public B<T>::Type {}; - LookupScope *binding = q; - if (const Name *qualification = qBaseName->base()) { - const TemplateNameId *baseTemplName = qualification->asTemplateNameId(); - if (!baseTemplName || !compareName(baseTemplName, templateSpecialization->name())) - binding = q->lookupType(qualification); + if (!baseBinding && subst.contains(baseName)) { + const FullySpecifiedType &fullType = subst[baseName]; + if (fullType.isValid()) { + if (NamedType *namedType = fullType.type()->asNamedType()) + baseBinding = lookupType(namedType->name()); + } } - baseName = qBaseName->name(); + } else { + SubstitutionMap map; + for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) { + const Name *name = templateSpecialization->templateParameterAt(i)->name(); + FullySpecifiedType ty = (i < argumentCountOfInitialization) ? + templId->templateArgumentAt(i): + templateSpecialization->templateParameterAt(i)->type(); + + map.bind(name, ty); + } + SubstitutionEnvironment env; + env.enter(&map); + + baseName = rewriteName(baseName, &env, _control.data()); + + if (const TemplateNameId *baseTemplId = baseName->asTemplateNameId()) { + // Another template that uses the dependent name. + // Ex.: template <class T> class A : public B<T> {}; + if (baseTemplId->identifier() != templId->identifier()) + baseBinding = nestedType(baseName, origin); + } else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { + // Qualified names in general. + // Ex.: template <class T> class A : public B<T>::Type {}; + ClassOrNamespace *binding = this; + if (const Name *qualification = qBaseName->base()) { + const TemplateNameId *baseTemplName = qualification->asTemplateNameId(); + if (!baseTemplName || !compareName(baseTemplName, templateSpecialization->name())) + binding = lookupType(qualification); + } + baseName = qBaseName->name(); - if (binding) - baseBinding = binding->lookupType(baseName); + if (binding) + baseBinding = binding->lookupType(baseName); + } } - } - if (baseBinding && !knownUsings.contains(baseBinding)) - instantiation->addUsing(baseBinding); + if (baseBinding && !knownUsings.contains(baseBinding)) + instantiation->addUsing(baseBinding); + } + } else { + instantiation->_classOrNamespaces = reference->_classOrNamespaces; + instantiation->_symbols.append(reference->symbols()); } + _alreadyConsideredTemplates.clear(templId); baseTemplateClassReference->_instantiations[templId] = instantiation; return instantiation; @@ -1382,14 +1305,14 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope // Find the missing bases for regular (non-template) types. // Ex.: class A : public B<Some>::Type {}; foreach (const Name *baseName, allBases) { - LookupScope *binding = q; + ClassOrNamespace *binding = this; if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { if (const Name *qualification = qBaseName->base()) - binding = q->lookupType(qualification); + binding = lookupType(qualification); else if (binding->parent() != 0) //if this is global identifier we take global namespace //Ex: class A{}; namespace NS { class A: public ::A{}; } - binding = binding->d->globalNamespace(); + binding = binding->globalNamespace(); else //if we are in the global scope continue; @@ -1397,7 +1320,7 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope } if (binding) { - LookupScope * baseBinding = binding->lookupType(baseName); + ClassOrNamespace * baseBinding = binding->lookupType(baseName); if (baseBinding && !knownUsings.contains(baseBinding)) reference->addUsing(baseBinding); } @@ -1407,152 +1330,176 @@ LookupScopePrivate *LookupScopePrivate::nestedType(const Name *name, LookupScope return reference; } -LookupScopePrivate *Instantiator::instantiate(LookupScopePrivate *lookupScope, - LookupScopePrivate *origin) + +void ClassOrNamespace::instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass, + Clone &cloner, + Subst &subst, + ClassOrNamespace *enclosingTemplateClassInstantiation) { - lookupScope->flush(); - LookupScopePrivate *instantiation = lookupScope->allocateChild(lookupScope->_name); - instantiation->_instantiationOrigin = origin; - doInstantiate(lookupScope, instantiation); - return instantiation; + NestedClassInstantiator nestedClassInstantiator(_factory, cloner, subst); + nestedClassInstantiator.instantiate(enclosingTemplateClass, enclosingTemplateClassInstantiation); } -void Instantiator::doInstantiate(LookupScopePrivate *lookupScope, LookupScopePrivate *instantiation) +void ClassOrNamespace::NestedClassInstantiator::instantiate(ClassOrNamespace *enclosingTemplateClass, + ClassOrNamespace *enclosingTemplateClassInstantiation) { - if (_alreadyConsideredInstantiations.contains(lookupScope)) + if (_alreadyConsideredNestedClassInstantiations.contains(enclosingTemplateClass)) return; - _alreadyConsideredInstantiations.insert(lookupScope); - // The instantiation should have all symbols, enums, and usings from the reference. - if (instantiation != lookupScope) { - instantiation->_enums = lookupScope->_enums; - auto typedefend = lookupScope->_typedefs.end(); - for (auto typedefit = lookupScope->_typedefs.begin(); - typedefit != typedefend; - ++typedefit) { - instantiation->_typedefs[typedefit->first] = - _cloner.symbol(typedefit->second, &_subst)->asDeclaration(); - } - foreach (LookupScope *usingLookupScope, lookupScope->_usings) - instantiation->_usings.append(instantiate(usingLookupScope->d, instantiation)->q); - foreach (Symbol *s, lookupScope->_symbols) { - Symbol *clone = _cloner.symbol(s, &_subst); - if (!clone->enclosingScope()) // Not from the cache but just cloned. - clone->setEnclosingScope(s->enclosingScope()); - instantiation->_symbols.append(clone); - if (s == instantiation->_rootClass) { - clone->setName(instantiation->_name); - instantiation->_rootClass = clone->asClass(); + _alreadyConsideredNestedClassInstantiations.insert(enclosingTemplateClass); + ClassOrNamespace::Table::const_iterator cit = enclosingTemplateClass->_classOrNamespaces.begin(); + for (; cit != enclosingTemplateClass->_classOrNamespaces.end(); ++cit) { + const Name *nestedName = cit->first; + ClassOrNamespace *nestedClassOrNamespace = cit->second; + ClassOrNamespace *nestedClassOrNamespaceInstantiation = nestedClassOrNamespace; + + if (isInstantiateNestedClassNeeded(nestedClassOrNamespace->_symbols)) { + nestedClassOrNamespaceInstantiation = _factory->allocClassOrNamespace(nestedClassOrNamespace); + nestedClassOrNamespaceInstantiation->_enums.append(nestedClassOrNamespace->unscopedEnums()); + nestedClassOrNamespaceInstantiation->_usings.append(nestedClassOrNamespace->usings()); + nestedClassOrNamespaceInstantiation->_instantiationOrigin = nestedClassOrNamespace; + + foreach (Symbol *s, nestedClassOrNamespace->_symbols) { + Symbol *clone = _cloner.symbol(s, &_subst); + if (!clone->enclosingScope()) // Not from the cache but just cloned. + clone->setEnclosingScope(s->enclosingScope()); + nestedClassOrNamespaceInstantiation->_symbols.append(clone); } - if (Q_UNLIKELY(debug)) { - Overview oo; - oo.showFunctionSignatures = true; - oo.showReturnTypes = true; - oo.showTemplateParameters = true; - qDebug() << "cloned" << oo(clone->type()); - if (Class *klass = clone->asClass()) { - const unsigned klassMemberCount = klass->memberCount(); - for (unsigned i = 0; i < klassMemberCount; ++i){ - Symbol *klassMemberAsSymbol = klass->memberAt(i); - if (klassMemberAsSymbol->isTypedef()) { - if (Declaration *declaration = klassMemberAsSymbol->asDeclaration()) - qDebug() << "Member: " << oo(declaration->type(), declaration->name()); - } - } + } + + if (isNestedInstantiationEnclosingTemplate(nestedClassOrNamespaceInstantiation, + enclosingTemplateClass)) { + nestedClassOrNamespaceInstantiation->_parent = enclosingTemplateClassInstantiation; + } + instantiate(nestedClassOrNamespace, nestedClassOrNamespaceInstantiation); + + enclosingTemplateClassInstantiation->_classOrNamespaces[nestedName] = + nestedClassOrNamespaceInstantiation; + } + _alreadyConsideredNestedClassInstantiations.remove(enclosingTemplateClass); +} + +bool ClassOrNamespace::NestedClassInstantiator::isInstantiateNestedClassNeeded(const QList<Symbol *> &symbols) const +{ + foreach (Symbol *s, symbols) { + if (Class *klass = s->asClass()) { + int memberCount = klass->memberCount(); + for (int i = 0; i < memberCount; ++i) { + Symbol *memberAsSymbol = klass->memberAt(i); + if (Declaration *declaration = memberAsSymbol->asDeclaration()) { + if (containsTemplateType(declaration)) + return true; + } else if (Function *function = memberAsSymbol->asFunction()) { + if (containsTemplateType(function)) + return true; } } } } - auto cit = lookupScope->_nestedScopes.begin(); - for (; cit != lookupScope->_nestedScopes.end(); ++cit) { - const Name *nestedName = cit->first; - LookupScopePrivate *nestedLookupScope = cit->second; - LookupScopePrivate *nestedInstantiation = instantiate(nestedLookupScope, instantiation); - nestedInstantiation->_parent = instantiation; - instantiation->_nestedScopes[nestedName] = nestedInstantiation; - } - _alreadyConsideredInstantiations.remove(lookupScope); + + return false; +} + +bool ClassOrNamespace::NestedClassInstantiator::containsTemplateType(Declaration *declaration) const +{ + Type *memberType = declaration->type().type(); + NamedType *namedType = findNamedType(memberType); + return namedType && _subst.contains(namedType->name()); +} + +bool ClassOrNamespace::NestedClassInstantiator::containsTemplateType(Function *function) const +{ + Type *returnType = function->returnType().type(); + NamedType *namedType = findNamedType(returnType); + return namedType && _subst.contains(namedType->name()); + //TODO: in future we will need also check function arguments, for now returned value is enough } -void LookupScopePrivate::flush() +NamedType *ClassOrNamespace::NestedClassInstantiator::findNamedType(Type *memberType) const +{ + if (NamedType *namedType = memberType->asNamedType()) + return namedType; + else if (PointerType *pointerType = memberType->asPointerType()) + return findNamedType(pointerType->elementType().type()); + else if (ReferenceType *referenceType = memberType->asReferenceType()) + return findNamedType(referenceType->elementType().type()); + + return 0; +} + +void ClassOrNamespace::flush() { if (! _todo.isEmpty()) { const QList<Symbol *> todo = _todo; _todo.clear(); foreach (Symbol *member, todo) - _factory->process(member, q); + _factory->process(member, this); } } -void LookupScopePrivate::addSymbol(Symbol *symbol) +void ClassOrNamespace::addSymbol(Symbol *symbol) { _symbols.append(symbol); } -void LookupScopePrivate::addTodo(Symbol *symbol) +void ClassOrNamespace::addTodo(Symbol *symbol) { _todo.append(symbol); } -void LookupScopePrivate::addUnscopedEnum(Enum *e) +void ClassOrNamespace::addUnscopedEnum(Enum *e) { _enums.append(e); } -void LookupScopePrivate::addTypedef(const Name *identifier, Declaration *d) -{ - _typedefs[identifier] = d; -} - -void LookupScopePrivate::addUsing(LookupScope *u) +void ClassOrNamespace::addUsing(ClassOrNamespace *u) { _usings.append(u); } -void LookupScopePrivate::addNestedType(const Name *alias, LookupScope *e) +void ClassOrNamespace::addNestedType(const Name *alias, ClassOrNamespace *e) { - _nestedScopes[alias] = e->d; + _classOrNamespaces[alias] = e; } -LookupScope *LookupScopePrivate::findOrCreateType( - const Name *name, LookupScopePrivate *origin, Class *clazz) +ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNamespace *origin, + Class *clazz) { if (! name) - return q; + return this; if (! origin) origin = this; - if (const QualifiedNameId *qName = name->asQualifiedNameId()) { - if (! qName->base()) - return globalNamespace()->d->findOrCreateType(qName->name(), origin, clazz); + if (const QualifiedNameId *q = name->asQualifiedNameId()) { + if (! q->base()) + return globalNamespace()->findOrCreateType(q->name(), origin, clazz); - return findOrCreateType(qName->base(), origin)->d->findOrCreateType(qName->name(), origin, clazz); + return findOrCreateType(q->base(), origin)->findOrCreateType(q->name(), origin, clazz); } else if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) { - LookupScopePrivate *e = nestedType(name, origin); + ClassOrNamespace *e = nestedType(name, origin); if (! e) { - e = allocateChild(name); + e = _factory->allocClassOrNamespace(this); e->_rootClass = clazz; - _nestedScopes[name] = e; + if (Q_UNLIKELY(debug)) + e->_name = name; + _classOrNamespaces[name] = e; } - return e->q; + return e; } return 0; } -} // namespace Internal - CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot) : _snapshot(snapshot) , _control(QSharedPointer<Control>(new Control)) , _expandTemplates(false) - , _depth(0) { - _globalNamespace = allocLookupScope(/*parent = */ 0, /*name = */ 0); - _currentLookupScope = _globalNamespace; + _globalNamespace = allocClassOrNamespace(/*parent = */ 0); + _currentClassOrNamespace = _globalNamespace; process(thisDocument); } @@ -1562,36 +1509,36 @@ CreateBindings::~CreateBindings() qDeleteAll(_entities); } -LookupScope *CreateBindings::switchCurrentLookupScope(LookupScope *lookupScope) +ClassOrNamespace *CreateBindings::switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace) { - LookupScope *previous = _currentLookupScope; - _currentLookupScope = lookupScope; + ClassOrNamespace *previous = _currentClassOrNamespace; + _currentClassOrNamespace = classOrNamespace; return previous; } -LookupScope *CreateBindings::globalNamespace() const +ClassOrNamespace *CreateBindings::globalNamespace() const { return _globalNamespace; } -LookupScope *CreateBindings::lookupType(Symbol *symbol, LookupScope *enclosingBinding) +ClassOrNamespace *CreateBindings::lookupType(Symbol *symbol, ClassOrNamespace *enclosingBinding) { const QList<const Name *> path = LookupContext::path(symbol); return lookupType(path, enclosingBinding); } -LookupScope *CreateBindings::lookupType(const QList<const Name *> &path, - LookupScope *enclosingBinding) +ClassOrNamespace *CreateBindings::lookupType(const QList<const Name *> &path, + ClassOrNamespace *enclosingBinding) { if (path.isEmpty()) return _globalNamespace; if (enclosingBinding) { - if (LookupScope *b = enclosingBinding->lookupType(path.last())) + if (ClassOrNamespace *b = enclosingBinding->lookupType(path.last())) return b; } - LookupScope *b = _globalNamespace->lookupType(path.at(0)); + ClassOrNamespace *b = _globalNamespace->lookupType(path.at(0)); for (int i = 1; b && i < path.size(); ++i) b = b->findType(path.at(i)); @@ -1599,23 +1546,22 @@ LookupScope *CreateBindings::lookupType(const QList<const Name *> &path, return b; } -void CreateBindings::process(Symbol *s, LookupScope *lookupScope) +void CreateBindings::process(Symbol *s, ClassOrNamespace *classOrNamespace) { - LookupScope *previous = switchCurrentLookupScope(lookupScope); + ClassOrNamespace *previous = switchCurrentClassOrNamespace(classOrNamespace); accept(s); - (void) switchCurrentLookupScope(previous); + (void) switchCurrentClassOrNamespace(previous); } void CreateBindings::process(Symbol *symbol) { - _currentLookupScope->d->addTodo(symbol); + _currentClassOrNamespace->addTodo(symbol); } -LookupScope *CreateBindings::allocLookupScope(LookupScope *parent, const Name *name) +ClassOrNamespace *CreateBindings::allocClassOrNamespace(ClassOrNamespace *parent) { - LookupScope *e = new LookupScope(this, parent); - e->d->_control = control(); - e->d->_name = name; + ClassOrNamespace *e = new ClassOrNamespace(this, parent); + e->_control = control(); _entities.append(e); return e; } @@ -1639,22 +1585,22 @@ void CreateBindings::process(Document::Ptr doc) } } -LookupScope *CreateBindings::enterLookupScopeBinding(Symbol *symbol) +ClassOrNamespace *CreateBindings::enterClassOrNamespaceBinding(Symbol *symbol) { - LookupScope *entity = _currentLookupScope->d->findOrCreateType( - symbol->name(), 0, symbol->asClass()); - entity->d->addSymbol(symbol); + ClassOrNamespace *entity = _currentClassOrNamespace->findOrCreateType(symbol->name(), 0, + symbol->asClass()); + entity->addSymbol(symbol); - return switchCurrentLookupScope(entity); + return switchCurrentClassOrNamespace(entity); } -LookupScope *CreateBindings::enterGlobalLookupScope(Symbol *symbol) +ClassOrNamespace *CreateBindings::enterGlobalClassOrNamespace(Symbol *symbol) { - LookupScope *entity = _globalNamespace->d->findOrCreateType( - symbol->name(), 0, symbol->asClass()); - entity->d->addSymbol(symbol); + ClassOrNamespace *entity = _globalNamespace->findOrCreateType(symbol->name(), 0, + symbol->asClass()); + entity->addSymbol(symbol); - return switchCurrentLookupScope(entity); + return switchCurrentClassOrNamespace(entity); } bool CreateBindings::visit(Template *templ) @@ -1665,40 +1611,34 @@ bool CreateBindings::visit(Template *templ) return false; } -bool CreateBindings::visit(ExplicitInstantiation *inst) -{ - Q_UNUSED(inst); - return false; -} - bool CreateBindings::visit(Namespace *ns) { - LookupScope *previous = enterLookupScopeBinding(ns); + ClassOrNamespace *previous = enterClassOrNamespaceBinding(ns); for (unsigned i = 0; i < ns->memberCount(); ++i) process(ns->memberAt(i)); if (ns->isInline() && previous) - previous->d->addUsing(_currentLookupScope); + previous->addUsing(_currentClassOrNamespace); - _currentLookupScope = previous; + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(Class *klass) { - LookupScope *previous = _currentLookupScope; - LookupScope *binding = 0; + ClassOrNamespace *previous = _currentClassOrNamespace; + ClassOrNamespace *binding = 0; if (klass->name() && klass->name()->isQualifiedNameId()) - binding = _currentLookupScope->lookupType(klass->name()); + binding = _currentClassOrNamespace->lookupType(klass->name()); if (! binding) - binding = _currentLookupScope->d->findOrCreateType(klass->name(), 0, klass); + binding = _currentClassOrNamespace->findOrCreateType(klass->name(), 0, klass); - _currentLookupScope = binding; - _currentLookupScope->d->addSymbol(klass); + _currentClassOrNamespace = binding; + _currentClassOrNamespace->addSymbol(klass); for (unsigned i = 0; i < klass->baseClassCount(); ++i) process(klass->baseClassAt(i)); @@ -1706,15 +1646,15 @@ bool CreateBindings::visit(Class *klass) for (unsigned i = 0; i < klass->memberCount(); ++i) process(klass->memberAt(i)); - _currentLookupScope = previous; + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(ForwardClassDeclaration *klass) { if (! klass->isFriend()) { - LookupScope *previous = enterLookupScopeBinding(klass); - _currentLookupScope = previous; + ClassOrNamespace *previous = enterClassOrNamespaceBinding(klass); + _currentClassOrNamespace = previous; } return false; @@ -1723,10 +1663,10 @@ bool CreateBindings::visit(ForwardClassDeclaration *klass) bool CreateBindings::visit(Enum *e) { if (e->isScoped()) { - LookupScope *previous = enterLookupScopeBinding(e); - _currentLookupScope = previous; + ClassOrNamespace *previous = enterClassOrNamespaceBinding(e); + _currentClassOrNamespace = previous; } else { - _currentLookupScope->d->addUnscopedEnum(e); + _currentClassOrNamespace->addUnscopedEnum(e); } return false; } @@ -1734,18 +1674,22 @@ bool CreateBindings::visit(Enum *e) bool CreateBindings::visit(Declaration *decl) { if (decl->isTypedef()) { - _currentLookupScope->d->_hasTypedefs = true; FullySpecifiedType ty = decl->type(); const Identifier *typedefId = decl->identifier(); if (typedefId && ! (ty.isConst() || ty.isVolatile())) { - if (ty->isNamedType()) { - _currentLookupScope->d->addTypedef(typedefId, decl); + if (const NamedType *namedTy = ty->asNamedType()) { + if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(namedTy->name())) { + _currentClassOrNamespace->addNestedType(decl->name(), e); + } else if (false) { + Overview oo; + qDebug() << "found entity not found for" << oo.prettyName(namedTy->name()); + } } else if (Class *klass = ty->asClassType()) { if (const Identifier *nameId = decl->name()->asNameId()) { - LookupScope *binding - = _currentLookupScope->d->findOrCreateType(nameId, 0, klass); - binding->d->addSymbol(klass); + ClassOrNamespace *binding + = _currentClassOrNamespace->findOrCreateType(nameId, 0, klass); + binding->addSymbol(klass); } } } @@ -1753,7 +1697,7 @@ bool CreateBindings::visit(Declaration *decl) if (Class *clazz = decl->type()->asClassType()) { if (const Name *name = clazz->name()) { if (const AnonymousNameId *anonymousNameId = name->asAnonymousNameId()) - _currentLookupScope->d->_declaredOrTypedefedAnonymouses.insert(anonymousNameId); + _currentClassOrNamespace->_declaredOrTypedefedAnonymouses.insert(anonymousNameId); } } return false; @@ -1761,59 +1705,58 @@ bool CreateBindings::visit(Declaration *decl) bool CreateBindings::visit(Function *function) { - LookupScope *previous = _currentLookupScope; - LookupScope *binding = lookupType(function, previous); + ClassOrNamespace *previous = _currentClassOrNamespace; + ClassOrNamespace *binding = lookupType(function, previous); if (!binding) return false; - _currentLookupScope = binding; + _currentClassOrNamespace = binding; for (unsigned i = 0, count = function->memberCount(); i < count; ++i) { Symbol *s = function->memberAt(i); if (Block *b = s->asBlock()) visit(b); } - _currentLookupScope = previous; + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(Block *block) { - LookupScope *previous = _currentLookupScope; + ClassOrNamespace *previous = _currentClassOrNamespace; - LookupScope *binding = new LookupScope(this, previous); - binding->d->_control = control(); + ClassOrNamespace *binding = new ClassOrNamespace(this, previous); + binding->_control = control(); - _currentLookupScope = binding; - _currentLookupScope->d->addSymbol(block); + _currentClassOrNamespace = binding; + _currentClassOrNamespace->addSymbol(block); for (unsigned i = 0; i < block->memberCount(); ++i) // we cannot use lazy processing here, because we have to know - // does this block contain any other blocks or LookupScopes - process(block->memberAt(i), _currentLookupScope); - - // we add this block to parent LookupScope only if it contains - // any nested LookupScopes or other blocks(which have to contain - // nested LookupScopes) - if (! _currentLookupScope->d->_blocks.empty() - || ! _currentLookupScope->d->_nestedScopes.empty() - || ! _currentLookupScope->d->_enums.empty() - || _currentLookupScope->d->_hasTypedefs - || ! _currentLookupScope->d->_anonymouses.empty()) { - previous->d->_blocks[block] = binding; + // does this block contain any other blocks or classOrNamespaces + process(block->memberAt(i), _currentClassOrNamespace); + + // we add this block to parent ClassOrNamespace only if it contains + // any nested ClassOrNamespaces or other blocks(which have to contain + // nested ClassOrNamespaces) + if (! _currentClassOrNamespace->_blocks.empty() + || ! _currentClassOrNamespace->_classOrNamespaces.empty() + || ! _currentClassOrNamespace->_enums.empty() + || ! _currentClassOrNamespace->_anonymouses.empty()) { + previous->_blocks[block] = binding; _entities.append(binding); } else { delete binding; binding = 0; } - _currentLookupScope = previous; + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(BaseClass *b) { - if (LookupScope *base = _currentLookupScope->lookupType(b->name())) { - _currentLookupScope->d->addUsing(base); + if (ClassOrNamespace *base = _currentClassOrNamespace->lookupType(b->name())) { + _currentClassOrNamespace->addUsing(base); } else if (false) { Overview oo; qDebug() << "no entity for:" << oo.prettyName(b->name()); @@ -1826,9 +1769,9 @@ bool CreateBindings::visit(UsingDeclaration *u) if (u->name()) { if (const QualifiedNameId *q = u->name()->asQualifiedNameId()) { if (const Identifier *unqualifiedId = q->name()->asNameId()) { - if (LookupScope *delegate = _currentLookupScope->lookupType(q)) { - LookupScope *b = _currentLookupScope->d->findOrCreateType(unqualifiedId); - b->d->addUsing(delegate); + if (ClassOrNamespace *delegate = _currentClassOrNamespace->lookupType(q)) { + ClassOrNamespace *b = _currentClassOrNamespace->findOrCreateType(unqualifiedId); + b->addUsing(delegate); } } } @@ -1838,8 +1781,8 @@ bool CreateBindings::visit(UsingDeclaration *u) bool CreateBindings::visit(UsingNamespaceDirective *u) { - if (LookupScope *e = _currentLookupScope->lookupType(u->name())) { - _currentLookupScope->d->addUsing(e); + if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(u->name())) { + _currentClassOrNamespace->addUsing(e); } else if (false) { Overview oo; qDebug() << "no entity for namespace:" << oo.prettyName(u->name()); @@ -1852,9 +1795,9 @@ bool CreateBindings::visit(NamespaceAlias *a) if (! a->identifier()) { return false; - } else if (LookupScope *e = _currentLookupScope->lookupType(a->namespaceName())) { + } else if (ClassOrNamespace *e = _currentClassOrNamespace->lookupType(a->namespaceName())) { if (a->name()->isNameId() || a->name()->isTemplateNameId() || a->name()->isAnonymousNameId()) - _currentLookupScope->d->addNestedType(a->name(), e); + _currentClassOrNamespace->addNestedType(a->name(), e); } else if (false) { Overview oo; @@ -1866,7 +1809,7 @@ bool CreateBindings::visit(NamespaceAlias *a) bool CreateBindings::visit(ObjCClass *klass) { - LookupScope *previous = enterGlobalLookupScope(klass); + ClassOrNamespace *previous = enterGlobalClassOrNamespace(klass); process(klass->baseClass()); @@ -1876,14 +1819,14 @@ bool CreateBindings::visit(ObjCClass *klass) for (unsigned i = 0; i < klass->memberCount(); ++i) process(klass->memberAt(i)); - _currentLookupScope = previous; + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(ObjCBaseClass *b) { - if (LookupScope *base = _globalNamespace->lookupType(b->name())) { - _currentLookupScope->d->addUsing(base); + if (ClassOrNamespace *base = _globalNamespace->lookupType(b->name())) { + _currentClassOrNamespace->addUsing(base); } else if (false) { Overview oo; qDebug() << "no entity for:" << oo.prettyName(b->name()); @@ -1893,14 +1836,14 @@ bool CreateBindings::visit(ObjCBaseClass *b) bool CreateBindings::visit(ObjCForwardClassDeclaration *klass) { - LookupScope *previous = enterGlobalLookupScope(klass); - _currentLookupScope = previous; + ClassOrNamespace *previous = enterGlobalClassOrNamespace(klass); + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(ObjCProtocol *proto) { - LookupScope *previous = enterGlobalLookupScope(proto); + ClassOrNamespace *previous = enterGlobalClassOrNamespace(proto); for (unsigned i = 0; i < proto->protocolCount(); ++i) process(proto->protocolAt(i)); @@ -1908,14 +1851,14 @@ bool CreateBindings::visit(ObjCProtocol *proto) for (unsigned i = 0; i < proto->memberCount(); ++i) process(proto->memberAt(i)); - _currentLookupScope = previous; + _currentClassOrNamespace = previous; return false; } bool CreateBindings::visit(ObjCBaseProtocol *b) { - if (LookupScope *base = _globalNamespace->lookupType(b->name())) { - _currentLookupScope->d->addUsing(base); + if (ClassOrNamespace *base = _globalNamespace->lookupType(b->name())) { + _currentClassOrNamespace->addUsing(base); } else if (false) { Overview oo; qDebug() << "no entity for:" << oo.prettyName(b->name()); @@ -1925,8 +1868,8 @@ bool CreateBindings::visit(ObjCBaseProtocol *b) bool CreateBindings::visit(ObjCForwardProtocolDeclaration *proto) { - LookupScope *previous = enterGlobalLookupScope(proto); - _currentLookupScope = previous; + ClassOrNamespace *previous = enterGlobalClassOrNamespace(proto); + _currentClassOrNamespace = previous; return false; } @@ -1935,57 +1878,29 @@ bool CreateBindings::visit(ObjCMethod *) return false; } -FullySpecifiedType CreateBindings::resolveTemplateArgument(Clone &cloner, - Subst &subst, - LookupScope *origin, - const Template *specialization, - const TemplateNameId *instantiation, - unsigned index) -{ - FullySpecifiedType ty; - CPP_ASSERT(specialization && instantiation, return ty); - - const TypenameArgument *tParam = 0; - if (Symbol *tArgument = specialization->templateParameterAt(index)) - tParam = tArgument->asTypenameArgument(); - if (!tParam) - return ty; - - if (index < instantiation->templateArgumentCount()) - ty = instantiation->templateArgumentAt(index); - else - ty = cloner.type(tParam->type(), &subst); - - TypeResolver typeResolver(*this); - Scope *resolveScope = specialization->enclosingScope(); - typeResolver.resolve(&ty, &resolveScope, origin); - const TemplateNameId *templSpecId = specialization->name()->asTemplateNameId(); - const unsigned templSpecArgumentCount = templSpecId ? templSpecId->templateArgumentCount() : 0; - if (index < templSpecArgumentCount && templSpecId->templateArgumentAt(index)->isPointerType()) { - if (PointerType *pointerType = ty->asPointerType()) - ty = pointerType->elementType(); - } - - if (const Name *name = tParam->name()) - subst.bind(cloner.name(name, &subst), ty); - return ty; -} - -void CreateBindings::initializeSubst(Clone &cloner, - Subst &subst, - LookupScope *origin, - const Template *specialization, - const TemplateNameId *instantiation) +Symbol *CreateBindings::instantiateTemplateFunction(const TemplateNameId *instantiation, + Template *specialization) const { + const unsigned argumentCountOfInitialization = instantiation->templateArgumentCount(); const unsigned argumentCountOfSpecialization = specialization->templateParameterCount(); - if (_depth > 15) - return; + Clone cloner(_control.data()); + Subst subst(_control.data()); + for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) { + const TypenameArgument *tParam + = specialization->templateParameterAt(i)->asTypenameArgument(); + if (!tParam) + continue; + const Name *name = tParam->name(); + if (!name) + continue; - ++_depth; - for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) - resolveTemplateArgument(cloner, subst, origin, specialization, instantiation, i); - --_depth; + FullySpecifiedType ty = (i < argumentCountOfInitialization) ? + instantiation->templateArgumentAt(i): + cloner.type(tParam->type(), &subst); + + subst.bind(cloner.name(name, &subst), ty); + } + return cloner.symbol(specialization, &subst); } -} // namespace CPlusPlus diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 8410c9000b..5858d80c95 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -41,7 +41,6 @@ #include <cplusplus/Control.h> #include <cplusplus/Name.h> -#include <QEnableSharedFromThis> #include <QSet> #include <QMap> @@ -59,78 +58,158 @@ struct FullyQualifiedName : fqn(fqn) {} }; -class LookupScopePrivate; -class Instantiator; } // namespace Internal; class CreateBindings; -class CPLUSPLUS_EXPORT LookupScope +class CPLUSPLUS_EXPORT ClassOrNamespace { - Q_DISABLE_COPY(LookupScope) + Q_DISABLE_COPY(ClassOrNamespace) - LookupScope(CreateBindings *factory, LookupScope *parent); + ClassOrNamespace(CreateBindings *factory, ClassOrNamespace *parent); public: - ~LookupScope(); + ~ClassOrNamespace(); - LookupScope *instantiationOrigin() const; + const TemplateNameId *templateId() const; + ClassOrNamespace *instantiationOrigin() const; - LookupScope *parent() const; - QList<LookupScope *> usings() const; + ClassOrNamespace *parent() const; + QList<ClassOrNamespace *> usings() const; QList<Enum *> unscopedEnums() const; QList<Symbol *> symbols() const; + ClassOrNamespace *globalNamespace() const; + QList<LookupItem> lookup(const Name *name); QList<LookupItem> find(const Name *name); - LookupScope *lookupType(const Name *name); - LookupScope *lookupType(const Name *name, Block *block); - LookupScope *findType(const Name *name); - LookupScope *findBlock(Block *block); + ClassOrNamespace *lookupType(const Name *name); + ClassOrNamespace *lookupType(const Name *name, Block *block); + ClassOrNamespace *findType(const Name *name); + ClassOrNamespace *findBlock(Block *block); + + Symbol *lookupInScope(const QList<const Name *> &fullName); - /// The class this LookupScope is based on. - Class *rootClass() const; + /// The class this ClassOrNamespace is based on. + Class *rootClass() const { return _rootClass; } private: - Internal::LookupScopePrivate *d; + typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table; + typedef std::map<const TemplateNameId *, ClassOrNamespace *, TemplateNameId::Compare> TemplateNameIdTable; + typedef QHash<const AnonymousNameId *, ClassOrNamespace *> Anonymouses; + + /// \internal + void flush(); + + /// \internal + ClassOrNamespace *findOrCreateType(const Name *name, ClassOrNamespace *origin = 0, + Class *clazz = 0); + + ClassOrNamespace *findOrCreateNestedAnonymousType(const AnonymousNameId *anonymousNameId); + + void addTodo(Symbol *symbol); + void addSymbol(Symbol *symbol); + void addUnscopedEnum(Enum *e); + void addUsing(ClassOrNamespace *u); + void addNestedType(const Name *alias, ClassOrNamespace *e); + + QList<LookupItem> lookup_helper(const Name *name, bool searchInEnclosingScope); + + void lookup_helper(const Name *name, ClassOrNamespace *binding, + QList<LookupItem> *result, + QSet<ClassOrNamespace *> *processed, + const TemplateNameId *templateId); + + ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed, + bool searchInEnclosingScope, ClassOrNamespace *origin); + + ClassOrNamespace *findBlock_helper(Block *block, QSet<ClassOrNamespace *> *processed, + bool searchInEnclosingScope); + + ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin); + + void instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass, + Clone &cloner, + Subst &subst, + ClassOrNamespace *enclosingTemplateClassInstantiation); + ClassOrNamespace *findSpecialization(const TemplateNameId *templId, + const TemplateNameIdTable &specializations); + + CreateBindings *_factory; + ClassOrNamespace *_parent; + QList<Symbol *> _symbols; + QList<ClassOrNamespace *> _usings; + Table _classOrNamespaces; + QHash<Block *, ClassOrNamespace *> _blocks; + QList<Enum *> _enums; + QList<Symbol *> _todo; + QSharedPointer<Control> _control; + TemplateNameIdTable _specializations; + QMap<const TemplateNameId *, ClassOrNamespace *> _instantiations; + Anonymouses _anonymouses; + QSet<const AnonymousNameId *> _declaredOrTypedefedAnonymouses; + + QHash<Internal::FullyQualifiedName, Symbol *> *_scopeLookupCache; + + // it's an instantiation. + const TemplateNameId *_templateId; + ClassOrNamespace *_instantiationOrigin; + + AlreadyConsideredClassContainer<Class> _alreadyConsideredClasses; + AlreadyConsideredClassContainer<TemplateNameId> _alreadyConsideredTemplates; + + Class *_rootClass; + + class NestedClassInstantiator + { + public: + NestedClassInstantiator(CreateBindings *factory, Clone &cloner, Subst &subst) + : _factory(factory) + , _cloner(cloner) + , _subst(subst) + {} + void instantiate(ClassOrNamespace *enclosingTemplateClass, + ClassOrNamespace *enclosingTemplateClassInstantiation); + private: + bool isInstantiateNestedClassNeeded(const QList<Symbol *> &symbols) const; + bool containsTemplateType(Declaration *declaration) const; + bool containsTemplateType(Function *function) const; + NamedType *findNamedType(Type *memberType) const; + + QSet<ClassOrNamespace *> _alreadyConsideredNestedClassInstantiations; + CreateBindings *_factory; + Clone &_cloner; + Subst &_subst; + }; + +public: + const Name *_name; // For debug - friend class Internal::LookupScopePrivate; - friend class Internal::Instantiator; friend class CreateBindings; }; -class CPLUSPLUS_EXPORT CreateBindings - : protected SymbolVisitor - , public QEnableSharedFromThis<CreateBindings> +class CPLUSPLUS_EXPORT CreateBindings: protected SymbolVisitor { Q_DISABLE_COPY(CreateBindings) public: - typedef QSharedPointer<CreateBindings> Ptr; - CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot); virtual ~CreateBindings(); /// Returns the binding for the global namespace. - LookupScope *globalNamespace() const; + ClassOrNamespace *globalNamespace() const; /// Finds the binding associated to the given symbol. - LookupScope *lookupType(Symbol *symbol, LookupScope *enclosingBinding = 0); - LookupScope *lookupType(const QList<const Name *> &path, LookupScope *enclosingBinding = 0); + ClassOrNamespace *lookupType(Symbol *symbol, ClassOrNamespace *enclosingBinding = 0); + ClassOrNamespace *lookupType(const QList<const Name *> &path, + ClassOrNamespace *enclosingBinding = 0); /// Returns the Control that must be used to create temporary symbols. /// \internal QSharedPointer<Control> control() const { return _control; } - Snapshot &snapshot() - { return _snapshot; } - - /// Adds an expression document in order to keep their symbols and names alive - void addExpressionDocument(Document::Ptr document) - { _expressionDocuments.append(document); } - bool expandTemplates() const { return _expandTemplates; } void setExpandTemplates(bool expandTemplates) @@ -140,36 +219,28 @@ public: /// Store the result in \a results. /// \internal void lookupInScope(const Name *name, Scope *scope, QList<LookupItem> *result, - LookupScope *binding = 0); + const TemplateNameId *templateId, ClassOrNamespace *binding); /// Create bindings for the symbols reachable from \a rootSymbol. /// \internal - void process(Symbol *rootSymbol, LookupScope *lookupScope); + void process(Symbol *rootSymbol, ClassOrNamespace *classOrNamespace); - /// Create an empty LookupScope binding with the given \a parent. + /// Create an empty ClassOrNamespace binding with the given \a parent. /// \internal - LookupScope *allocLookupScope(LookupScope *parent, const Name *name); - - FullySpecifiedType resolveTemplateArgument(Clone &cloner, Subst &subst, - LookupScope *origin, - const Template *specialization, - const TemplateNameId *instantiation, - unsigned index); - void initializeSubst(Clone &cloner, Subst &subst, LookupScope *origin, - const Template *specialization, const TemplateNameId *instantiation); + ClassOrNamespace *allocClassOrNamespace(ClassOrNamespace *parent); protected: using SymbolVisitor::visit; - /// Change the current LookupScope binding. - LookupScope *switchCurrentLookupScope(LookupScope *lookupScope); + /// Change the current ClassOrNamespace binding. + ClassOrNamespace *switchCurrentClassOrNamespace(ClassOrNamespace *classOrNamespace); - /// Enters the LookupScope binding associated with the given \a symbol. - LookupScope *enterLookupScopeBinding(Symbol *symbol); + /// Enters the ClassOrNamespace binding associated with the given \a symbol. + ClassOrNamespace *enterClassOrNamespaceBinding(Symbol *symbol); - /// Enters a LookupScope binding for the given \a symbol in the global + /// Enters a ClassOrNamespace binding for the given \a symbol in the global /// namespace binding. - LookupScope *enterGlobalLookupScope(Symbol *symbol); + ClassOrNamespace *enterGlobalClassOrNamespace(Symbol *symbol); /// Creates bindings for the given \a document. void process(Document::Ptr document); @@ -178,7 +249,6 @@ protected: void process(Symbol *root); virtual bool visit(Template *templ); - virtual bool visit(ExplicitInstantiation *inst); virtual bool visit(Namespace *ns); virtual bool visit(Class *klass); virtual bool visit(ForwardClassDeclaration *klass); @@ -201,15 +271,16 @@ protected: virtual bool visit(ObjCMethod *); private: + Symbol *instantiateTemplateFunction(const TemplateNameId *instantiation, + Template *specialization) const; + Snapshot _snapshot; QSharedPointer<Control> _control; - QList<Document::Ptr> _expressionDocuments; QSet<Namespace *> _processed; - QList<LookupScope *> _entities; - LookupScope *_globalNamespace; - LookupScope *_currentLookupScope; + QList<ClassOrNamespace *> _entities; + ClassOrNamespace *_globalNamespace; + ClassOrNamespace *_currentClassOrNamespace; bool _expandTemplates; - int _depth; }; class CPLUSPLUS_EXPORT LookupContext @@ -223,7 +294,7 @@ public: LookupContext(Document::Ptr expressionDocument, Document::Ptr thisDocument, const Snapshot &snapshot, - CreateBindings::Ptr bindings = CreateBindings::Ptr()); + QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>()); LookupContext(const LookupContext &other); LookupContext &operator = (const LookupContext &other); @@ -233,25 +304,25 @@ public: Document::Ptr document(const QString &fileName) const; Snapshot snapshot() const; - LookupScope *globalNamespace() const; + ClassOrNamespace *globalNamespace() const; QList<LookupItem> lookup(const Name *name, Scope *scope) const; - LookupScope *lookupType(const Name *name, Scope *scope, - LookupScope *enclosingBinding = 0, + ClassOrNamespace *lookupType(const Name *name, Scope *scope, + ClassOrNamespace *enclosingBinding = 0, QSet<const Declaration *> typedefsBeingResolved = QSet<const Declaration *>()) const; - LookupScope *lookupType(Symbol *symbol, - LookupScope *enclosingBinding = 0) const; - LookupScope *lookupParent(Symbol *symbol) const; + ClassOrNamespace *lookupType(Symbol *symbol, + ClassOrNamespace *enclosingBinding = 0) const; + ClassOrNamespace *lookupParent(Symbol *symbol) const; /// \internal - CreateBindings::Ptr bindings() const + QSharedPointer<CreateBindings> bindings() const { return _bindings; } static QList<const Name *> fullyQualifiedName(Symbol *symbol); static QList<const Name *> path(Symbol *symbol); - static const Name *minimalName(Symbol *symbol, LookupScope *target, Control *control); + static const Name *minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control); void setExpandTemplates(bool expandTemplates) { @@ -261,7 +332,7 @@ public: } private: - QList<LookupItem> lookupByUsing(const Name *name, LookupScope *bindingScope) const; + QList<LookupItem> lookupByUsing(const Name *name, ClassOrNamespace *bindingScope) const; // The current expression. Document::Ptr _expressionDocument; @@ -273,7 +344,7 @@ private: Snapshot _snapshot; // Bindings - CreateBindings::Ptr _bindings; + QSharedPointer<CreateBindings> _bindings; bool m_expandTemplates; }; diff --git a/src/libs/cplusplus/LookupItem.cpp b/src/libs/cplusplus/LookupItem.cpp index 4e22389503..0621c1f6e9 100644 --- a/src/libs/cplusplus/LookupItem.cpp +++ b/src/libs/cplusplus/LookupItem.cpp @@ -77,10 +77,10 @@ Scope *LookupItem::scope() const void LookupItem::setScope(Scope *scope) { _scope = scope; } -LookupScope *LookupItem::binding() const +ClassOrNamespace *LookupItem::binding() const { return _binding; } -void LookupItem::setBinding(LookupScope *binding) +void LookupItem::setBinding(ClassOrNamespace *binding) { _binding = binding; } bool LookupItem::operator == (const LookupItem &other) const diff --git a/src/libs/cplusplus/LookupItem.h b/src/libs/cplusplus/LookupItem.h index 13963b7064..46c7b34716 100644 --- a/src/libs/cplusplus/LookupItem.h +++ b/src/libs/cplusplus/LookupItem.h @@ -37,7 +37,7 @@ namespace CPlusPlus { -class LookupScope; +class ClassOrNamespace; class CPLUSPLUS_EXPORT LookupItem { @@ -63,8 +63,8 @@ public: /// Sets this item's scope. void setScope(Scope *scope); - LookupScope *binding() const; - void setBinding(LookupScope *binding); + ClassOrNamespace *binding() const; + void setBinding(ClassOrNamespace *binding); bool operator == (const LookupItem &other) const; bool operator != (const LookupItem &other) const; @@ -73,7 +73,7 @@ private: FullySpecifiedType _type; Scope *_scope; Symbol *_declaration; - LookupScope *_binding; + ClassOrNamespace *_binding; }; uint qHash(const CPlusPlus::LookupItem &result); diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 43887b2995..adaac12ab5 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -32,9 +32,9 @@ #include "LookupContext.h" #include "Overview.h" +#include "DeprecatedGenTemplateInstance.h" #include "CppRewriter.h" #include "TypeOfExpression.h" -#include "TypeResolver.h" #include <cplusplus/Control.h> #include <cplusplus/AST.h> @@ -75,6 +75,131 @@ static QList<T> removeDuplicates(const QList<T> &results) return uniqueList; } +class TypedefsResolver +{ +public: + TypedefsResolver(const LookupContext &context) : _context(context) {} + void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) + { + QSet<Symbol *> visited; + _binding = binding; + // Use a hard limit when trying to resolve typedefs. Typedefs in templates can refer to + // each other, each time enhancing the template argument and thus making it impossible to + // use an "alreadyResolved" container. FIXME: We might overcome this by resolving the + // template parameters. + unsigned maxDepth = 15; + for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) { + QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding); + + if (Q_UNLIKELY(debug)) + qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; + + if (!findTypedef(namedTypeItems, type, scope, visited)) + break; + } + } + +private: + NamedType *getNamedType(FullySpecifiedType& type) const + { + NamedType *namedTy = type->asNamedType(); + if (! namedTy) { + if (PointerType *pointerTy = type->asPointerType()) + namedTy = pointerTy->elementType()->asNamedType(); + } + return namedTy; + } + + QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope, + ClassOrNamespace *binding) const + { + QList<LookupItem> namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope); + if (namedTypeItems.isEmpty()) { + if (binding) + namedTypeItems = binding->lookup(name); + if (ClassOrNamespace *scopeCon = _context.lookupType(scope)) + namedTypeItems += scopeCon->lookup(name); + } + + return namedTypeItems; + } + + /// Return all typedefs with given name from given scope up to function scope. + static QList<LookupItem> typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) + { + QList<LookupItem> results; + if (!scope) + return results; + Scope *enclosingBlockScope = 0; + for (Block *block = scope->asBlock(); block; + block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) { + const unsigned memberCount = block->memberCount(); + for (unsigned i = 0; i < memberCount; ++i) { + Symbol *symbol = block->memberAt(i); + if (Declaration *declaration = symbol->asDeclaration()) { + if (isTypedefWithName(declaration, name)) { + LookupItem item; + item.setDeclaration(declaration); + item.setScope(block); + item.setType(declaration->type()); + results.append(item); + } + } + } + enclosingBlockScope = block->enclosingScope(); + } + return results; + } + + static bool isTypedefWithName(const Declaration *declaration, const Name *name) + { + if (declaration->isTypedef()) { + const Identifier *identifier = declaration->name()->identifier(); + if (name->identifier()->match(identifier)) + return true; + } + return false; + } + + bool findTypedef(const QList<LookupItem>& namedTypeItems, FullySpecifiedType *type, + Scope **scope, QSet<Symbol *>& visited) + { + bool foundTypedef = false; + foreach (const LookupItem &it, namedTypeItems) { + Symbol *declaration = it.declaration(); + if (declaration && declaration->isTypedef()) { + if (visited.contains(declaration)) + break; + visited.insert(declaration); + + // continue working with the typedefed type and scope + if (type->type()->isPointerType()) { + *type = FullySpecifiedType( + _context.bindings()->control()->pointerType(declaration->type())); + } else if (type->type()->isReferenceType()) { + *type = FullySpecifiedType( + _context.bindings()->control()->referenceType( + declaration->type(), + declaration->type()->asReferenceType()->isRvalueReference())); + } else { + *type = declaration->type(); + } + + *scope = it.scope(); + _binding = it.binding(); + foundTypedef = true; + break; + } + } + + return foundTypedef; + } + + const LookupContext &_context; + // binding has to be remembered in case of resolving typedefs for templates + ClassOrNamespace *_binding; +}; + static int evaluateFunctionArgument(const FullySpecifiedType &actualTy, const FullySpecifiedType &formalTy) { @@ -176,7 +301,7 @@ void ResolveExpression::addResults(const QList<LookupItem> &items) } void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope, - LookupScope *binding) + ClassOrNamespace *binding) { LookupItem item; item.setType(ty); @@ -206,7 +331,7 @@ bool ResolveExpression::visit(BinaryExpressionAST *ast) if (d->core_declarator) { if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId()) { if (NameAST *nameAST = declaratorId->name) { - if (LookupScope *binding = baseExpression(_results, T_ARROW)) { + if (ClassOrNamespace *binding = baseExpression(_results, T_ARROW)) { _results.clear(); addResults(binding->lookup(nameAST->name)); } @@ -487,17 +612,19 @@ bool ResolveExpression::visit(UnaryExpressionAST *ast) added = true; } else if (namedTy != 0) { const Name *starOp = control()->operatorNameId(OperatorNameId::StarOp); - if (LookupScope *b = _context.lookupType(namedTy->name(), p.scope(), p.binding())) { + if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), p.scope(), p.binding())) { foreach (const LookupItem &r, b->find(starOp)) { Symbol *overload = r.declaration(); if (Function *funTy = overload->type()->asFunctionType()) { if (maybeValidPrototype(funTy, 0)) { - FullySpecifiedType retTy = funTy->returnType().simplified(); - p.setType(retTy); - p.setScope(funTy->enclosingScope()); - it.setValue(p); - added = true; - break; + if (Function *proto = instantiate(b->templateId(), funTy)->asFunctionType()) { + FullySpecifiedType retTy = proto->returnType().simplified(); + p.setType(retTy); + p.setScope(proto->enclosingScope()); + it.setValue(p); + added = true; + break; + } } } } @@ -526,6 +653,48 @@ bool ResolveExpression::visit(QualifiedNameAST *ast) return false; } +namespace { + +class DeduceAutoCheck : public ASTVisitor +{ +public: + DeduceAutoCheck(const Identifier *id, TranslationUnit *tu) + : ASTVisitor(tu), _id(id), _block(false) + { + accept(tu->ast()); + } + + virtual bool preVisit(AST *) + { + if (_block) + return false; + + return true; + } + + virtual bool visit(SimpleNameAST *ast) + { + if (ast->name + && ast->name->identifier() + && strcmp(ast->name->identifier()->chars(), _id->chars()) == 0) { + _block = true; + } + + return false; + } + + virtual bool visit(MemberAccessAST *ast) + { + accept(ast->base_expression); + return false; + } + + const Identifier *_id; + bool _block; +}; + +} // namespace anonymous + bool ResolveExpression::visit(SimpleNameAST *ast) { QList<LookupItem> candidates = _context.lookup(ast->name, _scope); @@ -539,7 +708,7 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (item.declaration() == 0) continue; - if (item.type().isAuto() || item.type().isDecltype()) { + if (item.type().isAuto()) { const Declaration *decl = item.declaration()->asDeclaration(); if (!decl) continue; @@ -548,10 +717,53 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (_autoDeclarationsBeingResolved.contains(decl)) continue; - newCandidates += - TypeResolver::resolveDeclInitializer(*_context.bindings(), decl, - _autoDeclarationsBeingResolved << decl, - ast->name->identifier()); + const StringLiteral *initializationString = decl->getInitializer(); + if (initializationString == 0) + continue; + + const QByteArray &initializer = + QByteArray::fromRawData(initializationString->chars(), + initializationString->size()).trimmed(); + + // Skip lambda-function initializers + if (initializer.length() > 0 && initializer[0] == '[') + continue; + + TypeOfExpression exprTyper; + exprTyper.setExpandTemplates(true); + Document::Ptr doc = _context.snapshot().document(QString::fromLocal8Bit(decl->fileName())); + exprTyper.init(doc, _context.snapshot(), _context.bindings(), + QSet<const Declaration* >(_autoDeclarationsBeingResolved) << decl); + + Document::Ptr exprDoc = + documentForExpression(exprTyper.preprocessedExpression(initializer)); + exprDoc->check(); + + DeduceAutoCheck deduceAuto(ast->name->identifier(), exprDoc->translationUnit()); + if (deduceAuto._block) + continue; + + const QList<LookupItem> &typeItems = exprTyper(extractExpressionAST(exprDoc), exprDoc, + decl->enclosingScope()); + if (typeItems.empty()) + continue; + + Clone cloner(_context.bindings()->control().data()); + + for (int n = 0; n < typeItems.size(); ++ n) { + FullySpecifiedType newType = cloner.type(typeItems[n].type(), 0); + if (n == 0) { + item.setType(newType); + item.setScope(typeItems[n].scope()); + item.setBinding(typeItems[n].binding()); + } else { + LookupItem newItem(item); + newItem.setType(newType); + newItem.setScope(typeItems[n].scope()); + newItem.setBinding(typeItems[n].binding()); + newCandidates.push_back(newItem); + } + } } else { item.setType(item.declaration()->type()); item.setScope(item.declaration()->enclosingScope()); @@ -661,12 +873,14 @@ bool ResolveExpression::visit(CallAST *ast) Scope *scope = result.scope(); if (NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *b = _context.lookupType(namedTy->name(), scope)) { + if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) { foreach (const LookupItem &r, b->find(functionCallOp)) { Symbol *overload = r.declaration(); if (Function *funTy = overload->type()->asFunctionType()) { - if (maybeValidPrototype(funTy, actualArgumentCount)) - addResult(funTy->returnType().simplified(), scope); + if (maybeValidPrototype(funTy, actualArgumentCount)) { + if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType()) + addResult(proto->returnType().simplified(), scope); + } } } } @@ -679,6 +893,14 @@ bool ResolveExpression::visit(CallAST *ast) // Constructor call FullySpecifiedType ctorTy = control()->namedType(classTy->name()); addResult(ctorTy, scope); + } else if (Template *templateTy = ty->asTemplateType()) { + // template function + if (Symbol *declaration = templateTy->declaration()) { + if (Function *funTy = declaration->asFunction()) { + if (maybeValidPrototype(funTy, actualArgumentCount)) + addResult(funTy->returnType().simplified(), scope); + } + } } } @@ -694,8 +916,8 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) FullySpecifiedType ty = result.type().simplified(); Scope *scope = result.scope(); - TypeResolver typeResolver(*_context.bindings()); - typeResolver.resolve(&ty, &scope, result.binding()); + TypedefsResolver typedefsResolver(_context); + typedefsResolver.resolve(&ty, &scope, result.binding()); if (PointerType *ptrTy = ty->asPointerType()) { addResult(ptrTy->elementType().simplified(), scope); @@ -704,12 +926,13 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) addResult(arrTy->elementType().simplified(), scope); } else if (NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *b = _context.lookupType(namedTy->name(), scope)) { + if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) { foreach (const LookupItem &r, b->find(arrayAccessOp)) { Symbol *overload = r.declaration(); if (Function *funTy = overload->type()->asFunctionType()) { - // ### TODO: check the actual arguments - addResult(funTy->returnType().simplified(), scope); + if (Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType()) + // ### TODO: check the actual arguments + addResult(proto->returnType().simplified(), scope); } } @@ -719,7 +942,7 @@ bool ResolveExpression::visit(ArrayAccessAST *ast) return false; } -QList<LookupItem> ResolveExpression::getMembers(LookupScope *binding, const Name *memberName) const +QList<LookupItem> ResolveExpression::getMembers(ClassOrNamespace *binding, const Name *memberName) const { Q_UNUSED(binding); Q_UNUSED(memberName); @@ -788,17 +1011,17 @@ bool ResolveExpression::visit(MemberAccessAST *ast) // Remember the access operator. const int accessOp = tokenKind(ast->access_token); - if (LookupScope *binding = baseExpression(baseResults, accessOp)) + if (ClassOrNamespace *binding = baseExpression(baseResults, accessOp)) addResults(binding->find(memberName)); return false; } -LookupScope *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope, - LookupScope *enclosingBinding) const +ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope, + ClassOrNamespace *enclosingBinding) const { FullySpecifiedType ty = originalTy.simplified(); - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; if (Class *klass = ty->asClassType()) { if (scope->isBlock()) @@ -816,14 +1039,15 @@ LookupScope *ResolveExpression::findClass(const FullySpecifiedType &originalTy, return binding; } -LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults, - int accessOp, - bool *replacedDotOperator) const +ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults, + int accessOp, + bool *replacedDotOperator) const { if (Q_UNLIKELY(debug)) qDebug() << "In ResolveExpression::baseExpression with" << baseResults.size() << "results..."; int i = 0; - TypeResolver typeResolver(*_context.bindings()); + Overview oo; + TypedefsResolver typedefsResolver(_context); foreach (const LookupItem &r, baseResults) { if (!r.type().type() || !r.scope()) @@ -832,55 +1056,80 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu FullySpecifiedType originalType = ty; Scope *scope = r.scope(); - if (Q_UNLIKELY(debug)) + if (Q_UNLIKELY(debug)) { qDebug("trying result #%d", ++i); + qDebug() << "- before typedef resolving we have:" << oo(ty); + } + + typedefsResolver.resolve(&ty, &scope, r.binding()); - typeResolver.resolve(&ty, &scope, r.binding()); + if (Q_UNLIKELY(debug)) + qDebug() << "- after typedef resolving:" << oo(ty); if (accessOp == T_ARROW) { if (PointerType *ptrTy = ty->asPointerType()) { FullySpecifiedType type = ptrTy->elementType(); - if (LookupScope *binding = findClass(type, scope)) + if (ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + type)) { + return binding; + } + if (ClassOrNamespace *binding = findClass(type, scope)) return binding; - } else if (LookupScope *binding = findClass(ty, scope, r.binding())) { - // lookup for overloads of operator-> - - const OperatorNameId *arrowOp - = control()->operatorNameId(OperatorNameId::ArrowOp); - foreach (const LookupItem &r, binding->find(arrowOp)) { - Symbol *overload = r.declaration(); - if (! overload) - continue; - Scope *functionScope = overload->enclosingScope(); + } else { + ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + ty); - if (Function *funTy = overload->type()->asFunctionType()) { - FullySpecifiedType retTy = funTy->returnType().simplified(); + if (! binding) + binding = findClass(ty, scope, r.binding()); - typeResolver.resolve(&retTy, &functionScope, r.binding()); + if (binding){ + // lookup for overloads of operator-> - if (! retTy->isPointerType() && ! retTy->isNamedType()) + const OperatorNameId *arrowOp + = control()->operatorNameId(OperatorNameId::ArrowOp); + foreach (const LookupItem &r, binding->find(arrowOp)) { + Symbol *overload = r.declaration(); + if (! overload) continue; + Scope *functionScope = overload->enclosingScope(); + + if (overload->type()->isFunctionType()) { + FullySpecifiedType overloadTy + = instantiate(binding->templateId(), overload); + Function *instantiatedFunction = overloadTy->asFunctionType(); + Q_ASSERT(instantiatedFunction != 0); + + FullySpecifiedType retTy + = instantiatedFunction->returnType().simplified(); + + typedefsResolver.resolve(&retTy, &functionScope, r.binding()); - if (PointerType *ptrTy = retTy->asPointerType()) - retTy = ptrTy->elementType(); + if (! retTy->isPointerType() && ! retTy->isNamedType()) + continue; - if (LookupScope *retBinding = findClass(retTy, functionScope)) - return retBinding; + if (PointerType *ptrTy = retTy->asPointerType()) + retTy = ptrTy->elementType(); - if (scope != functionScope) { - if (LookupScope *retBinding = findClass(retTy, scope)) + if (ClassOrNamespace *retBinding = findClass(retTy, functionScope)) return retBinding; - } - if (LookupScope *origin = binding->instantiationOrigin()) { - foreach (Symbol *originSymbol, origin->symbols()) { - Scope *originScope = originSymbol->asScope(); - if (originScope && originScope != scope - && originScope != functionScope) { - if (LookupScope *retBinding - = findClass(retTy, originScope)) - return retBinding; + if (scope != functionScope) { + if (ClassOrNamespace *retBinding = findClass(retTy, scope)) + return retBinding; + } + + if (ClassOrNamespace *origin = binding->instantiationOrigin()) { + foreach (Symbol *originSymbol, origin->symbols()) { + Scope *originScope = originSymbol->asScope(); + if (originScope && originScope != scope + && originScope != functionScope) { + if (ClassOrNamespace *retBinding + = findClass(retTy, originScope)) + return retBinding; + } } } } @@ -894,13 +1143,19 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu ty = ptrTy->elementType(); } - LookupScope *enclosingBinding = 0; - if (LookupScope *binding = r.binding()) { + if (ClassOrNamespace *binding + = findClassForTemplateParameterInExpressionScope(r.binding(), + ty)) { + return binding; + } + + ClassOrNamespace *enclosingBinding = 0; + if (ClassOrNamespace *binding = r.binding()) { if (binding->instantiationOrigin()) enclosingBinding = binding; } - if (LookupScope *binding = findClass(ty, scope, enclosingBinding)) + if (ClassOrNamespace *binding = findClass(ty, scope, enclosingBinding)) return binding; } } @@ -908,6 +1163,30 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu return 0; } +ClassOrNamespace *ResolveExpression::findClassForTemplateParameterInExpressionScope( + ClassOrNamespace *resultBinding, + const FullySpecifiedType &ty) const +{ + if (resultBinding) { + if (ClassOrNamespace *origin = resultBinding->instantiationOrigin()) { + foreach (Symbol *originSymbol, origin->symbols()) { + if (Scope *originScope = originSymbol->asScope()) { + if (ClassOrNamespace *retBinding = findClass(ty, originScope)) + return retBinding; + } + } + } + } + + return 0; +} + +FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const +{ + return DeprecatedGenTemplateInstance::instantiate(className, candidate, + _context.bindings()->control()); +} + bool ResolveExpression::visit(PostIncrDecrAST *ast) { const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope); @@ -921,7 +1200,7 @@ bool ResolveExpression::visit(ObjCMessageExpressionAST *ast) foreach (const LookupItem &result, receiverResults) { FullySpecifiedType ty = result.type().simplified(); - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; if (ObjCClass *clazz = ty->asObjCClassType()) { // static access, e.g.: diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index df9ea22020..aee53c40fa 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -53,25 +53,26 @@ public: QList<LookupItem> resolve(ExpressionAST *ast, Scope *scope, bool ref = false); QList<LookupItem> reference(ExpressionAST *ast, Scope *scope); - LookupScope *baseExpression(const QList<LookupItem> &baseResults, + ClassOrNamespace *baseExpression(const QList<LookupItem> &baseResults, int accessOp, bool *replacedDotOperator = 0) const; const LookupContext &context() const; protected: - LookupScope *findClass(const FullySpecifiedType &ty, Scope *scope, - LookupScope *enclosingBinding = 0) const; + ClassOrNamespace *findClass(const FullySpecifiedType &ty, Scope *scope, + ClassOrNamespace *enclosingBinding = 0) const; QList<LookupItem> expression(ExpressionAST *ast); QList<LookupItem> switchResults(const QList<LookupItem> &symbols); + FullySpecifiedType instantiate(const Name *className, Symbol *candidate) const; - QList<LookupItem> getMembers(LookupScope *binding, const Name *memberName) const; + QList<LookupItem> getMembers(ClassOrNamespace *binding, const Name *memberName) const; void thisObject(); - void addResult(const FullySpecifiedType &ty, Scope *scope, LookupScope *binding = 0); + void addResult(const FullySpecifiedType &ty, Scope *scope, ClassOrNamespace *binding = 0); void addResults(const QList<Symbol *> &symbols); void addResults(const QList<LookupItem> &items); @@ -125,6 +126,10 @@ protected: private: + ClassOrNamespace *findClassForTemplateParameterInExpressionScope( + ClassOrNamespace *resultBinding, + const FullySpecifiedType &ty) const; + Scope *_scope; const LookupContext& _context; Bind bind; diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp index bc0792262a..8d5be1b251 100644 --- a/src/libs/cplusplus/TypeOfExpression.cpp +++ b/src/libs/cplusplus/TypeOfExpression.cpp @@ -50,7 +50,7 @@ TypeOfExpression::TypeOfExpression(): } void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot, - CreateBindings::Ptr bindings, + QSharedPointer<CreateBindings> bindings, const QSet<const Declaration *> &autoDeclarationsBeingResolved) { m_thisDocument = thisDocument; @@ -62,7 +62,7 @@ void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot Q_ASSERT(m_bindings.isNull()); m_bindings = bindings; if (m_bindings.isNull()) - m_bindings = CreateBindings::Ptr(new CreateBindings(thisDocument, snapshot)); + m_bindings = QSharedPointer<CreateBindings>(new CreateBindings(thisDocument, snapshot)); m_environment.clear(); m_autoDeclarationsBeingResolved = autoDeclarationsBeingResolved; @@ -105,7 +105,7 @@ QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression, m_scope = scope; - m_bindings->addExpressionDocument(document); + m_documents.append(document); m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot, m_bindings); Q_ASSERT(!m_bindings.isNull()); m_lookupContext.setExpandTemplates(m_expandTemplates); @@ -122,7 +122,7 @@ QList<LookupItem> TypeOfExpression::reference(ExpressionAST *expression, m_scope = scope; - m_bindings->addExpressionDocument(document); + m_documents.append(document); m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot, m_bindings); Q_ASSERT(!m_bindings.isNull()); m_lookupContext.setExpandTemplates(m_expandTemplates); diff --git a/src/libs/cplusplus/TypeOfExpression.h b/src/libs/cplusplus/TypeOfExpression.h index 0308f9a45e..158b3e9815 100644 --- a/src/libs/cplusplus/TypeOfExpression.h +++ b/src/libs/cplusplus/TypeOfExpression.h @@ -62,7 +62,7 @@ public: */ void init(Document::Ptr thisDocument, const Snapshot &snapshot, - CreateBindings::Ptr bindings = CreateBindings::Ptr(), + QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>(), const QSet<const Declaration *> &autoDeclarationsBeingResolved = QSet<const Declaration *>()); @@ -135,6 +135,7 @@ public: } private: + void processEnvironment(Document::Ptr doc, Environment *env, QSet<QString> *processed) const; @@ -142,13 +143,20 @@ private: private: Document::Ptr m_thisDocument; Snapshot m_snapshot; - CreateBindings::Ptr m_bindings; + QSharedPointer<CreateBindings> m_bindings; ExpressionAST *m_ast; Scope *m_scope; LookupContext m_lookupContext; mutable QSharedPointer<Environment> m_environment; - QSet<const Declaration *> m_autoDeclarationsBeingResolved; + bool m_expandTemplates; + + // FIXME: This is a temporary hack to avoid dangling pointers. + // Keep the expression documents and thus all the symbols and + // their types alive until they are not needed any more. + QList<Document::Ptr> m_documents; + + QSet<const Declaration *> m_autoDeclarationsBeingResolved; }; ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc); diff --git a/src/libs/cplusplus/TypeResolver.cpp b/src/libs/cplusplus/TypeResolver.cpp deleted file mode 100644 index 1be33f1410..0000000000 --- a/src/libs/cplusplus/TypeResolver.cpp +++ /dev/null @@ -1,262 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms and -** conditions see http://www.qt.io/terms-conditions. For further information -** use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "TypeResolver.h" -#include "Overview.h" -#include "TypeOfExpression.h" - -#include <QDebug> - -static const bool debug = ! qgetenv("QTC_LOOKUPCONTEXT_DEBUG").isEmpty(); - -namespace CPlusPlus { - -namespace { - -class DeduceAutoCheck : public ASTVisitor -{ -public: - DeduceAutoCheck(const Identifier *id, TranslationUnit *tu) - : ASTVisitor(tu), _id(id), _block(false) - { - accept(tu->ast()); - } - - virtual bool preVisit(AST *) - { - if (_block) - return false; - - return true; - } - - virtual bool visit(SimpleNameAST *ast) - { - if (ast->name - && ast->name->identifier() - && strcmp(ast->name->identifier()->chars(), _id->chars()) == 0) { - _block = true; - } - - return false; - } - - virtual bool visit(MemberAccessAST *ast) - { - accept(ast->base_expression); - return false; - } - - const Identifier *_id; - bool _block; -}; - -} // namespace anonymous - -void TypeResolver::resolve(FullySpecifiedType *type, Scope **scope, LookupScope *binding) -{ - QSet<Symbol *> visited; - _binding = binding; - // Use a hard limit when trying to resolve typedefs. Typedefs in templates can refer to - // each other, each time enhancing the template argument and thus making it impossible to - // use an "alreadyResolved" container. FIXME: We might overcome this by resolving the - // template parameters. - unsigned maxDepth = 15; - Overview oo; - if (Q_UNLIKELY(debug)) - qDebug() << "- before typedef resolving we have:" << oo(*type); - for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) { - QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding); - - if (Q_UNLIKELY(debug)) - qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; - - if (!findTypedef(namedTypeItems, type, scope, visited)) - break; - } - if (Q_UNLIKELY(debug)) - qDebug() << "- after typedef resolving:" << oo(*type); -} - -NamedType *TypeResolver::getNamedType(FullySpecifiedType &type) const -{ - NamedType *namedTy = type->asNamedType(); - if (! namedTy) { - if (PointerType *pointerTy = type->asPointerType()) - namedTy = pointerTy->elementType()->asNamedType(); - } - return namedTy; -} - -QList<LookupItem> TypeResolver::getNamedTypeItems(const Name *name, Scope *scope, - LookupScope *binding) const -{ - QList<LookupItem> namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope); - if (namedTypeItems.isEmpty()) { - if (binding) - namedTypeItems = binding->lookup(name); - if (LookupScope *scopeCon = _factory.lookupType(scope)) { - if (scopeCon != binding) - namedTypeItems += scopeCon->lookup(name); - } - } - - return namedTypeItems; -} - -/// Return all typedefs with given name from given scope up to function scope. -QList<LookupItem> TypeResolver::typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope) -{ - QList<LookupItem> results; - if (!scope) - return results; - Scope *enclosingBlockScope = 0; - for (Block *block = scope->asBlock(); block; - block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) { - const unsigned memberCount = block->memberCount(); - for (unsigned i = 0; i < memberCount; ++i) { - Symbol *symbol = block->memberAt(i); - if (Declaration *declaration = symbol->asDeclaration()) { - if (isTypedefWithName(declaration, name)) { - LookupItem item; - item.setDeclaration(declaration); - item.setScope(block); - item.setType(declaration->type()); - results.append(item); - } - } - } - enclosingBlockScope = block->enclosingScope(); - if (enclosingBlockScope) { - // For lambda, step beyond the function to its enclosing block - if (Function *enclosingFunction = enclosingBlockScope->asFunction()) { - if (!enclosingFunction->name()) - enclosingBlockScope = enclosingBlockScope->enclosingScope(); - } - } - } - return results; -} - -// Resolves auto and decltype initializer string -QList<LookupItem> TypeResolver::resolveDeclInitializer( - CreateBindings &factory, const Declaration *decl, - const QSet<const Declaration* > &declarationsBeingResolved, - const Identifier *id) -{ - const StringLiteral *initializationString = decl->getInitializer(); - if (initializationString == 0) - return QList<LookupItem>(); - - const QByteArray &initializer = - QByteArray::fromRawData(initializationString->chars(), - initializationString->size()).trimmed(); - - // Skip lambda-function initializers - if (initializer.length() > 0 && initializer[0] == '[') - return QList<LookupItem>(); - - TypeOfExpression exprTyper; - exprTyper.setExpandTemplates(true); - Document::Ptr doc = factory.snapshot().document(QString::fromLocal8Bit(decl->fileName())); - exprTyper.init(doc, factory.snapshot(), factory.sharedFromThis(), declarationsBeingResolved); - - Document::Ptr exprDoc = - documentForExpression(exprTyper.preprocessedExpression(initializer)); - factory.addExpressionDocument(exprDoc); - exprDoc->check(); - - if (id) { - DeduceAutoCheck deduceAuto(id, exprDoc->translationUnit()); - if (deduceAuto._block) - return QList<LookupItem>(); - } - - return exprTyper(extractExpressionAST(exprDoc), exprDoc, decl->enclosingScope()); -} - -bool TypeResolver::isTypedefWithName(const Declaration *declaration, const Name *name) -{ - if (declaration->isTypedef()) { - const Identifier *identifier = declaration->name()->identifier(); - if (name->identifier()->match(identifier)) - return true; - } - return false; -} - -bool TypeResolver::findTypedef(const QList<LookupItem> &namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet<Symbol *> &visited) -{ - foreach (const LookupItem &it, namedTypeItems) { - Symbol *declaration = it.declaration(); - if (!declaration) - continue; - if (Template *specialization = declaration->asTemplate()) - declaration = specialization->declaration(); - if (!declaration || (!declaration->isTypedef() && !declaration->type().isDecltype())) - continue; - if (visited.contains(declaration)) - break; - visited.insert(declaration); - - // continue working with the typedefed type and scope - if (type->type()->isPointerType()) { - *type = FullySpecifiedType( - _factory.control()->pointerType(declaration->type())); - } else if (type->type()->isReferenceType()) { - *type = FullySpecifiedType( - _factory.control()->referenceType( - declaration->type(), - declaration->type()->asReferenceType()->isRvalueReference())); - } else if (declaration->type().isDecltype()) { - Declaration *decl = declaration->asDeclaration(); - const QList<LookupItem> resolved = - resolveDeclInitializer(_factory, decl, QSet<const Declaration* >() << decl); - if (!resolved.isEmpty()) { - LookupItem item = resolved.first(); - *type = item.type(); - *scope = item.scope(); - _binding = item.binding(); - return true; - } - } else { - *type = it.type(); - } - - *scope = it.scope(); - _binding = it.binding(); - return true; - } - - return false; -} - -} // namespace CPlusPlus diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri index ebb5ad07f1..0e5bed22e0 100644 --- a/src/libs/cplusplus/cplusplus-lib.pri +++ b/src/libs/cplusplus/cplusplus-lib.pri @@ -36,7 +36,6 @@ HEADERS += \ $$PWD/NamePrettyPrinter.h \ $$PWD/TypeOfExpression.h \ $$PWD/TypePrettyPrinter.h \ - $$PWD/TypeResolver.h \ $$PWD/ResolveExpression.h \ $$PWD/LookupItem.h \ $$PWD/AlreadyConsideredClassContainer.h \ @@ -45,6 +44,7 @@ HEADERS += \ $$PWD/ASTPath.h \ $$PWD/SnapshotSymbolVisitor.h \ $$PWD/SymbolNameVisitor.h \ + $$PWD/DeprecatedGenTemplateInstance.h \ $$PWD/FindUsages.h \ $$PWD/DependencyTable.h \ $$PWD/PreprocessorClient.h \ @@ -67,7 +67,6 @@ SOURCES += \ $$PWD/NamePrettyPrinter.cpp \ $$PWD/TypeOfExpression.cpp \ $$PWD/TypePrettyPrinter.cpp \ - $$PWD/TypeResolver.cpp \ $$PWD/ResolveExpression.cpp \ $$PWD/LookupItem.cpp \ $$PWD/LookupContext.cpp \ @@ -75,6 +74,7 @@ SOURCES += \ $$PWD/ASTPath.cpp \ $$PWD/SnapshotSymbolVisitor.cpp \ $$PWD/SymbolNameVisitor.cpp \ + $$PWD/DeprecatedGenTemplateInstance.cpp \ $$PWD/FindUsages.cpp \ $$PWD/DependencyTable.cpp \ $$PWD/PreprocessorClient.cpp \ diff --git a/src/libs/cplusplus/cplusplus.qbs b/src/libs/cplusplus/cplusplus.qbs index 8ac08217eb..dd4012d633 100644 --- a/src/libs/cplusplus/cplusplus.qbs +++ b/src/libs/cplusplus/cplusplus.qbs @@ -96,6 +96,7 @@ QtcLibrary { "CppRewriter.cpp", "CppRewriter.h", "cppmodelmanagerbase.cpp", "cppmodelmanagerbase.h", "DependencyTable.cpp", "DependencyTable.h", + "DeprecatedGenTemplateInstance.cpp", "DeprecatedGenTemplateInstance.h", "ExpressionUnderCursor.cpp", "ExpressionUnderCursor.h", "FastPreprocessor.cpp", "FastPreprocessor.h", "FindUsages.cpp", "FindUsages.h", @@ -116,7 +117,6 @@ QtcLibrary { "SymbolNameVisitor.cpp", "SymbolNameVisitor.h", "TypeOfExpression.cpp", "TypeOfExpression.h", "TypePrettyPrinter.cpp", "TypePrettyPrinter.h", - "TypeResolver.cpp", "TypeResolver.h", "cplusplus.qrc", "findcdbbreakpoint.cpp", "findcdbbreakpoint.h", "pp-cctype.h", diff --git a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp index f7edb410d2..cf1dde0819 100644 --- a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp +++ b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp @@ -795,7 +795,7 @@ static void buildContextProperties( Scope *typeScope = result.scope(); if (!typeScope) typeScope = scope; // incorrect but may be an ok fallback - LookupScope *binding = typeOf.context().lookupType(namedType->name(), typeScope); + ClassOrNamespace *binding = typeOf.context().lookupType(namedType->name(), typeScope); if (binding && !binding->symbols().isEmpty()) { // find the best 'Class' symbol for (int i = binding->symbols().size() - 1; i >= 0; --i) { diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index b7f2a915c2..098138eb6d 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -1453,9 +1453,10 @@ void CppQmlTypes::load(const QString &originId, const T &fakeMetaObjects, const object->setPrototype(proto); } } + // explicitly instantiate load for list and hash -template void CppQmlTypes::load< QList<FakeMetaObject::ConstPtr> >(const QString &, const QList<FakeMetaObject::ConstPtr> &, const QString &); -template void CppQmlTypes::load< QHash<QString, FakeMetaObject::ConstPtr> >(const QString &, const QHash<QString, FakeMetaObject::ConstPtr> &, const QString &); +template QMLJS_EXPORT void CppQmlTypes::load< QList<FakeMetaObject::ConstPtr> >(const QString &, const QList<FakeMetaObject::ConstPtr> &, const QString &); +template QMLJS_EXPORT void CppQmlTypes::load< QHash<QString, FakeMetaObject::ConstPtr> >(const QString &, const QHash<QString, FakeMetaObject::ConstPtr> &, const QString &); QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version) { diff --git a/src/libs/sqlite/utf8string.cpp b/src/libs/sqlite/utf8string.cpp index b4492a9d19..c8cbaea223 100644 --- a/src/libs/sqlite/utf8string.cpp +++ b/src/libs/sqlite/utf8string.cpp @@ -158,6 +158,11 @@ bool Utf8String::endsWith(const Utf8String &text) const return byteArray.endsWith(text.byteArray); } +bool Utf8String::isNull() const +{ + return byteArray.isNull(); +} + bool Utf8String::isEmpty() const { return byteArray.isEmpty(); diff --git a/src/libs/sqlite/utf8string.h b/src/libs/sqlite/utf8string.h index 52c6f46758..c6adfc9371 100644 --- a/src/libs/sqlite/utf8string.h +++ b/src/libs/sqlite/utf8string.h @@ -86,6 +86,7 @@ public: bool startsWith(const char *text) const; bool startsWith(char character) const; bool endsWith(const Utf8String &text) const; + bool isNull() const; bool isEmpty() const; bool hasContent() const; diff --git a/src/libs/ssh/sshkeygenerator.cpp b/src/libs/ssh/sshkeygenerator.cpp index 1c6e22db03..6f1800e90d 100644 --- a/src/libs/ssh/sshkeygenerator.cpp +++ b/src/libs/ssh/sshkeygenerator.cpp @@ -173,7 +173,7 @@ void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key) void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key) { QList<BigInt> params; - const char *label; + const char *label = ""; switch (m_type) { case Rsa: { const QSharedPointer<RSA_PrivateKey> rsaKey @@ -197,6 +197,7 @@ void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key) case Ecdsa: params << key.dynamicCast<ECDSA_PrivateKey>()->private_value(); label = "EC PRIVATE KEY"; + break; } DER_Encoder encoder; diff --git a/src/libs/timeline/qml/CategoryLabel.qml b/src/libs/timeline/qml/CategoryLabel.qml index 984d23519f..a822ad835d 100644 --- a/src/libs/timeline/qml/CategoryLabel.qml +++ b/src/libs/timeline/qml/CategoryLabel.qml @@ -63,6 +63,7 @@ Item { cursorShape: dragging ? Qt.ClosedHandCursor : Qt.OpenHandCursor drag.minimumY: dragging ? 0 : -dragOffset // Account for parent change below drag.maximumY: draggerParent.height - (dragging ? 0 : dragOffset) + drag.axis: Drag.YAxis } DropArea { diff --git a/src/libs/timeline/qml/TimelineLabels.qml b/src/libs/timeline/qml/TimelineLabels.qml index ba3f883a42..c8eb63719b 100644 --- a/src/libs/timeline/qml/TimelineLabels.qml +++ b/src/libs/timeline/qml/TimelineLabels.qml @@ -102,7 +102,7 @@ Flickable { draggerParent: categories width: 150 height: parent.height - dragOffset: parent.y + dragOffset: loader.y onDropped: { categories.moveCategories(sourceIndex, targetIndex); diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 997f4c2f76..4288979395 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -250,6 +250,10 @@ PathChooser::PathChooser(QWidget *parent) : PathChooser::~PathChooser() { + // Since it is our focusProxy it can receive focus-out and emit the signal + // even when the possible ancestor-receiver is in mid of its destruction. + disconnect(d->m_lineEdit, &QLineEdit::editingFinished, this, &PathChooser::editingFinished); + delete d; } diff --git a/src/plugins/baremetal/gdbserverprovider.cpp b/src/plugins/baremetal/gdbserverprovider.cpp index 5f32c7efbf..cdb88987d4 100644 --- a/src/plugins/baremetal/gdbserverprovider.cpp +++ b/src/plugins/baremetal/gdbserverprovider.cpp @@ -67,7 +67,7 @@ GdbServerProvider::GdbServerProvider(const QString &id) } GdbServerProvider::GdbServerProvider(const GdbServerProvider &other) - : m_id(other.m_id) + : m_id(createId(other.m_id)) , m_startupMode(other.m_startupMode) , m_initCommands(other.m_initCommands) , m_resetCommands(other.m_resetCommands) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index fd9064a3f5..28c223d80a 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -41,6 +41,8 @@ #include <cpptools/cppprojects.h> #include <cpptools/cppworkingcopy.h> +#include <projectexplorer/projectexplorerconstants.h> + #include <utils/qtcassert.h> #include <QDir> @@ -122,7 +124,7 @@ public: optionsBuilder.addToolchainAndProjectDefines(); - optionsBuilder.addResourceDirOptions(); + optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions(); optionsBuilder.addWrappedQtHeadersIncludePath(); optionsBuilder.addHeaderPathOptions(); optionsBuilder.addProjectConfigFileInclude(); @@ -154,7 +156,21 @@ private: return false; } - void addResourceDirOptions() + void addPredefinedMacrosAndHeaderPathsOptions() + { + if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) + addPredefinedMacrosAndHeaderPathsOptionsForMsvc(); + else + addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc(); + } + + void addPredefinedMacrosAndHeaderPathsOptionsForMsvc() + { + add(QLatin1String("-nostdinc")); + add(QLatin1String("-undef")); + } + + void addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc() { static const QString resourceDir = getResourceDir(); if (!resourceDir.isEmpty()) { diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 81c7dc7158..2abdef298b 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -387,7 +387,7 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit) } else if (functionDefinitionSymbol) { const Snapshot snapshot = d->m_modelManager->snapshot(); LookupContext context(d->m_lastSemanticInfo.doc, snapshot); - LookupScope *binding = context.lookupType(functionDefinitionSymbol); + ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol); const QList<LookupItem> declarations = context.lookup(functionDefinitionSymbol->name(), functionDefinitionSymbol->enclosingScope()); diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cppeditor/cppelementevaluator.cpp index 97b25d723f..6740b935cc 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cppeditor/cppelementevaluator.cpp @@ -331,10 +331,10 @@ bool CppClass::operator==(const CppClass &other) void CppClass::lookupBases(Symbol *declaration, const LookupContext &context) { - typedef QPair<LookupScope *, CppClass *> Data; + typedef QPair<ClassOrNamespace *, CppClass *> Data; - if (LookupScope *clazz = context.lookupType(declaration)) { - QSet<LookupScope *> visited; + if (ClassOrNamespace *clazz = context.lookupType(declaration)) { + QSet<ClassOrNamespace *> visited; QQueue<Data> q; q.enqueue(qMakePair(clazz, this)); @@ -342,8 +342,8 @@ void CppClass::lookupBases(Symbol *declaration, const LookupContext &context) Data current = q.dequeue(); clazz = current.first; visited.insert(clazz); - const QList<LookupScope *> &bases = clazz->usings(); - foreach (LookupScope *baseClass, bases) { + const QList<ClassOrNamespace *> &bases = clazz->usings(); + foreach (ClassOrNamespace *baseClass, bases) { const QList<Symbol *> &symbols = baseClass->symbols(); foreach (Symbol *symbol, symbols) { if (symbol->isClass() && ( @@ -433,7 +433,7 @@ CppVariable::CppVariable(Symbol *declaration, const LookupContext &context, Scop } if (typeName) { - if (LookupScope *clazz = context.lookupType(typeName, scope)) { + if (ClassOrNamespace *clazz = context.lookupType(typeName, scope)) { if (!clazz->symbols().isEmpty()) { Overview overview; Symbol *symbol = clazz->symbols().at(0); diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index a166e8d641..407252ca50 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -38,7 +38,6 @@ #include <cplusplus/ExpressionUnderCursor.h> #include <cplusplus/ResolveExpression.h> #include <cplusplus/SimpleLexer.h> -#include <cplusplus/Templates.h> #include <cplusplus/TypeOfExpression.h> #include <cpptools/cppmodelmanager.h> #include <cpptools/functionutils.h> @@ -184,7 +183,7 @@ Class *VirtualFunctionHelper::staticClassOfFunctionCallExpression_internal() con const QList<LookupItem> items = m_typeOfExpression(memberAccessAST->base_expression, m_expressionDocument, m_scope); ResolveExpression resolveExpression(m_typeOfExpression.context()); - LookupScope *binding = resolveExpression.baseExpression(items, m_accessTokenKind); + ClassOrNamespace *binding = resolveExpression.baseExpression(items, m_accessTokenKind); if (binding) { if (Class *klass = binding->rootClass()) { result = klass; diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index dfb0b1018a..4c359ed9b6 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -607,7 +607,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse SubstitutionEnvironment env; env.setContext(sourceContext); env.switchScope(sourceFunction->enclosingScope()); - LookupScope *targetCoN = targetContext.lookupType(targetFunction->enclosingScope()); + ClassOrNamespace *targetCoN = targetContext.lookupType(targetFunction->enclosingScope()); if (!targetCoN) targetCoN = targetContext.globalNamespace(); UseMinimalNames q(targetCoN); @@ -653,7 +653,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse SubstitutionEnvironment env; env.setContext(sourceContext); env.switchScope(sourceFunction); - LookupScope *targetCoN = targetContext.lookupType(targetFunction); + ClassOrNamespace *targetCoN = targetContext.lookupType(targetFunction); if (!targetCoN) targetCoN = targetContext.globalNamespace(); UseMinimalNames q(targetCoN); diff --git a/src/plugins/cppeditor/cppinsertvirtualmethods.cpp b/src/plugins/cppeditor/cppinsertvirtualmethods.cpp index 711c1b056d..55ac472eec 100644 --- a/src/plugins/cppeditor/cppinsertvirtualmethods.cpp +++ b/src/plugins/cppeditor/cppinsertvirtualmethods.cpp @@ -567,15 +567,15 @@ public: // Determine base classes QList<const Class *> baseClasses; - QQueue<LookupScope *> baseClassQueue; - QSet<LookupScope *> visitedBaseClasses; - if (LookupScope *clazz = interface.context().lookupType(m_classAST->symbol)) + QQueue<ClassOrNamespace *> baseClassQueue; + QSet<ClassOrNamespace *> visitedBaseClasses; + if (ClassOrNamespace *clazz = interface.context().lookupType(m_classAST->symbol)) baseClassQueue.enqueue(clazz); while (!baseClassQueue.isEmpty()) { - LookupScope *clazz = baseClassQueue.dequeue(); + ClassOrNamespace *clazz = baseClassQueue.dequeue(); visitedBaseClasses.insert(clazz); - const QList<LookupScope *> bases = clazz->usings(); - foreach (LookupScope *baseClass, bases) { + const QList<ClassOrNamespace *> bases = clazz->usings(); + foreach (ClassOrNamespace *baseClass, bases) { foreach (Symbol *symbol, baseClass->symbols()) { Class *base = symbol->asClass(); if (base @@ -769,7 +769,7 @@ public: const LookupContext targetContext(headerFile->cppDocument(), snapshot()); const Class *targetClass = m_classAST->symbol; - LookupScope *targetCoN = targetContext.lookupType(targetClass->enclosingScope()); + ClassOrNamespace *targetCoN = targetContext.lookupType(targetClass->enclosingScope()); if (!targetCoN) targetCoN = targetContext.globalNamespace(); UseMinimalNames useMinimalNames(targetCoN); @@ -866,7 +866,7 @@ public: implementationDoc->translationUnit()->getPosition(insertPos, &line, &column); Scope *targetScope = implementationDoc->scopeAt(line, column); const LookupContext targetContext(implementationDoc, snapshot()); - LookupScope *targetCoN = targetContext.lookupType(targetScope); + ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope); if (!targetCoN) targetCoN = targetContext.globalNamespace(); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 176afcb7f9..9ef84adad2 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -219,7 +219,7 @@ Class *isMemberFunction(const LookupContext &context, Function *function) if (!q->base()) return 0; - if (LookupScope *binding = context.lookupType(q->base(), enclosingScope)) { + if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) { foreach (Symbol *s, binding->symbols()) { if (Class *matchingClass = s->asClass()) return matchingClass; @@ -257,7 +257,7 @@ Namespace *isNamespaceFunction(const LookupContext &context, Function *function) if (!q->base()) return 0; - if (LookupScope *binding = context.lookupType(q->base(), enclosingScope)) { + if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) { foreach (Symbol *s, binding->symbols()) { if (Namespace *matchingNamespace = s->asNamespace()) return matchingNamespace; @@ -1331,7 +1331,7 @@ void TranslateStringLiteral::match(const CppQuickFixInterface &interface, for (int i = path.size() - 1; i >= 0; --i) { if (FunctionDefinitionAST *definition = path.at(i)->asFunctionDefinition()) { Function *function = definition->symbol; - LookupScope *b = interface.context().lookupType(function); + ClassOrNamespace *b = interface.context().lookupType(function); if (b) { // Do we have a tr function? foreach (const LookupItem &r, b->find(trName)) { @@ -1592,7 +1592,7 @@ public: SubstitutionEnvironment env; env.setContext(context()); env.switchScope(result.first().scope()); - LookupScope *con = typeOfExpression.context().lookupType(scope); + ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); if (!con) con = typeOfExpression.context().globalNamespace(); UseMinimalNames q(con); @@ -2284,7 +2284,7 @@ Enum *findEnum(const QList<LookupItem> &results, const LookupContext &ctxt) if (Enum *e = type->asEnumType()) return e; if (const NamedType *namedType = type->asNamedType()) { - if (LookupScope *con = ctxt.lookupType(namedType->name(), result.scope())) { + if (ClassOrNamespace *con = ctxt.lookupType(namedType->name(), result.scope())) { const QList<Enum *> enums = con->unscopedEnums(); const Name *referenceName = namedType->name(); if (const QualifiedNameId *qualifiedName = referenceName->asQualifiedNameId()) @@ -2581,7 +2581,7 @@ public: Document::Ptr targetDoc = targetFile->cppDocument(); Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column()); LookupContext targetContext(targetDoc, snapshot()); - LookupScope *targetCoN = targetContext.lookupType(targetScope); + ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope); if (!targetCoN) targetCoN = targetContext.globalNamespace(); @@ -3215,7 +3215,7 @@ public: SubstitutionEnvironment env; env.setContext(context()); env.switchScope(refFunc); - LookupScope *targetCoN = context().lookupType(refFunc->enclosingScope()); + ClassOrNamespace *targetCoN = context().lookupType(refFunc->enclosingScope()); if (!targetCoN) targetCoN = context().globalNamespace(); UseMinimalNames subs(targetCoN); @@ -4644,7 +4644,7 @@ QString definitionSignature(const CppQuickFixInterface *assist, QTC_ASSERT(func, return QString()); LookupContext cppContext(targetFile->cppDocument(), assist->snapshot()); - LookupScope *cppCoN = cppContext.lookupType(scope); + ClassOrNamespace *cppCoN = cppContext.lookupType(scope); if (!cppCoN) cppCoN = cppContext.globalNamespace(); SubstitutionEnvironment env; @@ -5125,7 +5125,7 @@ public: SubstitutionEnvironment env; env.setContext(context()); env.switchScope(result.first().scope()); - LookupScope *con = typeOfExpression.context().lookupType(scope); + ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); if (!con) con = typeOfExpression.context().globalNamespace(); UseMinimalNames q(con); @@ -5724,7 +5724,7 @@ PointerType *determineConvertedType(NamedType *namedType, const LookupContext &c { if (!namedType) return 0; - if (LookupScope *binding = context.lookupType(namedType->name(), scope)) { + if (ClassOrNamespace *binding = context.lookupType(namedType->name(), scope)) { if (Symbol *objectClassSymbol = skipForwardDeclarations(binding->symbols())) { if (Class *klass = objectClassSymbol->asClass()) { for (auto it = klass->memberBegin(), end = klass->memberEnd(); it != end; ++it) { @@ -5782,7 +5782,7 @@ Class *senderOrReceiverClass(const CppQuickFixInterface &interface, NamedType *objectType = objectTypeBase->asNamedType(); QTC_ASSERT(objectType, return 0); - LookupScope *objectClassCON = context.lookupType(objectType->name(), objectPointerScope); + ClassOrNamespace *objectClassCON = context.lookupType(objectType->name(), objectPointerScope); QTC_ASSERT(objectClassCON, return 0); QTC_ASSERT(!objectClassCON->symbols().isEmpty(), return 0); @@ -5834,7 +5834,7 @@ bool findConnectReplacement(const CppQuickFixInterface &interface, // Minimize qualification Control *control = context.bindings()->control().data(); - LookupScope *functionCON = context.lookupParent(scope); + ClassOrNamespace *functionCON = context.lookupParent(scope); const Name *shortName = LookupContext::minimalName(method, functionCON, control); if (!shortName->asQualifiedNameId()) shortName = control->qualifiedNameId(classOfMethod->name(), shortName); diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp index 61828f1631..3b4ba8baf5 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp @@ -152,8 +152,8 @@ public: QTC_ASSERT(m_params.staticClass, return 0); QTC_ASSERT(!m_params.snapshot.isEmpty(), return 0); - Class *functionsClass = m_finder.findMatchingClassDeclaration( - m_params.function, m_params.snapshot, &m_params.typeOfExpression->context()); + Class *functionsClass = m_finder.findMatchingClassDeclaration(m_params.function, + m_params.snapshot); if (!functionsClass) return 0; diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 956b02b5d9..fbcda2628e 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -972,20 +972,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data() "template<class $T>\n" "using Foo = Bar<@T>;\n" ); - - QTest::newRow("qualifiedNames") << _( - "struct C\n" - "{\n" - " struct Nested { int $member; };\n" - " void f();\n" - "};\n" - "\n" - "void C::f()\n" - "{\n" - " C::Nested object;\n" - " object.@member;\n" - "}\n" - ); } void CppEditorPlugin::test_FollowSymbolUnderCursor() @@ -1390,7 +1376,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_data() "template <class T> struct A { virtual void virt() {} };\n" "void f(A<int> *l) { l->$@virt(); }\n") << (OverrideItemList() - << OverrideItem(QLatin1String("A<int>::virt"), 1)); + << OverrideItem(QLatin1String("A::virt"), 1)); /// Check: Static type is nicely resolved, especially for QSharedPointers. QTest::newRow("QSharedPointer") << _( diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp index acf3d5c86f..cbc6baf75e 100644 --- a/src/plugins/cpptools/cppchecksymbols.cpp +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -669,7 +669,7 @@ bool CheckSymbols::visit(NewExpressionAST *ast) if (highlightCtorDtorAsType) { accept(ast->new_type_id); } else { - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; NameAST *nameAST = 0; if (ast->new_type_id) { for (SpecifierListAST *it = ast->new_type_id->type_specifier_list; it; it = it->next) { @@ -735,7 +735,7 @@ void CheckSymbols::checkNamespace(NameAST *name) unsigned line, column; getTokenStartPosition(name->firstToken(), &line, &column); - if (LookupScope *b = _context.lookupType(name->name, enclosingScope())) { + if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope())) { foreach (Symbol *s, b->symbols()) { if (s->isNamespace()) return; @@ -768,14 +768,14 @@ bool CheckSymbols::hasVirtualDestructor(Class *klass) const return false; } -bool CheckSymbols::hasVirtualDestructor(LookupScope *binding) const +bool CheckSymbols::hasVirtualDestructor(ClassOrNamespace *binding) const { - QSet<LookupScope *> processed; - QList<LookupScope *> todo; + QSet<ClassOrNamespace *> processed; + QList<ClassOrNamespace *> todo; todo.append(binding); while (!todo.isEmpty()) { - LookupScope *b = todo.takeFirst(); + ClassOrNamespace *b = todo.takeFirst(); if (b && !processed.contains(b)) { processed.insert(b); foreach (Symbol *s, b->symbols()) { @@ -857,7 +857,7 @@ bool CheckSymbols::visit(QualifiedNameAST *ast) { if (ast->name) { - LookupScope *binding = checkNestedName(ast); + ClassOrNamespace *binding = checkNestedName(ast); if (binding && ast->unqualified_name) { if (ast->unqualified_name->asDestructorName() != 0) { @@ -886,9 +886,9 @@ bool CheckSymbols::visit(QualifiedNameAST *ast) return false; } -LookupScope *CheckSymbols::checkNestedName(QualifiedNameAST *ast) +ClassOrNamespace *CheckSymbols::checkNestedName(QualifiedNameAST *ast) { - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; if (ast->name) { if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) { @@ -954,7 +954,7 @@ bool CheckSymbols::visit(MemInitializerAST *ast) { if (FunctionDefinitionAST *enclosingFunction = enclosingFunctionDefinition()) { if (ast->name && enclosingFunction->symbol) { - if (LookupScope *binding = _context.lookupType(enclosingFunction->symbol)) { + if (ClassOrNamespace *binding = _context.lookupType(enclosingFunction->symbol)) { foreach (Symbol *s, binding->symbols()) { if (Class *klass = s->asClass()) { NameAST *nameAST = ast->name; @@ -1157,7 +1157,7 @@ void CheckSymbols::addUse(const Result &use) _usages.append(use); } -void CheckSymbols::addType(LookupScope *b, NameAST *ast) +void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast) { unsigned startToken; if (!b || !acceptName(ast, &startToken)) @@ -1296,8 +1296,12 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST isConstructor = isConstructorDeclaration(c); Function *funTy = c->type()->asFunctionType(); - if (!funTy) // Template function has an overridden type - funTy = r.type()->asFunctionType(); + if (!funTy) { + //Try to find a template function + if (Template * t = r.type()->asTemplateType()) + if ((c = t->declaration())) + funTy = c->type()->asFunctionType(); + } if (!funTy || funTy->isAmbiguous()) continue; // TODO: add diagnostic messages and color call-operators calls too? diff --git a/src/plugins/cpptools/cppchecksymbols.h b/src/plugins/cpptools/cppchecksymbols.h index 11cde21146..f874c16323 100644 --- a/src/plugins/cpptools/cppchecksymbols.h +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -105,7 +105,7 @@ protected: const QList<Result> &otherUses); bool hasVirtualDestructor(CPlusPlus::Class *klass) const; - bool hasVirtualDestructor(CPlusPlus::LookupScope *binding) const; + bool hasVirtualDestructor(CPlusPlus::ClassOrNamespace *binding) const; bool warning(unsigned line, unsigned column, const QString &text, unsigned length = 0); bool warning(CPlusPlus::AST *ast, const QString &text); @@ -119,13 +119,13 @@ protected: void checkNamespace(CPlusPlus::NameAST *name); void checkName(CPlusPlus::NameAST *ast, CPlusPlus::Scope *scope = 0); - CPlusPlus::LookupScope *checkNestedName(CPlusPlus::QualifiedNameAST *ast); + CPlusPlus::ClassOrNamespace *checkNestedName(CPlusPlus::QualifiedNameAST *ast); void addUse(const Result &use); void addUse(unsigned tokenIndex, Kind kind); void addUse(CPlusPlus::NameAST *name, Kind kind); - void addType(CPlusPlus::LookupScope *b, CPlusPlus::NameAST *ast); + void addType(CPlusPlus::ClassOrNamespace *b, CPlusPlus::NameAST *ast); bool maybeAddTypeOrStatic(const QList<CPlusPlus::LookupItem> &candidates, CPlusPlus::NameAST *ast); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 02cc06848f..7deb309f58 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -328,17 +328,16 @@ void CppToolsPlugin::test_completion() actualCompletions.sort(); expectedCompletions.sort(); - QEXPECT_FAIL("template_as_base: typedef not available in derived", - "We can live with that...", Abort); - QEXPECT_FAIL("template_specialization_with_reference", "test of reverted change", Abort); - QEXPECT_FAIL("specialization_multiple_arguments", "test of reverted change", Abort); - QEXPECT_FAIL("specialization_with_default_value", "test of reverted change", Abort); + QEXPECT_FAIL("template_as_base: explicit typedef from base", "QTCREATORBUG-14218", Abort); QEXPECT_FAIL("enum_in_function_in_struct_in_function", "QTCREATORBUG-13757", Abort); QEXPECT_FAIL("enum_in_function_in_struct_in_function_cxx11", "QTCREATORBUG-13757", Abort); QEXPECT_FAIL("enum_in_function_in_struct_in_function_anon", "QTCREATORBUG-13757", Abort); QEXPECT_FAIL("enum_in_class_accessed_in_member_func_cxx11", "QTCREATORBUG-13757", Abort); QEXPECT_FAIL("enum_in_class_accessed_in_member_func_inline_cxx11", "QTCREATORBUG-13757", Abort); - QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort); + QEXPECT_FAIL("pointer_indirect_specialization", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("pointer_indirect_specialization_typedef", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("pointer_indirect_specialization_double_indirection", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort); QCOMPARE(actualCompletions, expectedCompletions); } @@ -802,21 +801,6 @@ void CppToolsPlugin::test_completion_data() << QLatin1String("Data") << QLatin1String("dataMember")); - QTest::newRow("explicit_instantiation") << _( - "template<class T>\n" - "struct Foo { T bar; };\n" - "\n" - "template class Foo<int>;\n" - "\n" - "void func()\n" - "{\n" - " Foo<int> foo;\n" - " @\n" - "}\n" - ) << _("foo.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - QTest::newRow("use_global_identifier_as_base_class: derived as global and base as global") << _( "struct Global\n" "{\n" @@ -1327,28 +1311,21 @@ void CppToolsPlugin::test_completion_data() << QLatin1String("Template1")); QTest::newRow("template_specialization_with_pointer") << _( - "template <typename T> struct Temp { T variable; };\n" - "template <typename T> struct Temp<T *> { T *pointer; };\n" - "void func()\n" + "template <typename T>\n" + "struct Template\n" "{\n" - " Temp<int*> templ;\n" - " @\n" - "}" - ) << _("templ.") << (QStringList() - << QLatin1String("Temp") - << QLatin1String("pointer")); - - QTest::newRow("template_specialization_with_reference") << _( - "template <typename T> struct Temp { T variable; };\n" - "template <typename T> struct Temp<T &> { T reference; };\n" - "void func()\n" + " T variable;\n" + "};\n" + "template <typename T>\n" + "struct Template<T *>\n" "{\n" - " Temp<int&> templ;\n" - " @\n" - "}" + " T *pointer;\n" + "};\n" + "Template<int*> templ;\n" + "@\n" ) << _("templ.") << (QStringList() - << QLatin1String("Temp") - << QLatin1String("reference")); + << QLatin1String("Template") + << QLatin1String("pointer")); QTest::newRow("typedef_using_templates1") << _( "namespace NS1\n" @@ -1572,29 +1549,6 @@ void CppToolsPlugin::test_completion_data() << QLatin1String("C") << QLatin1String("m")); - QTest::newRow("type_and_using_declaration: type in nested namespace and using in global") << _( - "namespace Ns {\n" - "namespace Nested {\n" - "struct Foo\n" - "{\n" - " void func();\n" - " int m_bar;\n" - "};\n" - "}\n" - "}\n" - "\n" - "using namespace Ns::Nested;\n" - "\n" - "namespace Ns\n" - "{\n" - "void Foo::func()\n" - "{\n" - " @\n" - "}\n" - "}\n" - ) << _("m_") << (QStringList() - << QLatin1String("m_bar")); - QTest::newRow("instantiate_template_with_anonymous_class") << _( "template <typename T>\n" "struct S\n" @@ -2568,21 +2522,6 @@ void CppToolsPlugin::test_completion_data() ) << _("ar") << (QStringList() << QLatin1String("arg1")); - QTest::newRow("local_typedef_access_in_lambda") << _( - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " typedef Foo F;\n" - " []() {\n" - " F f;\n" - " @\n" - " };\n" - "}\n" - ) << _("f.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - QTest::newRow("default_arguments_for_class_templates_and_base_class_QTCREATORBUG-12605") << _( "struct Foo { int foo; };\n" "template <typename T = Foo>\n" @@ -2689,78 +2628,6 @@ void CppToolsPlugin::test_completion_data() ) << _("s.") << (QStringList() << QLatin1String("S")); - QTest::newRow("partial_specialization") << _( - "struct b {};\n" - "template<class X, class Y> struct s { float f; };\n" - "template<class X> struct s<X, b> { int i; };\n" - "\n" - "void f()\n" - "{\n" - " s<int, b> var;\n" - " @\n" - "}\n" - ) << _("var.") << (QStringList() - << QLatin1String("i") - << QLatin1String("s")); - -// QTest::newRow("partial_specialization_with_pointer") << _( -// "struct b {};\n" -// "struct a : b {};\n" -// "template<class X, class Y> struct s { float f; };\n" -// "template<class X> struct s<X, b*> { int i; };\n" -// "template<class X> struct s<X, a*> { char j; };\n" -// "\n" -// "void f()\n" -// "{\n" -// " s<int, a*> var;\n" -// " @\n" -// "}\n" -// ) << _("var.") << (QStringList() -// << QLatin1String("j") -// << QLatin1String("s")); - - QTest::newRow("partial_specialization_templated_argument") << _( - "template<class T> struct t {};\n" - "\n" - "template<class> struct s { float f; };\n" - "template<class X> struct s<t<X>> { int i; };\n" - "\n" - "void f()\n" - "{\n" - " s<t<char>> var;\n" - " @\n" - "}\n" - ) << _("var.") << (QStringList() - << QLatin1String("i") - << QLatin1String("s")); - - QTest::newRow("specialization_multiple_arguments") << _( - "class false_type {};\n" - "class true_type {};\n" - "template<class T1, class T2> class and_type { false_type f; };\n" - "template<> class and_type<true_type, true_type> { true_type t; };\n" - "void func()\n" - "{\n" - " and_type<true_type, false_type> a;\n" - " @;\n" - "}\n" - ) << _("a.") << (QStringList() - << QLatin1String("f") - << QLatin1String("and_type")); - - QTest::newRow("specialization_with_default_value") << _( - "class Foo {};\n" - "template<class T1 = Foo> class Temp;\n" - "template<> class Temp<Foo> { int var; };\n" - "void func()\n" - "{\n" - " Temp<> t;\n" - " @\n" - "}\n" - ) << _("t.") << (QStringList() - << QLatin1String("var") - << QLatin1String("Temp")); - QTest::newRow("auto_declaration_in_if_condition") << _( "struct Foo { int bar; };\n" "void fun() {\n" @@ -2966,28 +2833,6 @@ void CppToolsPlugin::test_completion_data() << QLatin1String("Foo") << QLatin1String("bar")); - QTest::newRow("instantiation_of_indirect_typedef") << _( - "template<typename _Tp>\n" - "struct Indirect { _Tp t; };\n" - "\n" - "template<typename T>\n" - "struct Temp\n" - "{\n" - " typedef T MyT;\n" - " typedef Indirect<MyT> indirect;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp<Foo>::indirect i;\n" - " @\n" - "}\n" - ) << _("i.t.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar"));; - QTest::newRow("pointer_indirect_specialization_double_indirection_with_base") << _( "template<typename _Tp>\n" "struct Traits { };\n" @@ -3024,337 +2869,6 @@ void CppToolsPlugin::test_completion_data() ) << _("t.p->") << (QStringList() << QLatin1String("Foo") << QLatin1String("bar")); - - QTest::newRow("recursive_instantiation_of_template_type") << _( - "template<typename _Tp>\n" - "struct Temp { typedef _Tp value_type; };\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp<Temp<Foo> >::value_type::value_type *p;\n" - " @\n" - "}\n" - ) << _("p->") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("recursive_instantiation_of_template_type_2") << _( - "template<typename _Tp>\n" - "struct Temp { typedef _Tp value_type; };\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp<Temp<Foo>::value_type>::value_type *p;\n" - " @\n" - "}\n" - ) << _("p->") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("template_using_instantiation") << _( - "template<typename _Tp>\n" - "using T = _Tp;\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " T<Foo> p;\n" - " @\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_template_using_instantiation") << _( - "struct Parent {\n" - " template<typename _Tp>\n" - " using T = _Tp;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Parent::T<Foo> p;\n" - " @;\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_template_using_instantiation_in_template_class") << _( - "template<typename ParentT>\n" - "struct Parent {\n" - " template<typename _Tp>\n" - " using T = _Tp;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Parent<Foo>::T<Foo> p;\n" - " @;\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("recursive_nested_template_using_instantiation") << _( - "struct Foo { int bar; };\n" - "\n" - "struct A { typedef Foo value_type; };\n" - "\n" - "template<typename T>\n" - "struct Traits\n" - "{\n" - " typedef Foo value_type;\n" - "\n" - " template<typename _Tp>\n" - " using U = T;\n" - "};\n" - "\n" - "template<typename T>\n" - "struct Temp\n" - "{\n" - " typedef Traits<T> TraitsT;\n" - " typedef typename T::value_type value_type;\n" - " typedef typename TraitsT::template U<Foo> rebind;\n" - "};\n" - "\n" - "void func()\n" - "{\n" - " typename Temp<typename Temp<A>::rebind>::value_type p;\n" - " @\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("qualified_name_in_nested_type") << _( - "template<typename _Tp>\n" - "struct Temp {\n" - " struct Nested {\n" - " typedef typename _Tp::Nested2 N;\n" - " };\n" - "};\n" - "\n" - "struct Foo {\n" - " struct Nested2 {\n" - " int bar;\n" - " };\n" - "};\n" - "\n" - "void func()\n" - "{\n" - " Temp<Foo>::Nested::N p;\n" - " @;\n" - "}\n" - ) << _("p.") << (QStringList() - << QLatin1String("Nested2") - << QLatin1String("bar")); - - QTest::newRow("simple_decltype_declaration") << _( - "struct Foo { int bar; };\n" - "Foo foo;\n" - "void fun() {\n" - " decltype(foo) s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("typedefed_decltype_declaration") << _( - "struct Foo { int bar; };\n" - "Foo foo;\n" - "typedef decltype(foo) TypedefedFooWithDecltype;\n" - "void fun() {\n" - " TypedefedFooWithDecltype s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_instantiation_typedefed_decltype_declaration") << _( - "template <typename T>\n" - "struct Temp\n" - "{\n" - " struct Nested\n" - " {\n" - " static T f();\n" - " typedef decltype(f()) type;\n" - " };\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void fun()\n" - "{\n" - " Temp<Foo>::Nested::type s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("typedefed_decltype_of_template_function") << _( - "template<typename T>\n" - "static T f();\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void fun()\n" - "{\n" - " decltype(f<Foo>()) s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("nested_instantiation_typedefed_decltype_declaration_of_template_function") << _( - "template <typename T, typename D = T>\n" - "struct Temp\n" - "{\n" - " struct Nested\n" - " {\n" - " template<typename U> static T* __test(...);\n" - " typedef decltype(__test<D>(0)) type;\n" - " };\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp<Foo>::Nested::type s;\n" - " @\n" - "}\n" - ) << _("s.") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); - - QTest::newRow("typedef for templates in namespace") << _( - "namespace N {\n" - "\n" - "struct Data { int x; };\n" - "template <typename T> struct Foo { T member; };\n" - "typedef Foo<Data> Bar;\n" - "\n" - "} // N\n" - "\n" - "\n" - "void f()\n" - "{\n" - " N::Bar o;\n" - " @\n" - "}\n" - ) << _("o.member.") << (QStringList() - << QLatin1String("Data") - << QLatin1String("x")); - - QTest::newRow("std vector") << _( - "namespace std\n" - "{\n" - "template<typename _Tp>\n" - "struct allocator\n" - "{\n" - " typedef _Tp value_type;\n" - "\n" - " template<typename _Tp1>\n" - " struct rebind\n" - " { typedef allocator<_Tp1> other; };\n" - "};\n" - "\n" - "template<typename _Alloc, typename _Tp>\n" - "struct __alloctr_rebind\n" - "{\n" - " typedef typename _Alloc::template rebind<_Tp>::other __type;\n" - "};\n" - "\n" - "template<typename _Alloc>\n" - "struct allocator_traits\n" - "{\n" - " typedef typename _Alloc::value_type value_type;\n" - "\n" - " template<typename _Tp>\n" - " using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;\n" - "};\n" - "\n" - "template<typename _Iterator>\n" - "struct iterator_traits { };\n" - "\n" - "template<typename _Tp>\n" - "struct iterator_traits<_Tp*>\n" - "{\n" - " typedef _Tp* pointer;\n" - "};\n" - "} // namespace std\n" - "\n" - "namespace __gnu_cxx\n" - "{\n" - "template<typename _Alloc>\n" - "struct __alloc_traits\n" - "{\n" - " typedef _Alloc allocator_type;\n" - " typedef std::allocator_traits<_Alloc> _Base_type;\n" - " typedef typename _Alloc::value_type value_type;\n" - "\n" - " static value_type *_S_pointer_helper(...);\n" - " typedef decltype(_S_pointer_helper((_Alloc*)0)) __pointer;\n" - " typedef __pointer pointer;\n" - "\n" - " template<typename _Tp>\n" - " struct rebind\n" - " { typedef typename _Base_type::template rebind_alloc<_Tp> other; };\n" - "};\n" - "\n" - "template<typename _Iterator, typename _Container>\n" - "struct __normal_iterator\n" - "{\n" - " typedef std::iterator_traits<_Iterator> __traits_type;\n" - " typedef typename __traits_type::pointer pointer;\n" - "\n" - " pointer p;\n" - "};\n" - "} // namespace __gnu_cxx\n" - "\n" - "namespace std {\n" - "template<typename _Tp, typename _Alloc>\n" - "struct _Vector_Base\n" - "{\n" - " typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template\n" - " rebind<_Tp>::other _Tp_alloc_type;\n" - " typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer\n" - " pointer;\n" - "};\n" - "\n" - "template<typename _Tp, typename _Alloc = std::allocator<_Tp> >\n" - "struct vector : protected _Vector_Base<_Tp, _Alloc>\n" - "{\n" - " typedef _Vector_Base<_Tp, _Alloc> _Base;\n" - " typedef typename _Base::pointer pointer;\n" - " typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;\n" - "};\n" - "} // namespace std\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " std::vector<Foo>::iterator it;\n" - " @;\n" - "}\n" - ) << _("it.p->") << (QStringList() - << QLatin1String("Foo") - << QLatin1String("bar")); } void CppToolsPlugin::test_completion_member_access_operator() diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index fa7790a915..eec2f2e5fe 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -753,8 +753,8 @@ bool canCompleteClassNameAt2ndOr4thConnectArgument( || eater.eatConnectOpenParenthesisExpressionCommaAmpersandExpressionComma(); } -LookupScope *lookupScopeFromLookupItem(const LookupItem &lookupItem, - const LookupContext &context) +ClassOrNamespace *classOrNamespaceFromLookupItem(const LookupItem &lookupItem, + const LookupContext &context) { const Name *name = 0; @@ -783,7 +783,7 @@ LookupScope *lookupScopeFromLookupItem(const LookupItem &lookupItem, Class *classFromLookupItem(const LookupItem &lookupItem, const LookupContext &context) { - LookupScope *b = lookupScopeFromLookupItem(lookupItem, context); + ClassOrNamespace *b = classOrNamespaceFromLookupItem(lookupItem, context); if (!b) return 0; @@ -796,7 +796,7 @@ Class *classFromLookupItem(const LookupItem &lookupItem, const LookupContext &co const Name *minimalName(Symbol *symbol, Scope *targetScope, const LookupContext &context) { - LookupScope *target = context.lookupType(targetScope); + ClassOrNamespace *target = context.lookupType(targetScope); if (!target) target = context.globalNamespace(); return context.minimalName(symbol, target, context.bindings()->control().data()); @@ -1219,12 +1219,12 @@ bool InternalCppCompletionAssistProcessor::tryObjCCompletion() ty = ty->asPointerType()->elementType().simplified(); if (NamedType *namedTy = ty->asNamedType()) { - LookupScope *binding = lookupContext.lookupType(namedTy->name(), item.scope()); + ClassOrNamespace *binding = lookupContext.lookupType(namedTy->name(), item.scope()); completeObjCMsgSend(binding, false); } } else { if (ObjCClass *clazz = ty->asObjCClassType()) { - LookupScope *binding = lookupContext.lookupType(clazz->name(), item.scope()); + ClassOrNamespace *binding = lookupContext.lookupType(clazz->name(), item.scope()); completeObjCMsgSend(binding, true); } } @@ -1273,7 +1273,7 @@ void InternalCppCompletionAssistProcessor::addCompletionItem(Symbol *symbol, int } } -void InternalCppCompletionAssistProcessor::completeObjCMsgSend(LookupScope *binding, +void InternalCppCompletionAssistProcessor::completeObjCMsgSend(ClassOrNamespace *binding, bool staticClassAccess) { QList<Scope*> memberScopes; @@ -1542,26 +1542,26 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope) return !m_completions.isEmpty(); } - QList<LookupScope *> usingBindings; - LookupScope *currentBinding = 0; + QList<ClassOrNamespace *> usingBindings; + ClassOrNamespace *currentBinding = 0; for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) { if (Block *block = scope->asBlock()) { - if (LookupScope *binding = context.lookupType(scope)) { + if (ClassOrNamespace *binding = context.lookupType(scope)) { for (unsigned i = 0; i < scope->memberCount(); ++i) { Symbol *member = scope->memberAt(i); if (member->isEnum()) { - if (LookupScope *b = binding->findBlock(block)) + if (ClassOrNamespace *b = binding->findBlock(block)) completeNamespace(b); } if (!member->name()) continue; if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) { - if (LookupScope *b = binding->lookupType(u->name())) + if (ClassOrNamespace *b = binding->lookupType(u->name())) usingBindings.append(b); } else if (Class *c = member->asClass()) { if (c->name()->isAnonymousNameId()) { - if (LookupScope *b = binding->findBlock(block)) + if (ClassOrNamespace *b = binding->findBlock(block)) completeClass(b); } } @@ -1588,7 +1588,7 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope) } for (; currentBinding; currentBinding = currentBinding->parent()) { - foreach (LookupScope* u, currentBinding->usings()) + foreach (ClassOrNamespace* u, currentBinding->usings()) usingBindings.append(u); const QList<Symbol *> symbols = currentBinding->symbols(); @@ -1601,7 +1601,7 @@ bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope) } } - foreach (LookupScope *b, usingBindings) + foreach (ClassOrNamespace *b, usingBindings) completeNamespace(b); addKeywords(); @@ -1624,7 +1624,7 @@ bool InternalCppCompletionAssistProcessor::completeMember(const QList<LookupItem if (!m_interface->languageFeatures().objCEnabled) replaceDotForArrow = &m_model->m_replaceDotForArrow; - if (LookupScope *binding = + if (ClassOrNamespace *binding = resolveExpression.baseExpression(baseResults, m_model->m_completionOperator, replaceDotForArrow)) { @@ -1648,27 +1648,27 @@ bool InternalCppCompletionAssistProcessor::completeScope(const QList<LookupItem> Scope *scope = result.scope(); if (NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *b = context.lookupType(namedTy->name(), scope)) { + if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) { completeClass(b); break; } } else if (Class *classTy = ty->asClassType()) { - if (LookupScope *b = context.lookupType(classTy)) { + if (ClassOrNamespace *b = context.lookupType(classTy)) { completeClass(b); break; } // it can be class defined inside a block if (classTy->enclosingScope()->isBlock()) { - if (LookupScope *b = context.lookupType(classTy->name(), classTy->enclosingScope())) { + if (ClassOrNamespace *b = context.lookupType(classTy->name(), classTy->enclosingScope())) { completeClass(b); break; } } } else if (Namespace *nsTy = ty->asNamespaceType()) { - if (LookupScope *b = context.lookupType(nsTy)) { + if (ClassOrNamespace *b = context.lookupType(nsTy)) { completeNamespace(b); break; } @@ -1676,7 +1676,7 @@ bool InternalCppCompletionAssistProcessor::completeScope(const QList<LookupItem> } else if (Template *templ = ty->asTemplateType()) { if (!result.binding()) continue; - if (LookupScope *b = result.binding()->lookupType(templ->name())) { + if (ClassOrNamespace *b = result.binding()->lookupType(templ->name())) { completeClass(b); break; } @@ -1684,16 +1684,16 @@ bool InternalCppCompletionAssistProcessor::completeScope(const QList<LookupItem> } else if (Enum *e = ty->asEnumType()) { // it can be class defined inside a block if (e->enclosingScope()->isBlock()) { - if (LookupScope *b = context.lookupType(e)) { + if (ClassOrNamespace *b = context.lookupType(e)) { Block *block = e->enclosingScope()->asBlock(); - if (LookupScope *bb = b->findBlock(block)) { + if (ClassOrNamespace *bb = b->findBlock(block)) { completeNamespace(bb); break; } } } - if (LookupScope *b = context.lookupType(e)) { + if (ClassOrNamespace *b = context.lookupType(e)) { completeNamespace(b); break; } @@ -1704,14 +1704,14 @@ bool InternalCppCompletionAssistProcessor::completeScope(const QList<LookupItem> return !m_completions.isEmpty(); } -void InternalCppCompletionAssistProcessor::completeNamespace(LookupScope *b) +void InternalCppCompletionAssistProcessor::completeNamespace(ClassOrNamespace *b) { - QSet<LookupScope *> bindingsVisited; - QList<LookupScope *> bindingsToVisit; + QSet<ClassOrNamespace *> bindingsVisited; + QList<ClassOrNamespace *> bindingsToVisit; bindingsToVisit.append(b); while (!bindingsToVisit.isEmpty()) { - LookupScope *binding = bindingsToVisit.takeFirst(); + ClassOrNamespace *binding = bindingsToVisit.takeFirst(); if (!binding || bindingsVisited.contains(binding)) continue; @@ -1744,14 +1744,14 @@ void InternalCppCompletionAssistProcessor::completeNamespace(LookupScope *b) } } -void InternalCppCompletionAssistProcessor::completeClass(LookupScope *b, bool staticLookup) +void InternalCppCompletionAssistProcessor::completeClass(ClassOrNamespace *b, bool staticLookup) { - QSet<LookupScope *> bindingsVisited; - QList<LookupScope *> bindingsToVisit; + QSet<ClassOrNamespace *> bindingsVisited; + QList<ClassOrNamespace *> bindingsToVisit; bindingsToVisit.append(b); while (!bindingsToVisit.isEmpty()) { - LookupScope *binding = bindingsToVisit.takeFirst(); + ClassOrNamespace *binding = bindingsToVisit.takeFirst(); if (!binding || bindingsVisited.contains(binding)) continue; @@ -1838,16 +1838,16 @@ bool InternalCppCompletionAssistProcessor::completeQtMethod(const QList<LookupIt QSet<QString> signatures; foreach (const LookupItem &lookupItem, results) { - LookupScope *b = lookupScopeFromLookupItem(lookupItem, context); + ClassOrNamespace *b = classOrNamespaceFromLookupItem(lookupItem, context); if (!b) continue; - QList<LookupScope *>todo; - QSet<LookupScope *> processed; + QList<ClassOrNamespace *>todo; + QSet<ClassOrNamespace *> processed; QList<Scope *> scopes; todo.append(b); while (!todo.isEmpty()) { - LookupScope *binding = todo.takeLast(); + ClassOrNamespace *binding = todo.takeLast(); if (!processed.contains(binding)) { processed.insert(binding); @@ -2063,7 +2063,7 @@ bool InternalCppCompletionAssistProcessor::completeConstructorOrFunction(const Q Scope *scope = result.scope(); if (NamedType *namedTy = ty->asNamedType()) { - if (LookupScope *b = context.lookupType(namedTy->name(), scope)) { + if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) { foreach (const LookupItem &r, b->lookup(functionCallOp)) { Symbol *overload = r.declaration(); FullySpecifiedType overloadTy = overload->type().simplified(); @@ -2145,7 +2145,7 @@ bool InternalCppCompletionAssistProcessor::completeConstructorOrFunction(const Q SubstitutionEnvironment env; env.setContext(context); env.switchScope(sc); - LookupScope *targetCoN = context.lookupType(sc); + ClassOrNamespace *targetCoN = context.lookupType(sc); if (!targetCoN) targetCoN = context.globalNamespace(); UseMinimalNames q(targetCoN); diff --git a/src/plugins/cpptools/cppcompletionassist.h b/src/plugins/cpptools/cppcompletionassist.h index 01fd44e5b8..30f8809081 100644 --- a/src/plugins/cpptools/cppcompletionassist.h +++ b/src/plugins/cpptools/cppcompletionassist.h @@ -53,7 +53,7 @@ namespace CPlusPlus { class LookupItem; -class LookupScope; +class ClassOrNamespace; class Function; class LookupContext; } // namespace CPlusPlus @@ -121,7 +121,7 @@ private: const QString &expression, int endOfExpression); - void completeObjCMsgSend(CPlusPlus::LookupScope *binding, bool staticClassAccess); + void completeObjCMsgSend(CPlusPlus::ClassOrNamespace *binding, bool staticClassAccess); bool completeInclude(const QTextCursor &cursor); void completeInclude(const QString &realPath, const QStringList &suffixes); void completePreprocessor(); @@ -130,8 +130,8 @@ private: bool toolTipOnly); bool completeMember(const QList<CPlusPlus::LookupItem> &results); bool completeScope(const QList<CPlusPlus::LookupItem> &results); - void completeNamespace(CPlusPlus::LookupScope *binding); - void completeClass(CPlusPlus::LookupScope *b, bool staticLookup = true); + void completeNamespace(CPlusPlus::ClassOrNamespace *binding); + void completeClass(CPlusPlus::ClassOrNamespace *b, bool staticLookup = true); void addClassMembersToCompletion(CPlusPlus::Scope *scope, bool staticLookup); enum CompleteQtMethodMode { CompleteQt4Signals, diff --git a/src/plugins/cpptools/cpptoolsreuse.cpp b/src/plugins/cpptools/cpptoolsreuse.cpp index 41031eb839..db9bbb07c1 100644 --- a/src/plugins/cpptools/cpptoolsreuse.cpp +++ b/src/plugins/cpptools/cpptoolsreuse.cpp @@ -109,7 +109,7 @@ bool isOwnershipRAIIType(Symbol *symbol, const LookupContext &context) Declaration *declaration = symbol->asDeclaration(); const NamedType *namedType = declaration->type()->asNamedType(); if (namedType) { - LookupScope *clazz = context.lookupType(namedType->name(), + ClassOrNamespace *clazz = context.lookupType(namedType->name(), declaration->enclosingScope()); if (clazz && !clazz->symbols().isEmpty()) { Overview overview; diff --git a/src/plugins/cpptools/symbolfinder.cpp b/src/plugins/cpptools/symbolfinder.cpp index 3bc72c00b5..cc5006e63a 100644 --- a/src/plugins/cpptools/symbolfinder.cpp +++ b/src/plugins/cpptools/symbolfinder.cpp @@ -151,7 +151,7 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration, QList<Function *> viableFunctions; - LookupScope *enclosingType = context.lookupType(declaration); + ClassOrNamespace *enclosingType = context.lookupType(declaration); if (!enclosingType) continue; // nothing to do @@ -214,15 +214,13 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration, return 0; } -Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Snapshot &snapshot, - const LookupContext *context) +Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Snapshot &snapshot) { if (!declaration->identifier()) return 0; QString declFile = QString::fromUtf8(declaration->fileName(), declaration->fileNameLength()); - const bool useLocalContext = !context; foreach (const QString &file, fileIterationOrder(declFile, snapshot)) { Document::Ptr doc = snapshot.document(file); if (!doc) { @@ -234,13 +232,9 @@ Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Sna declaration->identifier()->size())) continue; - QScopedPointer<LookupContext> localContext; - if (useLocalContext) { - localContext.reset(new LookupContext(doc, snapshot)); - context = localContext.data(); - } + LookupContext context(doc, snapshot); - LookupScope *type = context->lookupType(declaration); + ClassOrNamespace *type = context.lookupType(declaration); if (!type) continue; @@ -289,7 +283,7 @@ void SymbolFinder::findMatchingDeclaration(const LookupContext &context, if (!functionName) return; - LookupScope *binding = 0; + ClassOrNamespace *binding = 0; const QualifiedNameId *qName = functionName->asQualifiedNameId(); if (qName) { if (qName->base()) diff --git a/src/plugins/cpptools/symbolfinder.h b/src/plugins/cpptools/symbolfinder.h index 45236eb1ad..c1d65f7716 100644 --- a/src/plugins/cpptools/symbolfinder.h +++ b/src/plugins/cpptools/symbolfinder.h @@ -61,8 +61,7 @@ public: bool strict = false); CPlusPlus::Class *findMatchingClassDeclaration(CPlusPlus::Symbol *declaration, - const CPlusPlus::Snapshot &snapshot, - const CPlusPlus::LookupContext *context = 0); + const CPlusPlus::Snapshot &snapshot); void findMatchingDeclaration(const CPlusPlus::LookupContext &context, CPlusPlus::Function *functionType, diff --git a/src/plugins/genericprojectmanager/genericprojectnodes.cpp b/src/plugins/genericprojectmanager/genericprojectnodes.cpp index c58b336587..6683c7443e 100644 --- a/src/plugins/genericprojectmanager/genericprojectnodes.cpp +++ b/src/plugins/genericprojectmanager/genericprojectnodes.cpp @@ -68,6 +68,9 @@ QHash<QString, QStringList> sortFilesIntoPaths(const QString &base, const QSet<Q relativeFilePath.chop(1); } + if (relativeFilePath == QLatin1String(".")) + relativeFilePath.clear(); + filesInPath[relativeFilePath].append(absoluteFileName); } return filesInPath; diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h index 80c9067e1c..c50aeaeacd 100644 --- a/src/plugins/mercurial/mercurialclient.h +++ b/src/plugins/mercurial/mercurialclient.h @@ -75,6 +75,8 @@ public: const QStringList &extraOptions = QStringList()); void revertAll(const QString &workingDir, const QString &revision = QString(), const QStringList &extraOptions = QStringList()); + +public slots: void view(const QString &source, const QString &id, const QStringList &extraOptions = QStringList()); diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 5471287a3f..1d2ceac974 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -483,6 +483,7 @@ Abi Abi::abiFromTargetTriplet(const QString &triple) } else if (p == QLatin1String("i386") || p == QLatin1String("i486") || p == QLatin1String("i586") || p == QLatin1String("i686") || p == QLatin1String("x86")) { arch = Abi::X86Architecture; + width = 32; } else if (p.startsWith(QLatin1String("arm"))) { arch = Abi::ArmArchitecture; width = p.contains(QLatin1String("64")) ? 64 : 32; @@ -1057,27 +1058,27 @@ void ProjectExplorer::ProjectExplorerPlugin::testAbiFromTargetTriplet_data() QTest::newRow("i586-pc-mingw32msvc") << int(Abi::X86Architecture) << int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor) - << int(Abi::PEFormat) << 0; + << int(Abi::PEFormat) << 32; QTest::newRow("i686-linux-gnu") << int(Abi::X86Architecture) << int(Abi::LinuxOS) << int(Abi::GenericLinuxFlavor) - << int(Abi::ElfFormat) << 0; + << int(Abi::ElfFormat) << 32; QTest::newRow("i686-linux-android") << int(Abi::X86Architecture) << int(Abi::LinuxOS) << int(Abi::AndroidLinuxFlavor) - << int(Abi::ElfFormat) << 0; + << int(Abi::ElfFormat) << 32; QTest::newRow("i686-pc-linux-android") << int(Abi::X86Architecture) << int(Abi::LinuxOS) << int(Abi::AndroidLinuxFlavor) - << int(Abi::ElfFormat) << 0; + << int(Abi::ElfFormat) << 32; QTest::newRow("i686-pc-mingw32") << int(Abi::X86Architecture) << int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor) - << int(Abi::PEFormat) << 0; + << int(Abi::PEFormat) << 32; QTest::newRow("i686-w64-mingw32") << int(Abi::X86Architecture) << int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor) - << int(Abi::PEFormat) << 0; + << int(Abi::PEFormat) << 32; QTest::newRow("x86_64-pc-msys") << int(Abi::X86Architecture) << int(Abi::WindowsOS) << int(Abi::WindowsMSysFlavor) diff --git a/src/plugins/projectexplorer/customwizard/customwizard.cpp b/src/plugins/projectexplorer/customwizard/customwizard.cpp index c52bd20eab..fbbe9e7b9e 100644 --- a/src/plugins/projectexplorer/customwizard/customwizard.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizard.cpp @@ -40,6 +40,7 @@ #include <coreplugin/messagemanager.h> #include <extensionsystem/pluginmanager.h> +#include <utils/algorithm.h> #include <utils/fileutils.h> #include <utils/qtcassert.h> @@ -358,7 +359,6 @@ CustomWizard *CustomWizard::createWizard(const CustomProjectWizard::CustomWizard QList<Core::IWizardFactory *> CustomWizard::createWizards() { - QList<Core::IWizardFactory *> rc; QString errorMessage; QString verboseLog; const QString templateDirName = Core::ICore::resourcePath() + @@ -371,29 +371,32 @@ QList<Core::IWizardFactory *> CustomWizard::createWizards() const QDir templateDir(templateDirName); if (CustomWizardPrivate::verbose) - verboseLog = QString::fromLatin1("### CustomWizard: Checking \"%1\"\n").arg(templateDirName); + verboseLog += QString::fromLatin1("### CustomWizard: Checking \"%1\"\n").arg(templateDirName); if (!templateDir.exists()) { if (CustomWizardPrivate::verbose) qWarning("Custom project template path %s does not exist.", qPrintable(templateDir.absolutePath())); - return rc; + return QList<Core::IWizardFactory *>(); } const QDir userTemplateDir(userTemplateDirName); if (CustomWizardPrivate::verbose) - verboseLog = QString::fromLatin1("### CustomWizard: Checking \"%1\"\n").arg(userTemplateDirName); + verboseLog += QString::fromLatin1("### CustomWizard: Checking \"%1\"\n").arg(userTemplateDirName); const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; const QDir::SortFlags sortflags = QDir::Name|QDir::IgnoreCase; - QList<QFileInfo> dirs = templateDir.entryInfoList(filters, sortflags); + QList<QFileInfo> dirs; if (userTemplateDir.exists()) { if (CustomWizardPrivate::verbose) - verboseLog = QString::fromLatin1("### CustomWizard: userTemplateDir \"%1\" found, adding\n").arg(userTemplateDirName); + verboseLog += QString::fromLatin1("### CustomWizard: userTemplateDir \"%1\" found, adding\n").arg(userTemplateDirName); dirs += userTemplateDir.entryInfoList(filters, sortflags); } + dirs += templateDir.entryInfoList(filters, sortflags); const QString configFile = QLatin1String(configFileC); // Check and parse config file in each directory. + QList<CustomWizardParametersPtr> toCreate; + while (!dirs.isEmpty()) { const QFileInfo dirFi = dirs.takeFirst(); const QDir dir(dirFi.absoluteFilePath()); @@ -403,11 +406,13 @@ QList<Core::IWizardFactory *> CustomWizard::createWizards() CustomWizardParametersPtr parameters(new CustomWizardParameters); switch (parameters->parse(dir.absoluteFilePath(configFile), &errorMessage)) { case CustomWizardParameters::ParseOk: - parameters->directory = dir.absolutePath(); - if (CustomWizard *w = createWizard(parameters)) - rc.push_back(w); - else - qWarning("Custom wizard factory function failed for %s", qPrintable(parameters->id.toString())); + if (!Utils::contains(toCreate, [parameters](CustomWizardParametersPtr p) { return parameters->id == p->id; })) { + parameters->directory = dir.absolutePath(); + toCreate.append(parameters); + } else { + verboseLog += QString::fromLatin1("Customwizard: Ignoring wizard in %1 due to duplicate Id %2.\n") + .arg(dir.absolutePath()).arg(parameters->id.toString()); + } break; case CustomWizardParameters::ParseDisabled: if (CustomWizardPrivate::verbose) @@ -429,6 +434,18 @@ QList<Core::IWizardFactory *> CustomWizard::createWizards() } } } + + QList<Core::IWizardFactory *> rc; + foreach (CustomWizardParametersPtr p, toCreate) { + if (CustomWizard *w = createWizard(p)) { + rc.push_back(w); + } else { + qWarning("Custom wizard factory function failed for %s from %s.", + qPrintable(p->id.toString()), qPrintable(p->directory)); + } + } + + if (CustomWizardPrivate::verbose) { // Print to output pane for Windows. qWarning("%s", qPrintable(verboseLog)); Core::MessageManager::write(verboseLog, Core::MessageManager::ModeSwitch); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 4df29ac2c9..134893481c 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -568,7 +568,8 @@ static void appendNodeToEndOfTheRow(const ModelNode &modelNode, const ItemRow &n parentPropertyItem->appendRow(newItemRow.toList()); } else { QStandardItem *parentDefaultPropertyItem = parentRow.idItem; - parentDefaultPropertyItem->appendRow(newItemRow.toList()); + if (parentDefaultPropertyItem) + parentDefaultPropertyItem->appendRow(newItemRow.toList()); } } else { // root node treeModel->appendRow(newItemRow.toList()); diff --git a/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp b/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp index 7dfb02609c..b984b3da1a 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp +++ b/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp @@ -885,7 +885,7 @@ void PathItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (pickedControlPoint.isEditPoint()) { createEditPointContextMenu(pickedControlPoint, event->screenPos()); } else { - double t; + double t = 0.0; CubicSegment minimumDistanceSegment = getMinimumDistanceSegment(event->pos(), m_cubicSegments, 20., &t); if (minimumDistanceSegment.isValid()) createCubicSegmentContextMenu(minimumDistanceSegment, event->screenPos(), t); diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index 8945675e05..96b70100d7 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -104,16 +104,24 @@ void QmlProfilerTraceTime::setTime(qint64 startTime, qint64 endTime) void QmlProfilerTraceTime::decreaseStartTime(qint64 time) { - if (m_startTime > time) { + if (m_startTime > time || m_startTime == -1) { m_startTime = time; + if (m_endTime == -1) + m_endTime = m_startTime; + else + QTC_ASSERT(m_endTime >= m_startTime, m_endTime = m_startTime); emit timeChanged(time, m_endTime); } } void QmlProfilerTraceTime::increaseEndTime(qint64 time) { - if (m_endTime < time) { + if (m_endTime < time || m_endTime == -1) { m_endTime = time; + if (m_startTime == -1) + m_startTime = m_endTime; + else + QTC_ASSERT(m_endTime >= m_startTime, m_startTime = m_endTime); emit timeChanged(m_startTime, time); } } @@ -152,6 +160,8 @@ QmlProfilerModelManager::QmlProfilerModelManager(Utils::FileInProjectFinder *fin QObject(parent), d(new QmlProfilerModelManagerPrivate(this)) { d->totalWeight = 0; + d->previousProgress = 0; + d->progress = 0; d->availableFeatures = 0; d->visibleFeatures = 0; d->recordedFeatures = 0; diff --git a/src/shared/json/json.cpp b/src/shared/json/json.cpp index c40aa3dc1f..75d313c9e2 100644 --- a/src/shared/json/json.cpp +++ b/src/shared/json/json.cpp @@ -33,6 +33,7 @@ #include <algorithm> #include <atomic> +#include <cmath> #include <iostream> #include <limits> #include <string> diff --git a/src/shared/qbs b/src/shared/qbs -Subproject 94aaf3b94f9a9d8975349d75966917b4a8e0a43 +Subproject ca3974a0828c029e47f644931386fe6df200fba diff --git a/src/tools/clangbackend/clangbackendmain.cpp b/src/tools/clangbackend/clangbackendmain.cpp index 428d55add6..33a6c1660e 100644 --- a/src/tools/clangbackend/clangbackendmain.cpp +++ b/src/tools/clangbackend/clangbackendmain.cpp @@ -53,6 +53,9 @@ int main(int argc, char *argv[]) ClangBackEnd::Messages::registerMessages(); + clang_toggleCrashRecovery(true); + clang_enableStackTraces(); + ClangBackEnd::ClangIpcServer clangIpcServer; ClangBackEnd::ConnectionServer connectionServer(application.arguments()[1]); connectionServer.start(); diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index 73aa363a95..93131082bf 100644 --- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri @@ -25,7 +25,13 @@ HEADERS += $$PWD/clangipcserver.h \ $$PWD/diagnosticsetiterator.h \ $$PWD/clangfilesystemwatcher.h \ $$PWD/translationunitalreadyexistsexception.h \ - $$PWD/commandlinearguments.h + $$PWD/commandlinearguments.h \ + $$PWD/cursor.h \ + $$PWD/type.h \ + $$PWD/highlightinginformations.h \ + $$PWD/highlightinginformation.h \ + $$PWD/highlightinginformationsiterator.h \ + $$PWD/skippedsourceranges.h SOURCES += $$PWD/clangipcserver.cpp \ $$PWD/codecompleter.cpp \ @@ -51,4 +57,9 @@ SOURCES += $$PWD/clangipcserver.cpp \ $$PWD/fixit.cpp \ $$PWD/clangfilesystemwatcher.cpp \ $$PWD/translationunitalreadyexistsexception.cpp \ - $$PWD/commandlinearguments.cpp + $$PWD/commandlinearguments.cpp \ + $$PWD/cursor.cpp \ + $$PWD/type.cpp \ + $$PWD/highlightinginformations.cpp \ + $$PWD/highlightinginformation.cpp \ + $$PWD/skippedsourceranges.cpp diff --git a/src/tools/clangbackend/ipcsource/clangstring.cpp b/src/tools/clangbackend/ipcsource/clangstring.cpp index 200e834270..5decaf1549 100644 --- a/src/tools/clangbackend/ipcsource/clangstring.cpp +++ b/src/tools/clangbackend/ipcsource/clangstring.cpp @@ -61,6 +61,11 @@ ClangString &ClangString::operator=(ClangString &&other) return *this; } +const char *ClangString::cString() const +{ + return clang_getCString(cxString); +} + ClangString::ClangString(ClangString &&other) : cxString(std::move(other.cxString)) { @@ -70,7 +75,7 @@ ClangString::ClangString(ClangString &&other) ClangString::operator Utf8String() const { - return Utf8String(clang_getCString(cxString), -1); + return Utf8String(cString(), -1); } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangstring.h b/src/tools/clangbackend/ipcsource/clangstring.h index f18a612282..2db7b8ade0 100644 --- a/src/tools/clangbackend/ipcsource/clangstring.h +++ b/src/tools/clangbackend/ipcsource/clangstring.h @@ -51,6 +51,8 @@ public: operator Utf8String() const; + const char *cString() const; + bool isNull() const; private: diff --git a/src/tools/clangbackend/ipcsource/cursor.cpp b/src/tools/clangbackend/ipcsource/cursor.cpp new file mode 100644 index 0000000000..7ea5009d4d --- /dev/null +++ b/src/tools/clangbackend/ipcsource/cursor.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "cursor.h" + +#include "clangstring.h" +#include "sourcelocation.h" +#include "sourcerange.h" + +#include <ostream> + +namespace ClangBackEnd { + +Cursor::Cursor() + : cxCursor(clang_getNullCursor()) +{ +} + +Cursor::Cursor(CXCursor cxCursor) + : cxCursor(cxCursor) +{ +} + +bool Cursor::isNull() const +{ + return clang_Cursor_isNull(cxCursor); +} + +bool Cursor::isValid() const +{ + return !clang_isInvalid(kind()); +} + +bool Cursor::isTranslationUnit() const +{ + return clang_isTranslationUnit(kind()); +} + +bool Cursor::isDefinition() const +{ + return clang_isCursorDefinition(cxCursor); +} + +bool Cursor::isDynamicCall() const +{ + return clang_Cursor_isDynamicCall(cxCursor); +} + +bool Cursor::isVirtualMethod() const +{ + return clang_CXXMethod_isVirtual(cxCursor); +} + +bool Cursor::isPureVirtualMethod() const +{ + return clang_CXXMethod_isPureVirtual(cxCursor); +} + +bool Cursor::isConstantMethod() const +{ + return clang_CXXMethod_isConst(cxCursor); +} + +bool Cursor::isStaticMethod() const +{ + return clang_CXXMethod_isStatic(cxCursor); +} + +bool Cursor::isCompoundType() const +{ + switch (kind()) { + case CXCursor_ClassDecl: + case CXCursor_StructDecl: + case CXCursor_UnionDecl: return true; + default: return false; + } +} + +bool Cursor::isDeclaration() const +{ + return clang_isDeclaration(kind()); +} + +bool Cursor::isLocalVariable() const +{ + switch (semanticParent().kind()) { + case CXCursor_FunctionDecl: + case CXCursor_CXXMethod: + case CXCursor_Constructor: + case CXCursor_Destructor: + case CXCursor_ConversionFunction: + case CXCursor_FunctionTemplate: + case CXCursor_ObjCInstanceMethodDecl: return true; + default: + return false; + } +} + +bool Cursor::hasFinalFunctionAttribute() const +{ + bool hasFinal = false; + + visit([&] (Cursor cursor, Cursor /*parent*/) { + if (cursor.kind() == CXCursor_CXXFinalAttr) { + hasFinal = true; + return CXChildVisit_Break; + } else { + return CXChildVisit_Recurse; + } + }); + + return hasFinal; +} + +bool Cursor::hasFinalClassAttribute() const +{ + bool hasFinal = false; + + visit([&] (Cursor cursor, Cursor /*parent*/) { + switch (cursor.kind()) { + case CXCursor_CXXFinalAttr: + hasFinal = true; + return CXChildVisit_Break; + case CXCursor_CXXMethod: + return CXChildVisit_Break; + default: + return CXChildVisit_Recurse; + } + }); + + return hasFinal; +} + +bool Cursor::isUnexposed() const +{ + return clang_isUnexposed(kind()); +} + +Utf8String Cursor::unifiedSymbolResolution() const +{ + return ClangString(clang_getCursorUSR(cxCursor)); +} + +Utf8String Cursor::mangling() const +{ + return ClangString(clang_Cursor_getMangling(cxCursor)); +} + +ClangString Cursor::spelling() const +{ + return ClangString(clang_getCursorSpelling(cxCursor)); +} + +Utf8String Cursor::displayName() const +{ + return ClangString(clang_getCursorDisplayName(cxCursor)); +} + +Utf8String Cursor::briefComment() const +{ + return ClangString(clang_Cursor_getBriefCommentText(cxCursor)); +} + +Utf8String Cursor::rawComment() const +{ + return ClangString(clang_Cursor_getRawCommentText(cxCursor)); +} + +int Cursor::argumentCount() const +{ + return clang_Cursor_getNumArguments(cxCursor); +} + +Type Cursor::type() const +{ + return clang_getCursorType(cxCursor); +} + +Type Cursor::nonPointerTupe() const +{ + auto typeResult = type(); + + if (typeResult.isPointer()) + typeResult = typeResult.pointeeType(); + + return typeResult; +} + +SourceLocation Cursor::sourceLocation() const +{ + return clang_getCursorLocation(cxCursor); +} + +SourceRange Cursor::sourceRange() const +{ + return clang_getCursorExtent(cxCursor); +} + +SourceRange Cursor::commentRange() const +{ + return clang_Cursor_getCommentRange(cxCursor); +} + +Cursor Cursor::definition() const +{ + return clang_getCursorDefinition(cxCursor); +} + +Cursor Cursor::canonical() const +{ + return clang_getCanonicalCursor(cxCursor); +} + +Cursor Cursor::referenced() const +{ + return clang_getCursorReferenced(cxCursor); +} + +Cursor Cursor::semanticParent() const +{ + return clang_getCursorSemanticParent(cxCursor); +} + +Cursor Cursor::lexicalParent() const +{ + return clang_getCursorLexicalParent(cxCursor); +} + +Cursor Cursor::functionBaseDeclaration() const +{ + auto functionBaseCursor = functionBase(); + + if (functionBaseCursor.isValid()) + return functionBaseCursor.nonPointerTupe().canonical().declaration(); + else + return semanticParent().semanticParent(); +} + +Cursor Cursor::functionBase() const +{ + Cursor functionBaseCursor; + + visit([&] (Cursor cursor, Cursor /*parentCursor*/) { + switch (cursor.kind()) { + case CXCursor_DeclRefExpr: + functionBaseCursor = cursor; ; + return CXChildVisit_Break; + default: + return CXChildVisit_Recurse; + } + }); + + return functionBaseCursor; +} + +Cursor Cursor::argument(int index) const +{ + return clang_Cursor_getArgument(cxCursor, index); +} +namespace { +void collectOutputArguments(const Cursor &callExpression, + std::vector<Cursor> &outputArguments) +{ + auto callExpressionType = callExpression.referenced().type(); + auto argumentCount = callExpression.argumentCount(); + outputArguments.reserve(argumentCount); + + for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) { + auto argument = callExpression.argument(argumentIndex); + auto argumentType = callExpressionType.argument(argumentIndex); + + if (!argument.isUnexposed() && argumentType.isOutputParameter()) + outputArguments.push_back(callExpression.argument(argumentIndex)); + } +} +} + +std::vector<Cursor> Cursor::outputArguments() const +{ + std::vector<Cursor> outputArguments; + + if (kind() == CXCursor_CallExpr) + collectOutputArguments(*this, outputArguments); + + return outputArguments; +} + +CXCursorKind Cursor::kind() const +{ + return clang_getCursorKind(cxCursor); +} + +bool operator==(const Cursor &first, const Cursor &second) +{ + return clang_equalCursors(first.cxCursor, second.cxCursor); +} + +void PrintTo(CXCursorKind cursorKind, ::std::ostream *os) +{ + ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind)); + *os << cursorKindSpelling.cString(); +} + +void PrintTo(const Cursor &cursor, ::std::ostream*os) +{ + if (cursor.isValid()) { + ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursor.kind())); + *os << cursorKindSpelling.cString() << " "; + + auto identifier = cursor.displayName(); + if (identifier.hasContent()) { + *os << "\"" + << identifier.constData() + << "\": "; + } + + PrintTo(cursor.sourceLocation(), os); + } else { + *os << "Invalid cursor!"; + } +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/cursor.h b/src/tools/clangbackend/ipcsource/cursor.h new file mode 100644 index 0000000000..d4256401e5 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/cursor.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_CURSOR_H +#define CLANGBACKEND_CURSOR_H + +#include "type.h" + +#include <clang-c/Index.h> + +#include <iosfwd> + +#include <vector> + +class Utf8String; + +namespace ClangBackEnd { + +class SourceLocation; +class SourceRange; +class ClangString; + +class Cursor +{ + friend class Type; + friend bool operator==(const Cursor &first, const Cursor &second); +public: + Cursor(); + Cursor(CXCursor cxCursor); + + bool isNull() const; + bool isValid() const; + + bool isTranslationUnit() const; + bool isDefinition() const; + bool isDynamicCall() const; + bool isVirtualMethod() const; + bool isPureVirtualMethod() const; + bool isConstantMethod() const; + bool isStaticMethod() const; + bool isCompoundType() const; + bool isDeclaration() const; + bool isLocalVariable() const; + bool hasFinalFunctionAttribute() const; + bool hasFinalClassAttribute() const; + bool isUnexposed() const; + + Utf8String unifiedSymbolResolution() const; + Utf8String mangling() const; + ClangString spelling() const; + Utf8String displayName() const; + Utf8String briefComment() const; + Utf8String rawComment() const; + int argumentCount() const; + + Type type() const; + Type nonPointerTupe() const; + + SourceLocation sourceLocation() const; + SourceRange sourceRange() const; + SourceRange commentRange() const; + + Cursor definition() const; + Cursor canonical() const; + Cursor alias() const; + Cursor referenced() const; + Cursor semanticParent() const; + Cursor lexicalParent() const; + Cursor functionBaseDeclaration() const; + Cursor functionBase() const; + Cursor argument(int index) const; + std::vector<Cursor> outputArguments() const; + + CXCursorKind kind() const; + + template <class VisitorCallback> + void visit(VisitorCallback visitorCallback) const; + +private: + CXCursor cxCursor; +}; + +template <class VisitorCallback> +void Cursor::visit(VisitorCallback visitorCallback) const +{ + auto visitor = [] (CXCursor cursor, CXCursor parent, CXClientData lambda) -> CXChildVisitResult { + auto &visitorCallback = *static_cast<VisitorCallback*>(lambda); + + return visitorCallback(cursor, parent); + }; + + clang_visitChildren(cxCursor, visitor, &visitorCallback); +} + +bool operator==(const Cursor &first, const Cursor &second); + +void PrintTo(CXCursorKind cursorKind, ::std::ostream *os); +void PrintTo(const Cursor &cursor, ::std::ostream* os); +} // namespace ClangBackEnd + + +#endif // CLANGBACKEND_CURSOR_H diff --git a/src/tools/clangbackend/ipcsource/diagnostic.cpp b/src/tools/clangbackend/ipcsource/diagnostic.cpp index fdb7a0940a..81e519894b 100644 --- a/src/tools/clangbackend/ipcsource/diagnostic.cpp +++ b/src/tools/clangbackend/ipcsource/diagnostic.cpp @@ -113,7 +113,7 @@ std::vector<SourceRange> Diagnostic::ranges() const const SourceRange sourceRange(clang_getDiagnosticRange(cxDiagnostic, index)); if (sourceRange.isValid()) - ranges.push_back(SourceRange(clang_getDiagnosticRange(cxDiagnostic, index))); + ranges.push_back(std::move(sourceRange)); } return ranges; diff --git a/src/tools/clangbackend/ipcsource/highlightinginformation.cpp b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp new file mode 100644 index 0000000000..808a0407d1 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "clangstring.h" +#include "cursor.h" +#include "highlightinginformation.h" +#include "sourcelocation.h" +#include "sourcerange.h" + +#include <cstring> +#include <ostream> + +#include <QDebug> + +namespace ClangBackEnd { + +HighlightingInformation::HighlightingInformation(const CXCursor &cxCursor, + CXToken *cxToken, + CXTranslationUnit cxTranslationUnit) +{ + const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken); + const auto start = sourceRange.start(); + const auto end = sourceRange.end(); + + originalCursor = cxCursor; + line = start.line(); + column = start.column(); + length = end.offset() - start.offset(); + type = kind(cxToken, originalCursor); +} + +HighlightingInformation::HighlightingInformation(uint line, uint column, uint length, HighlightingType type) + : line(line), + column(column), + length(length), + type(type) +{ +} + +bool HighlightingInformation::hasType(HighlightingType type) const +{ + return this->type == type; +} + +bool HighlightingInformation::hasFunctionArguments() const +{ + return originalCursor.argumentCount() > 0; +} + +QVector<HighlightingInformation> HighlightingInformation::outputFunctionArguments() const +{ + QVector<HighlightingInformation> outputFunctionArguments; + + return outputFunctionArguments; +} + +namespace { + +bool isFinalFunction(const Cursor &cursor) +{ + auto referencedCursor = cursor.referenced(); + if (referencedCursor.hasFinalFunctionAttribute()) + return true; + + else return false; +} + +bool isFunctionInFinalClass(const Cursor &cursor) +{ + auto functionBase = cursor.functionBaseDeclaration(); + if (functionBase.isValid() && functionBase.hasFinalClassAttribute()) + return true; + + return false; +} +} + +HighlightingType HighlightingInformation::memberReferenceKind(const Cursor &cursor) const +{ + if (cursor.isDynamicCall()) { + if (isFinalFunction(cursor) || isFunctionInFinalClass(cursor)) + return HighlightingType::Function; + else + return HighlightingType::VirtualFunction; + } + + return identifierKind(cursor.referenced()); + +} + +HighlightingType HighlightingInformation::referencedTypeKind(const Cursor &cursor) const +{ + const Cursor referencedCursor = cursor.referenced(); + + switch (referencedCursor.kind()) { + case CXCursor_ClassDecl: + case CXCursor_StructDecl: + case CXCursor_UnionDecl: + case CXCursor_TemplateTypeParameter: + case CXCursor_TypeAliasDecl: return HighlightingType::Type; + case CXCursor_EnumDecl: return HighlightingType::Enumeration; + default: return HighlightingType::Invalid; + } + + Q_UNREACHABLE(); +} + +HighlightingType HighlightingInformation::variableKind(const Cursor &cursor) const +{ + if (cursor.isLocalVariable()) + return HighlightingType::LocalVariable; + else + return HighlightingType::GlobalVariable; +} + +bool HighlightingInformation::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const +{ + return cursor.isVirtualMethod() + && (originalCursor.isDeclaration() || originalCursor.isDefinition()); +} +namespace { +bool isNotFinalFunction(const Cursor &cursor) +{ + return !cursor.hasFinalFunctionAttribute(); +} + +} +bool HighlightingInformation::isRealDynamicCall(const Cursor &cursor) const +{ + + return originalCursor.isDynamicCall() && isNotFinalFunction(cursor); +} + +HighlightingType HighlightingInformation::functionKind(const Cursor &cursor) const +{ + if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor)) + return HighlightingType::VirtualFunction; + else + return HighlightingType::Function; +} + +HighlightingType HighlightingInformation::identifierKind(const Cursor &cursor) const +{ + switch (cursor.kind()) { + case CXCursor_Destructor: + case CXCursor_Constructor: + case CXCursor_FunctionDecl: + case CXCursor_CallExpr: + case CXCursor_CXXMethod: return functionKind(cursor); + case CXCursor_NonTypeTemplateParameter: + case CXCursor_ParmDecl: return HighlightingType::LocalVariable; + case CXCursor_VarDecl: return variableKind(cursor); + case CXCursor_DeclRefExpr: return identifierKind(cursor.referenced()); + case CXCursor_MemberRefExpr: return memberReferenceKind(cursor); + case CXCursor_FieldDecl: + case CXCursor_MemberRef: + case CXCursor_ObjCIvarDecl: + case CXCursor_ObjCPropertyDecl: + case CXCursor_ObjCClassMethodDecl: + case CXCursor_ObjCInstanceMethodDecl: + case CXCursor_ObjCSynthesizeDecl: + case CXCursor_ObjCDynamicDecl: return HighlightingType::Field; + case CXCursor_TypeRef: return referencedTypeKind(cursor); + case CXCursor_ClassDecl: + case CXCursor_TemplateTypeParameter: + case CXCursor_TemplateTemplateParameter: + case CXCursor_UnionDecl: + case CXCursor_StructDecl: + case CXCursor_TemplateRef: + case CXCursor_Namespace: + case CXCursor_NamespaceRef: + case CXCursor_NamespaceAlias: + case CXCursor_TypeAliasDecl: + case CXCursor_ClassTemplate: + case CXCursor_UnexposedDecl: + case CXCursor_CXXStaticCastExpr: + case CXCursor_CXXReinterpretCastExpr: + case CXCursor_ObjCCategoryDecl: + case CXCursor_ObjCCategoryImplDecl: + case CXCursor_ObjCImplementationDecl: + case CXCursor_ObjCInterfaceDecl: + case CXCursor_ObjCProtocolDecl: + case CXCursor_ObjCProtocolRef: + case CXCursor_ObjCClassRef: + case CXCursor_ObjCSuperClassRef: return HighlightingType::Type; + case CXCursor_FunctionTemplate: return HighlightingType::Function; + case CXCursor_EnumConstantDecl: return HighlightingType::Enumeration; + case CXCursor_EnumDecl: return referencedTypeKind(cursor); + case CXCursor_PreprocessingDirective: return HighlightingType::Preprocessor; + case CXCursor_MacroExpansion: return HighlightingType::PreprocessorExpansion; + case CXCursor_MacroDefinition: return HighlightingType::PreprocessorDefinition; + case CXCursor_InclusionDirective: return HighlightingType::StringLiteral; + case CXCursor_LabelRef: + case CXCursor_LabelStmt: return HighlightingType::Label; + default: return HighlightingType::Invalid; + } + + Q_UNREACHABLE(); +} + +namespace { +HighlightingType literalKind(const Cursor &cursor) +{ + switch (cursor.kind()) { + case CXCursor_CharacterLiteral: + case CXCursor_StringLiteral: + case CXCursor_ObjCStringLiteral: return HighlightingType::StringLiteral; + case CXCursor_IntegerLiteral: + case CXCursor_ImaginaryLiteral: + case CXCursor_FloatingLiteral: return HighlightingType::NumberLiteral; + default: return HighlightingType::Invalid; + } + + Q_UNREACHABLE(); +} + + +HighlightingType punctationKind(const Cursor &cursor) +{ + switch (cursor.kind()) { + case CXCursor_DeclRefExpr: return HighlightingType::Operator; + default: return HighlightingType::Invalid; + } +} + +} +HighlightingType HighlightingInformation::kind(CXToken *cxToken, const Cursor &cursor) const +{ + auto cxTokenKind = clang_getTokenKind(*cxToken); + + switch (cxTokenKind) { + case CXToken_Keyword: return HighlightingType::Keyword; + case CXToken_Punctuation: return punctationKind(cursor); + case CXToken_Identifier: return identifierKind(cursor); + case CXToken_Comment: return HighlightingType::Comment; + case CXToken_Literal: return literalKind(cursor); + } + + Q_UNREACHABLE(); +} + +void PrintTo(const HighlightingInformation& information, ::std::ostream *os) +{ + *os << "type: "; + PrintTo(information.type, os); + *os << " line: " << information.line + << " column: " << information.column + << " length: " << information.length; +} + +void PrintTo(HighlightingType highlightingType, std::ostream *os) +{ + switch (highlightingType) { + case HighlightingType::Invalid: *os << "Invalid"; break; + case HighlightingType::Comment: *os << "Comment"; break; + case HighlightingType::Keyword: *os << "Keyword"; break; + case HighlightingType::StringLiteral: *os << "StringLiteral"; break; + case HighlightingType::NumberLiteral: *os << "NumberLiteral"; break; + case HighlightingType::Function: *os << "Function"; break; + case HighlightingType::VirtualFunction: *os << "VirtualFunction"; break; + case HighlightingType::Type: *os << "Type"; break; + case HighlightingType::LocalVariable: *os << "LocalVariable"; break; + case HighlightingType::GlobalVariable: *os << "GlobalVariable"; break; + case HighlightingType::Field: *os << "Field"; break; + case HighlightingType::Enumeration: *os << "Enumeration"; break; + case HighlightingType::Operator: *os << "Operator"; break; + case HighlightingType::Preprocessor: *os << "Preprocessor"; break; + case HighlightingType::Label: *os << "Label"; break; + case HighlightingType::OutputArgument: *os << "OutputArgument"; break; + case HighlightingType::PreprocessorDefinition: *os << "PreprocessorDefinition"; break; + case HighlightingType::PreprocessorExpansion: *os << "PreprocessorExpansion"; break; + } +} + + + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/highlightinginformation.h b/src/tools/clangbackend/ipcsource/highlightinginformation.h new file mode 100644 index 0000000000..ee327b6213 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/highlightinginformation.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_HIGHLIGHTINGINFORMATION_H +#define CLANGBACKEND_HIGHLIGHTINGINFORMATION_H + +#include <clangbackendipc_global.h> + +#include "cursor.h" + +#include <clang-c/Index.h> + +namespace ClangBackEnd { + +class HighlightingInformation +{ + friend bool operator==(const HighlightingInformation &first, const HighlightingInformation &second); + friend void PrintTo(const HighlightingInformation& highlightingInformation, ::std::ostream *os); + +public: + HighlightingInformation(const CXCursor &cxCursor, CXToken *cxToken, CXTranslationUnit cxTranslationUnit); + HighlightingInformation(uint line, uint column, uint length, HighlightingType type); + + bool hasType(HighlightingType type) const; + bool hasFunctionArguments() const; + QVector<HighlightingInformation> outputFunctionArguments() const; + +private: + HighlightingType identifierKind(const Cursor &cursor) const; + HighlightingType referencedTypeKind(const Cursor &cursor) const; + HighlightingType variableKind(const Cursor &cursor) const; + bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const; + HighlightingType functionKind(const Cursor &cursor) const; + HighlightingType memberReferenceKind(const Cursor &cursor) const; + HighlightingType kind(CXToken *cxToken, const Cursor &cursor) const; + bool isRealDynamicCall(const Cursor &cursor) const; + +private: + Cursor originalCursor; + uint line; + uint column; + uint length; + HighlightingType type; +}; + +void PrintTo(const HighlightingInformation& highlightingInformation, ::std::ostream *os); +void PrintTo(HighlightingType highlightingType, ::std::ostream *os); + +inline bool operator==(const HighlightingInformation &first, const HighlightingInformation &second) +{ + return first.line == second.line + && first.column == second.column + && first.length == second.length + && first.type == second.type; +} + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_HIGHLIGHTINGINFORMATION_H diff --git a/src/tools/clangbackend/ipcsource/highlightinginformations.cpp b/src/tools/clangbackend/ipcsource/highlightinginformations.cpp new file mode 100644 index 0000000000..f7157768fd --- /dev/null +++ b/src/tools/clangbackend/ipcsource/highlightinginformations.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "highlightinginformations.h" + +namespace ClangBackEnd { + +HighlightingInformations::HighlightingInformations(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount) + : cxTranslationUnit(cxTranslationUnit), + cxToken(tokens), + cxTokenCount(tokensCount) +{ + cxCursor.resize(tokensCount); + clang_annotateTokens(cxTranslationUnit, cxToken, cxTokenCount, cxCursor.data()); +} + +HighlightingInformations::~HighlightingInformations() +{ + clang_disposeTokens(cxTranslationUnit, cxToken, cxTokenCount); +} + +HighlightingInformations::const_iterator HighlightingInformations::begin() const +{ + return const_iterator(cxCursor.cbegin(), cxToken, cxTranslationUnit); +} + +HighlightingInformations::const_iterator HighlightingInformations::end() const +{ + return const_iterator(cxCursor.cend(), cxToken + cxTokenCount, cxTranslationUnit); +} + +bool HighlightingInformations::isEmpty() const +{ + return cxTokenCount == 0; +} + +bool ClangBackEnd::HighlightingInformations::isNull() const +{ + return cxToken == nullptr; +} + +uint HighlightingInformations::size() const +{ + return cxTokenCount; +} + +HighlightingInformation HighlightingInformations::operator[](size_t index) const +{ + return HighlightingInformation(cxCursor[index], cxToken + index, cxTranslationUnit); +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/highlightinginformations.h b/src/tools/clangbackend/ipcsource/highlightinginformations.h new file mode 100644 index 0000000000..2c7b8ce9bb --- /dev/null +++ b/src/tools/clangbackend/ipcsource/highlightinginformations.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_HIGHLIGHTINGINFORMATIONS_H +#define CLANGBACKEND_HIGHLIGHTINGINFORMATIONS_H + +#include "highlightinginformationsiterator.h" + +#include <clang-c/Index.h> + +#include <vector> + +namespace ClangBackEnd { + +using uint = unsigned int; + +class HighlightingInformations +{ +public: + using const_iterator = HighlightingInformationsIterator; + using value_type = HighlightingInformation; + +public: + HighlightingInformations() = default; + HighlightingInformations(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount); + ~HighlightingInformations(); + + bool isEmpty() const; + bool isNull() const; + uint size() const; + + HighlightingInformation operator[](size_t index) const; + + const_iterator begin() const; + const_iterator end() const; + +private: + CXTranslationUnit cxTranslationUnit = nullptr; + CXToken *const cxToken = nullptr; + const uint cxTokenCount = 0; + + std::vector<CXCursor> cxCursor; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_HIGHLIGHTINGINFORMATIONS_H diff --git a/src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h b/src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h new file mode 100644 index 0000000000..53f540970e --- /dev/null +++ b/src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef HIGHLIGHTINGINFORMATIONSITERATOR_H +#define HIGHLIGHTINGINFORMATIONSITERATOR_H + +#include "highlightinginformation.h" + +#include <iterator> +#include <vector> + +#include <clang-c/Index.h> + +namespace ClangBackEnd { + +using uint = unsigned int; + +class DiagnosticSet; +class Diagnostic; + +class HighlightingInformationsIterator : public std::iterator<std::forward_iterator_tag, HighlightingInformation, uint> +{ +public: + HighlightingInformationsIterator(std::vector<CXCursor>::const_iterator cxCursorIterator, + CXToken *cxToken, + CXTranslationUnit cxTranslationUnit) + : cxCursorIterator(cxCursorIterator), + cxToken(cxToken), + cxTranslationUnit(cxTranslationUnit) + {} + + HighlightingInformationsIterator(const HighlightingInformationsIterator &other) + : cxCursorIterator(other.cxCursorIterator) + {} + + HighlightingInformationsIterator& operator++() + { + ++cxCursorIterator; + ++cxToken; + + return *this; + } + + HighlightingInformationsIterator operator++(int) + { + return HighlightingInformationsIterator(cxCursorIterator++, cxToken++, cxTranslationUnit); + } + + bool operator==(HighlightingInformationsIterator other) const + { + return cxCursorIterator == other.cxCursorIterator; + } + + bool operator!=(HighlightingInformationsIterator other) const + { + return cxCursorIterator != other.cxCursorIterator; + } + + HighlightingInformation operator*() + { + return HighlightingInformation(*cxCursorIterator, cxToken, cxTranslationUnit); + } + +private: + std::vector<CXCursor>::const_iterator cxCursorIterator; + CXToken *cxToken; + CXTranslationUnit cxTranslationUnit; +}; + +} // namespace ClangBackEnd + +#endif // HIGHLIGHTINGINFORMATIONSITERATOR_H diff --git a/src/tools/clangbackend/ipcsource/skippedsourceranges.cpp b/src/tools/clangbackend/ipcsource/skippedsourceranges.cpp new file mode 100644 index 0000000000..2a39131474 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/skippedsourceranges.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#include "skippedsourceranges.h" + +#include "sourcerangecontainer.h" + +#include <QVector> + +#include <algorithm> + +namespace ClangBackEnd { + +SkippedSourceRanges::SkippedSourceRanges(CXTranslationUnit cxTranslationUnit, const char *filePath) +{ + cxSkippedSourceRanges = clang_getSkippedRanges(cxTranslationUnit, + clang_getFile(cxTranslationUnit, + filePath)); +} + +SkippedSourceRanges::~SkippedSourceRanges() +{ + clang_disposeSourceRangeList(cxSkippedSourceRanges); +} + +SkippedSourceRanges &SkippedSourceRanges::operator=(SkippedSourceRanges &&other) +{ + if (this != &other) { + cxSkippedSourceRanges = other.cxSkippedSourceRanges; + other.cxSkippedSourceRanges = nullptr; + } + + return *this; +} + +std::vector<SourceRange> SkippedSourceRanges::sourceRanges() const +{ + std::vector<SourceRange> sourceRanges; + + auto sourceRangeCount = cxSkippedSourceRanges->count; + sourceRanges.reserve(sourceRangeCount); + + std::copy(cxSkippedSourceRanges->ranges, + cxSkippedSourceRanges->ranges + sourceRangeCount, + std::back_inserter(sourceRanges)); + + return sourceRanges; +} + +QVector<SourceRangeContainer> SkippedSourceRanges::toSourceRangeContainers() const +{ + QVector<SourceRangeContainer> sourceRangeContainers; + + auto sourceRanges = this->sourceRanges(); + + std::copy(sourceRanges.cbegin(), + sourceRanges.cend(), + std::back_inserter(sourceRangeContainers)); + + return sourceRangeContainers; +} + +ClangBackEnd::SkippedSourceRanges::operator QVector<SourceRangeContainer>() const +{ + return toSourceRangeContainers(); +} + +SkippedSourceRanges::SkippedSourceRanges(SkippedSourceRanges &&other) + : cxSkippedSourceRanges(other.cxSkippedSourceRanges) +{ + other.cxSkippedSourceRanges = nullptr; +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/skippedsourceranges.h b/src/tools/clangbackend/ipcsource/skippedsourceranges.h new file mode 100644 index 0000000000..8d38bc50c9 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/skippedsourceranges.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef CLANGBACKEND_SKIPPEDSOURCERANGES_H +#define CLANGBACKEND_SKIPPEDSOURCERANGES_H + +#include "sourcerange.h" + +namespace ClangBackEnd { + +class SourceRangeContainer; + +class SkippedSourceRanges +{ +public: + SkippedSourceRanges(CXTranslationUnit TranslationUnit, const char *filePath); + ~SkippedSourceRanges(); + + SkippedSourceRanges(const SkippedSourceRanges &) = delete; + const SkippedSourceRanges &operator=(const SkippedSourceRanges &) = delete; + + SkippedSourceRanges(SkippedSourceRanges &&); + SkippedSourceRanges &operator=(SkippedSourceRanges &&); + + std::vector<SourceRange> sourceRanges() const; + + QVector<SourceRangeContainer> toSourceRangeContainers() const; + + operator QVector<SourceRangeContainer>() const; + +private: + CXSourceRangeList *cxSkippedSourceRanges; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_SKIPPEDSOURCERANGES_H diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.cpp b/src/tools/clangbackend/ipcsource/sourcelocation.cpp index 8a7cd0d871..e04f44c7d8 100644 --- a/src/tools/clangbackend/ipcsource/sourcelocation.cpp +++ b/src/tools/clangbackend/ipcsource/sourcelocation.cpp @@ -31,6 +31,7 @@ #include "sourcelocation.h" #include "clangstring.h" +#include "translationunit.h" #include <utf8string.h> @@ -39,6 +40,11 @@ namespace ClangBackEnd { +SourceLocation::SourceLocation() + : cxSourceLocation(clang_getNullLocation()) +{ +} + const Utf8String &SourceLocation::filePath() const { return filePath_; @@ -65,6 +71,7 @@ SourceLocationContainer SourceLocation::toSourceLocationContainer() const } SourceLocation::SourceLocation(CXSourceLocation cxSourceLocation) + : cxSourceLocation(cxSourceLocation) { CXFile cxFile; @@ -77,10 +84,37 @@ SourceLocation::SourceLocation(CXSourceLocation cxSourceLocation) filePath_ = ClangString(clang_getFileName(cxFile)); } +SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit, + const Utf8String &filePath, + uint line, + uint column) + : cxSourceLocation(clang_getLocation(cxTranslationUnit, + clang_getFile(cxTranslationUnit, + filePath.constData()), + line, + column)), + filePath_(filePath), + line_(line) +{ +} + +bool operator==(const SourceLocation &first, const SourceLocation &second) +{ + return clang_equalLocations(first.cxSourceLocation, second.cxSourceLocation); +} + +SourceLocation::operator CXSourceLocation() const +{ + return cxSourceLocation; +} + void PrintTo(const SourceLocation &sourceLocation, std::ostream *os) { - *os << sourceLocation.filePath().constData() - << ", line: " << sourceLocation.line() + auto filePath = sourceLocation.filePath(); + if (filePath.hasContent()) + *os << filePath.constData() << ", "; + + *os << "line: " << sourceLocation.line() << ", column: "<< sourceLocation.column() << ", offset: "<< sourceLocation.offset(); } diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.h b/src/tools/clangbackend/ipcsource/sourcelocation.h index 3ee500623b..83ba6c77c9 100644 --- a/src/tools/clangbackend/ipcsource/sourcelocation.h +++ b/src/tools/clangbackend/ipcsource/sourcelocation.h @@ -38,13 +38,19 @@ namespace ClangBackEnd { class SourceLocationContainer; +class TranslationUnit; class SourceLocation { friend class Diagnostic; friend class SourceRange; + friend class TranslationUnit; + friend class Cursor; + friend bool operator==(const SourceLocation &first, const SourceLocation &second); public: + SourceLocation(); + const Utf8String &filePath() const; uint line() const; uint column() const; @@ -54,14 +60,23 @@ public: private: SourceLocation(CXSourceLocation cxSourceLocation); + SourceLocation(CXTranslationUnit cxTranslationUnit, + const Utf8String &filePath, + uint line, + uint column); + + operator CXSourceLocation() const; private: + CXSourceLocation cxSourceLocation; Utf8String filePath_; - uint line_; - uint column_; - uint offset_; + uint line_ = 0; + uint column_ = 0; + uint offset_ = 0; }; +bool operator==(const SourceLocation &first, const SourceLocation &second); + void PrintTo(const SourceLocation &sourceLocation, ::std::ostream* os); } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/sourcerange.cpp b/src/tools/clangbackend/ipcsource/sourcerange.cpp index 7375988b2b..f069edc9cb 100644 --- a/src/tools/clangbackend/ipcsource/sourcerange.cpp +++ b/src/tools/clangbackend/ipcsource/sourcerange.cpp @@ -32,6 +32,8 @@ #include <sourcerangecontainer.h> +#include <ostream> + namespace ClangBackEnd { SourceRange::SourceRange() @@ -39,6 +41,11 @@ SourceRange::SourceRange() { } +SourceRange::SourceRange(const SourceLocation &start, const SourceLocation &end) + : cxSourceRange(clang_getRange(start, end)) +{ +} + bool SourceRange::isNull() const { return clang_Range_isNull(cxSourceRange); @@ -65,10 +72,33 @@ SourceRangeContainer SourceRange::toSourceRangeContainer() const end().toSourceLocationContainer()); } +ClangBackEnd::SourceRange::operator SourceRangeContainer() const +{ + return toSourceRangeContainer(); +} + +ClangBackEnd::SourceRange::operator CXSourceRange() const +{ + return cxSourceRange; +} + SourceRange::SourceRange(CXSourceRange cxSourceRange) : cxSourceRange(cxSourceRange) { } +bool operator==(const SourceRange &first, const SourceRange &second) +{ + return clang_equalRanges(first.cxSourceRange, second.cxSourceRange); +} + +void PrintTo(const SourceRange &sourceRange, ::std::ostream* os) +{ + *os << "["; + PrintTo(sourceRange.start(), os); + *os << ", "; + PrintTo(sourceRange.end(), os); + *os << "]"; +} } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/sourcerange.h b/src/tools/clangbackend/ipcsource/sourcerange.h index 3c80e4e040..f9b786cf4a 100644 --- a/src/tools/clangbackend/ipcsource/sourcerange.h +++ b/src/tools/clangbackend/ipcsource/sourcerange.h @@ -41,9 +41,14 @@ class SourceRange { friend class Diagnostic; friend class FixIt; + friend class Cursor; + friend class HighlightingInformation; + friend bool operator==(const SourceRange &first, const SourceRange &second); public: SourceRange(); + SourceRange(CXSourceRange cxSourceRange); + SourceRange(const SourceLocation &start, const SourceLocation &end); bool isNull() const; bool isValid() const; @@ -53,13 +58,15 @@ public: SourceRangeContainer toSourceRangeContainer() const; -private: - SourceRange(CXSourceRange cxSourceRange); + operator CXSourceRange() const; + operator SourceRangeContainer() const; private: CXSourceRange cxSourceRange; }; +bool operator==(const SourceRange &first, const SourceRange &second); +void PrintTo(const SourceRange &sourceRange, ::std::ostream* os); } // namespace ClangBackEnd #endif // CLANGBACKEND_SOURCERANGE_H diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index 88e917010f..8769f7caef 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -30,13 +30,17 @@ #include "translationunit.h" +#include "cursor.h" #include "clangstring.h" #include "codecompleter.h" #include "commandlinearguments.h" #include "diagnosticcontainer.h" #include "diagnosticset.h" #include "projectpart.h" +#include "skippedsourceranges.h" #include "sourcelocation.h" +#include "sourcerange.h" +#include "highlightinginformations.h" #include "translationunitfilenotexitexception.h" #include "translationunitisnullexception.h" #include "translationunitparseerrorexception.h" @@ -245,6 +249,53 @@ void TranslationUnit::setDirtyIfDependencyIsMet(const Utf8String &filePath) } } +SourceLocation TranslationUnit::sourceLocationAt(uint line, uint column) const +{ + return SourceLocation(cxTranslationUnit(), filePath(), line, column); +} + +SourceLocation TranslationUnit::sourceLocationAt(const Utf8String &filePath, uint line, uint column) const +{ + return SourceLocation(cxTranslationUnit(), filePath, line, column); +} + +SourceRange TranslationUnit::sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const +{ + return SourceRange(sourceLocationAt(fromLine, fromColumn), + sourceLocationAt(toLine, toColumn)); +} + +Cursor TranslationUnit::cursorAt(uint line, uint column) const +{ + return clang_getCursor(cxTranslationUnit(), sourceLocationAt(line, column)); +} + +Cursor TranslationUnit::cursorAt(const Utf8String &filePath, uint line, uint column) const +{ + return clang_getCursor(cxTranslationUnit(), sourceLocationAt(filePath, line, column)); +} + +Cursor TranslationUnit::cursor() const +{ + return clang_getTranslationUnitCursor(cxTranslationUnit()); +} + +HighlightingInformations TranslationUnit::highlightingInformationsInRange(const SourceRange &range) const +{ + CXToken *cxTokens = 0; + uint cxTokensCount = 0; + auto translationUnit = cxTranslationUnit(); + + clang_tokenize(translationUnit, range, &cxTokens, &cxTokensCount); + + return HighlightingInformations(translationUnit, cxTokens, cxTokensCount); +} + +SkippedSourceRanges TranslationUnit::skippedSourceRanges() const +{ + return SkippedSourceRanges(cxTranslationUnit(), d->filePath.constData()); +} + void TranslationUnit::checkIfNull() const { if (isNull()) @@ -380,7 +431,8 @@ uint TranslationUnit::defaultOptions() { return CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble - | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; + | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion + | CXTranslationUnit_DetailedPreprocessingRecord; } uint TranslationUnit::unsavedFilesCount() const diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h index e44852e473..fd3831cb3e 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.h +++ b/src/tools/clangbackend/ipcsource/translationunit.h @@ -52,8 +52,13 @@ class ProjectPart; class DiagnosticContainer; class DiagnosticSet; class FileContainer; +class HighlightingInformations; class TranslationUnits; class CommandLineArguments; +class Cursor; +class SourceLocation; +class SourceRange; +class SkippedSourceRanges; using time_point = std::chrono::steady_clock::time_point; @@ -111,6 +116,19 @@ public: CommandLineArguments commandLineArguments() const; + SourceLocation sourceLocationAt(uint line, uint column) const; + SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const; + + SourceRange sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const; + + Cursor cursorAt(uint line, uint column) const; + Cursor cursorAt(const Utf8String &filePath, uint line, uint column) const; + Cursor cursor() const; + + HighlightingInformations highlightingInformationsInRange(const SourceRange &range) const; + + SkippedSourceRanges skippedSourceRanges() const; + private: void checkIfNull() const; void checkIfFileExists() const; diff --git a/src/tools/clangbackend/ipcsource/type.cpp b/src/tools/clangbackend/ipcsource/type.cpp new file mode 100644 index 0000000000..a1f78e44eb --- /dev/null +++ b/src/tools/clangbackend/ipcsource/type.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "type.h" + +#include "clangstring.h" +#include "cursor.h" + +#include <utf8string.h> + +#include <ostream> + +namespace ClangBackEnd { + +bool Type::isConstant() const +{ + return clang_isConstQualifiedType(cxType); +} + +bool Type::isConstantReference() +{ + return isLValueReference() && pointeeType().isConstant(); +} + +bool Type::isPointer() const +{ + return cxType.kind == CXType_Pointer; +} + +bool Type::isPointerToConstant() const +{ + return isPointer() && pointeeType().isConstant(); +} + +bool Type::isConstantPointer() const +{ + return isPointer() && isConstant(); +} + +bool Type::isLValueReference() const +{ + return cxType.kind == CXType_LValueReference; +} + +bool Type::isReferencingConstant() const +{ + return (isPointer() || isLValueReference()) && pointeeType().isConstant(); +} + +bool Type::isOutputParameter() const +{ + return (isPointer() || isLValueReference()) && !pointeeType().isConstant(); +} + +Utf8String Type::utf8Spelling() const +{ + return ClangString(clang_getTypeSpelling(cxType)); +} + +ClangString Type::spelling() const +{ + return ClangString(clang_getTypeSpelling(cxType)); +} + +int Type::argumentCount() const +{ + return clang_getNumArgTypes(cxType); +} + +Type Type::alias() const +{ + return clang_getTypedefDeclUnderlyingType(clang_getTypeDeclaration(cxType)); +} + +Type Type::canonical() const +{ + return clang_getCanonicalType(cxType); +} + +Type Type::classType() const +{ + return clang_Type_getClassType(cxType); +} + +Type Type::pointeeType() const +{ + return clang_getPointeeType(cxType); +} + +Type Type::argument(int index) const +{ + return clang_getArgType(cxType, index); +} + +Cursor Type::declaration() const +{ + return clang_getTypeDeclaration(cxType); +} + +CXTypeKind Type::kind() const +{ + return cxType.kind; +} + +Type::Type(CXType cxType) + : cxType(cxType) +{ +} + +bool operator==(Type first, Type second) +{ + return clang_equalTypes(first.cxType, second.cxType); +} + +void PrintTo(CXTypeKind typeKind, ::std::ostream* os) +{ + ClangString typeKindSpelling(clang_getTypeKindSpelling(typeKind)); + *os << typeKindSpelling.cString(); +} + +void PrintTo(const Type &type, ::std::ostream* os) +{ + ClangString typeKindSpelling(clang_getTypeKindSpelling(type.kind())); + *os << typeKindSpelling.cString() + << ": \"" << type.spelling().cString() << "\""; +} + + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/type.h b/src/tools/clangbackend/ipcsource/type.h new file mode 100644 index 0000000000..099bfa4e3e --- /dev/null +++ b/src/tools/clangbackend/ipcsource/type.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_TYPE_H +#define CLANGBACKEND_TYPE_H + +#include <clang-c/Index.h> + +#include <iosfwd> + +class Utf8String; + +namespace ClangBackEnd { + +class Cursor; +class ClangString; + +class Type +{ + friend class Cursor; + friend bool operator==(Type first, Type second); + +public: + bool isConstant() const; + bool isConstantReference(); + bool isPointer() const; + bool isPointerToConstant() const; + bool isConstantPointer() const; + bool isLValueReference() const; + bool isReferencingConstant() const; + bool isOutputParameter() const; + + Utf8String utf8Spelling() const; + ClangString spelling() const; + int argumentCount() const; + + Type alias() const; + Type canonical() const; + Type classType() const; + Type pointeeType() const; + Type argument(int index) const; + + Cursor declaration() const; + + CXTypeKind kind() const; + +private: + Type(CXType cxType); + +private: + CXType cxType; +}; + +bool operator==(Type first, Type second); + +void PrintTo(CXTypeKind typeKind, ::std::ostream* os); +void PrintTo(const Type &type, ::std::ostream* os); +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_TYPE_H diff --git a/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp index 5c2be00058..3b7e4c52d0 100644 --- a/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp +++ b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp @@ -65,12 +65,12 @@ class MkVisitor: protected SymbolVisitor { const LookupContext &context; Overview oo; - QList<LookupScope *> interfaces; - QList<LookupScope *> nodes; + QList<ClassOrNamespace *> interfaces; + QList<ClassOrNamespace *> nodes; - bool isMiscNode(LookupScope *b) const + bool isMiscNode(ClassOrNamespace *b) const { - foreach (LookupScope *u, b->usings()) { + foreach (ClassOrNamespace *u, b->usings()) { if (oo(u->symbols().first()->name()) == QLatin1String("AST")) return true; } @@ -78,7 +78,7 @@ class MkVisitor: protected SymbolVisitor return false; } - QString getAcceptFunctionName(LookupScope *b, QString *retType) const + QString getAcceptFunctionName(ClassOrNamespace *b, QString *retType) const { Q_ASSERT(b != 0); @@ -131,7 +131,7 @@ public: << " Semantic(TranslationUnit *unit): ASTVisitor(unit) { translationUnit(unit->ast()->asTranslationUnit()); }" << std::endl << std::endl; - foreach (LookupScope *b, interfaces) { + foreach (ClassOrNamespace *b, interfaces) { Q_ASSERT(! b->symbols().isEmpty()); Class *klass = 0; @@ -162,10 +162,10 @@ public: std::cout << " using ASTVisitor::translationUnit;" << std::endl << std::endl; - QHash<LookupScope *, QList<LookupScope *> > implements; - foreach (LookupScope *b, nodes) { - LookupScope *iface = 0; - foreach (LookupScope *u, b->usings()) { + QHash<ClassOrNamespace *, QList<ClassOrNamespace *> > implements; + foreach (ClassOrNamespace *b, nodes) { + ClassOrNamespace *iface = 0; + foreach (ClassOrNamespace *u, b->usings()) { if (interfaces.contains(u)) { iface = u; break; @@ -175,8 +175,8 @@ public: implements[iface].append(b); } - foreach (LookupScope *iface, interfaces) { - foreach (LookupScope *b, implements.value(iface)) { + foreach (ClassOrNamespace *iface, interfaces) { + foreach (ClassOrNamespace *b, implements.value(iface)) { if (! isMiscNode(b)) continue; @@ -195,9 +195,9 @@ public: std::cout << std::endl; - foreach (LookupScope *iface, interfaces) { + foreach (ClassOrNamespace *iface, interfaces) { std::cout << " // " << qPrintable(oo(iface->symbols().first()->name())) << std::endl; - foreach (LookupScope *b, implements.value(iface)) { + foreach (ClassOrNamespace *b, implements.value(iface)) { Class *klass = 0; foreach (Symbol *s, b->symbols()) if ((klass = s->asClass()) != 0) @@ -212,7 +212,7 @@ public: } std::cout << "private:" << std::endl; - foreach (LookupScope *b, interfaces) { + foreach (ClassOrNamespace *b, interfaces) { Q_ASSERT(! b->symbols().isEmpty()); Class *klass = 0; @@ -245,7 +245,7 @@ public: // implementation - foreach (LookupScope *b, interfaces) { + foreach (ClassOrNamespace *b, interfaces) { Q_ASSERT(! b->symbols().isEmpty()); Class *klass = 0; @@ -280,9 +280,9 @@ public: << std::endl; } - foreach (LookupScope *iface, interfaces) { + foreach (ClassOrNamespace *iface, interfaces) { std::cout << "// " << qPrintable(oo(iface->symbols().first()->name())) << std::endl; - foreach (LookupScope *b, implements.value(iface)) { + foreach (ClassOrNamespace *b, implements.value(iface)) { Class *klass = 0; foreach (Symbol *s, b->symbols()) if ((klass = s->asClass()) != 0) @@ -331,7 +331,7 @@ public: Control *control = context.thisDocument()->control(); const Name *n = control->identifier(name.toLatin1().constData()); - if (LookupScope *bb = context.lookupType(n, klass)) { + if (ClassOrNamespace *bb = context.lookupType(n, klass)) { QString retTy; QString funcName = getAcceptFunctionName(bb, &retTy); Q_ASSERT(! funcName.isEmpty()); @@ -350,7 +350,7 @@ public: continue; } - if (LookupScope *ty = context.lookupType(namedTy->name(), klass)) { + if (ClassOrNamespace *ty = context.lookupType(namedTy->name(), klass)) { QString className = oo(ty->symbols().first()->name()); QString baseClassName = className; if (baseClassName.endsWith(QLatin1String("AST"))) { @@ -386,9 +386,9 @@ public: protected: using SymbolVisitor::visit; - QList<LookupScope *> baseClasses(LookupScope *b) { - QList<LookupScope *> usings = b->usings(); - foreach (LookupScope *u, usings) + QList<ClassOrNamespace *> baseClasses(ClassOrNamespace *b) { + QList<ClassOrNamespace *> usings = b->usings(); + foreach (ClassOrNamespace *u, usings) usings += baseClasses(u); return usings; } @@ -398,14 +398,14 @@ protected: if (! className.endsWith(QLatin1String("AST"))) return false; - LookupScope *b = context.lookupType(klass); + ClassOrNamespace *b = context.lookupType(klass); Q_ASSERT(b != 0); const Identifier *accept0 = context.thisDocument()->control()->identifier("accept0"); if (Symbol *s = klass->find(accept0)) { if (Function *meth = s->type()->asFunctionType()) { if (! meth->isPureVirtual()) { - foreach (LookupScope *u, b->usings()) { + foreach (ClassOrNamespace *u, b->usings()) { if (interfaces.contains(u)) { // qDebug() << oo(klass->name()) << "implements" << oo(u->symbols().first()->name()); } else { diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index a2219e7cfc..aa42b2b3ec 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -208,6 +208,8 @@ private slots: void expensiveExpression(); void invalidCode_data(); void invalidCode(); + void enumDeclaration(); + void invalidEnumClassDeclaration(); }; void tst_AST::gcc_attributes_1() @@ -1982,6 +1984,28 @@ void tst_AST::invalidCode() QVERIFY(diag.errorCount != 0); } +void tst_AST::enumDeclaration() +{ + QSharedPointer<TranslationUnit> unit(parseStatement( + //Unnamed + "enum { ENUMERATOR0 };\n" + "enum Enum { ENUMERATOR1 };\n" + "enum EnumWithBase : int { ENUMERATOR2 };\n" + "enum enum : int { ENUMERATOR2a };\n" + "enum class EnumClass { ENUMERATOR3 = 10 };\n", true)); + + QVERIFY(unit->ast()); + QCOMPARE(diag.errorCount, 0); +} + +void tst_AST::invalidEnumClassDeclaration() +{ + QSharedPointer<TranslationUnit> unit(parseStatement( + "enum class operator A { };", true)); + + QVERIFY(diag.errorCount != 0); +} + void tst_AST::initTestCase() { control.setDiagnosticClient(&diag); diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index 3a39909e3c..683513f12b 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -115,7 +115,6 @@ public: // Process source const Document::Ptr document = createDocument(filePath, source); - QVERIFY(document); Snapshot snapshot; snapshot.insert(document); @@ -225,8 +224,6 @@ private slots: void test_checksymbols_infiniteLoop_data(); void test_checksymbols_infiniteLoop(); - void test_checksymbols_infiniteLoop_BUG15141(); - void test_parentOfBlock(); void findField(); @@ -1173,25 +1170,6 @@ void tst_CheckSymbols::test_checksymbols_infiniteLoop() TestCase::runCheckSymbols(document1, snapshot); } -void tst_CheckSymbols::test_checksymbols_infiniteLoop_BUG15141() -{ - QByteArray source = - "template <class R1>\n" - "struct Base\n" - "{\n" - "};\n" - "\n" - "template<typename R>\n" - "struct Derived :\n" - " Base<\n" - " typename Derived<typename Base<R>::type>::type,\n" - " typename Derived<typename Base<R>::type>::type\n" - " >::type\n" - "{};\n"; - - BaseTestCase tc(source); -} - void tst_CheckSymbols::test_parentOfBlock() { const QByteArray source = "void C::f()\n" @@ -1286,8 +1264,13 @@ void tst_CheckSymbols::findField() source[position] = ' '; BaseTestCase tc(source); Use use = tc.findUse(line, column); - + QEXPECT_FAIL("pointer_indirect_specialization", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("pointer_indirect_specialization_typedef", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("pointer_indirect_specialization_double_indirection", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("instantiation_of_pointer_typedef_in_block", "QTCREATORBUG-14141", Abort); + QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort); QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort); + QEXPECT_FAIL("recursive_instantiation_of_template_type_2", "QTCREATORBUG-14141", Abort); QVERIFY(use.isValid()); QVERIFY(use.kind == Highlighting::FieldUse); } @@ -1364,26 +1347,6 @@ void tst_CheckSymbols::findField_data() "}\n" ); - QTest::newRow("instantiation_of_indirect_typedef") << _( - "template<typename _Tp>\n" - "struct Indirect { _Tp t; };\n" - "\n" - "template<typename T>\n" - "struct Temp\n" - "{\n" - " typedef T MyT;\n" - " typedef Indirect<MyT> indirect;\n" - "};\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " Temp<Foo>::indirect i;\n" - " i.t.@bar;\n" - "}\n" - ); - QTest::newRow("pointer_indirect_specialization_double_indirection") << _( "template<typename _Tp>\n" "struct Traits { };\n" @@ -1475,100 +1438,6 @@ void tst_CheckSymbols::findField_data() " p->@bar;\n" "}\n" ); - - QTest::newRow("std vector") << _( - "namespace std\n" - "{\n" - "template<typename _Tp>\n" - "struct allocator\n" - "{\n" - " typedef _Tp value_type;\n" - "\n" - " template<typename _Tp1>\n" - " struct rebind\n" - " { typedef allocator<_Tp1> other; };\n" - "};\n" - "\n" - "template<typename _Alloc, typename _Tp>\n" - "struct __alloctr_rebind\n" - "{\n" - " typedef typename _Alloc::template rebind<_Tp>::other __type;\n" - "};\n" - "\n" - "template<typename _Alloc>\n" - "struct allocator_traits\n" - "{\n" - " typedef typename _Alloc::value_type value_type;\n" - "\n" - " template<typename _Tp>\n" - " using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;\n" - "};\n" - "\n" - "template<typename _Iterator>\n" - "struct iterator_traits { };\n" - "\n" - "template<typename _Tp>\n" - "struct iterator_traits<_Tp*>\n" - "{\n" - " typedef _Tp* pointer;\n" - "};\n" - "} // namespace std\n" - "\n" - "namespace __gnu_cxx\n" - "{\n" - "template<typename _Alloc>\n" - "struct __alloc_traits\n" - "{\n" - " typedef _Alloc allocator_type;\n" - " typedef std::allocator_traits<_Alloc> _Base_type;\n" - " typedef typename _Alloc::value_type value_type;\n" - "\n" - " static value_type *_S_pointer_helper(...);\n" - " typedef decltype(_S_pointer_helper((_Alloc*)0)) __pointer;\n" - " typedef __pointer pointer;\n" - "\n" - " template<typename _Tp>\n" - " struct rebind\n" - " { typedef typename _Base_type::template rebind_alloc<_Tp> other; };\n" - "};\n" - "\n" - "template<typename _Iterator, typename _Container>\n" - "struct __normal_iterator\n" - "{\n" - " typedef std::iterator_traits<_Iterator> __traits_type;\n" - " typedef typename __traits_type::pointer pointer;\n" - "\n" - " pointer p;\n" - "};\n" - "} // namespace __gnu_cxx\n" - "\n" - "namespace std {\n" - "template<typename _Tp, typename _Alloc>\n" - "struct _Vector_Base\n" - "{\n" - " typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template\n" - " rebind<_Tp>::other _Tp_alloc_type;\n" - " typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer\n" - " pointer;\n" - "};\n" - "\n" - "template<typename _Tp, typename _Alloc = std::allocator<_Tp> >\n" - "struct vector : protected _Vector_Base<_Tp, _Alloc>\n" - "{\n" - " typedef _Vector_Base<_Tp, _Alloc> _Base;\n" - " typedef typename _Base::pointer pointer;\n" - " typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;\n" - "};\n" - "} // namespace std\n" - "\n" - "struct Foo { int bar; };\n" - "\n" - "void func()\n" - "{\n" - " std::vector<Foo>::iterator it;\n" - " it.p->@bar;\n" - "}\n" - ); } QTEST_APPLESS_MAIN(tst_CheckSymbols) diff --git a/tests/auto/cplusplus/lookup/tst_lookup.cpp b/tests/auto/cplusplus/lookup/tst_lookup.cpp index deab703a8f..8347749f43 100644 --- a/tests/auto/cplusplus/lookup/tst_lookup.cpp +++ b/tests/auto/cplusplus/lookup/tst_lookup.cpp @@ -133,7 +133,7 @@ void tst_Lookup::base_class_defined_1() const LookupContext ctx(doc, snapshot); - LookupScope *klass = ctx.lookupType(derivedClass->baseClassAt(0)->name(), derivedClass->enclosingScope()); + ClassOrNamespace *klass = ctx.lookupType(derivedClass->baseClassAt(0)->name(), derivedClass->enclosingScope()); QVERIFY(klass != 0); QCOMPARE(klass->symbols().size(), 1); @@ -272,7 +272,7 @@ void tst_Lookup::simple_class_1() const LookupContext context(doc, snapshot); // check class resolving: - LookupScope *klass = context.lookupType(impl->name(), impl->enclosingScope()); + ClassOrNamespace *klass = context.lookupType(impl->name(), impl->enclosingScope()); QVERIFY(klass != 0); QCOMPARE(klass->symbols().size(), 2); QVERIFY(klass->symbols().contains(iface)); @@ -336,7 +336,7 @@ void tst_Lookup::class_with_baseclass() const LookupContext context(doc, snapshot); - LookupScope *objClass = context.lookupType(baseZoo->name(), zooImpl->enclosingScope()); + ClassOrNamespace *objClass = context.lookupType(baseZoo->name(), zooImpl->enclosingScope()); QVERIFY(objClass != 0); QVERIFY(objClass->symbols().contains(baseZoo)); diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index 4717c5fc22..2011f03e00 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -38,6 +38,7 @@ #include <cplusplus/Bind.h> #include <cplusplus/Control.h> #include <cplusplus/CoreTypes.h> +#include <cplusplus/DeprecatedGenTemplateInstance.h> #include <cplusplus/DiagnosticClient.h> #include <cplusplus/ExpressionUnderCursor.h> #include <cplusplus/Literals.h> @@ -47,7 +48,6 @@ #include <cplusplus/Parser.h> #include <cplusplus/Scope.h> #include <cplusplus/Symbols.h> -#include <cplusplus/Templates.h> //TESTED_COMPONENT=src/libs/cplusplus @@ -166,7 +166,6 @@ private slots: void pointer_to_function_1(); void template_instance_1(); - void explicit_instantiation_1(); void expression_under_cursor_1(); @@ -512,37 +511,17 @@ void tst_Semantic::template_instance_1() QVERIFY(decl); FullySpecifiedType templArgs[] = { control->integerType(IntegerType::Int) }; - Clone cloner(control.data()); - Class *clone = cloner.instantiate(templ, templArgs, 1)->asClass(); - QVERIFY(clone); + const Name *templId = control->templateNameId(control->identifier("QList"), false, templArgs, 1); + + FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, control); Overview oo; oo.showReturnTypes = true; - Declaration *clonedDecl = clone->memberAt(0)->asDeclaration(); - const QString genDecl = oo.prettyType(clonedDecl->type()); + const QString genDecl = oo.prettyType(genTy); QCOMPARE(genDecl, QString::fromLatin1("void (const int &)")); } -void tst_Semantic::explicit_instantiation_1() -{ - QSharedPointer<Document> doc = document("template class basic_string<char>;"); - QCOMPARE(doc->errorCount, 0U); - QCOMPARE(doc->globals->memberCount(), 1U); - - ExplicitInstantiation *inst = doc->globals->memberAt(0)->asExplicitInstantiation(); - QVERIFY(inst); - - ForwardClassDeclaration *fwd = inst->memberAt(0)->asForwardClassDeclaration(); - QVERIFY(fwd); - - QVERIFY(inst->name()->match(fwd->name())); - - Overview oo; - const QString name = oo.prettyName(inst->name()); - QCOMPARE(name, QString::fromLatin1("basic_string<char>")); -} - void tst_Semantic::expression_under_cursor_1() { const QString plainText = "void *ptr = foo(10, bar"; diff --git a/tests/system/suite_WELP/tst_WELP04/test.py b/tests/system/suite_WELP/tst_WELP04/test.py index 9cc23275d0..cf10169042 100644 --- a/tests/system/suite_WELP/tst_WELP04/test.py +++ b/tests/system/suite_WELP/tst_WELP04/test.py @@ -81,7 +81,7 @@ def main(): replaceEditorContent(searchTutWidget, "embedded device") test.verify(checkIfObjectExists(getQmlItem("Delegate", welcomePage, False, "id='delegate' radius='0' caption=" - "'Device Creation with Qt'")), + "'Qt for Device Creation'")), "Verifying: Link to the expected demonstration video exists.") # exit Qt Creator invokeMenuItem("File", "Exit") diff --git a/tests/unit/unittest/clangstringtest.cpp b/tests/unit/unittest/clangstringtest.cpp index 0467de693d..b7ee1982b9 100644 --- a/tests/unit/unittest/clangstringtest.cpp +++ b/tests/unit/unittest/clangstringtest.cpp @@ -42,6 +42,8 @@ namespace { +using ::testing::StrEq; + using ClangBackEnd::ClangString; TEST(ClangString, ConvertToUtf8String) @@ -87,4 +89,11 @@ TEST(ClangString, MoveSelfAssigment) ASSERT_FALSE(text.isNull()); } + +TEST(ClangString, SpellingAsCString) +{ + ClangString text(CXString{"text", 0}); + + ASSERT_THAT(text.cString(), StrEq("text")); +} } diff --git a/tests/unit/unittest/cursortest.cpp b/tests/unit/unittest/cursortest.cpp new file mode 100644 index 0000000000..e0e18c1308 --- /dev/null +++ b/tests/unit/unittest/cursortest.cpp @@ -0,0 +1,819 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include <clangstring.h> +#include <cursor.h> +#include <projectpart.h> +#include <projects.h> +#include <sourcelocation.h> +#include <sourcerange.h> +#include <translationunit.h> +#include <translationunits.h> +#include <unsavedfiles.h> + +#include <gmock/gmock.h> +#include <gmock/gmock-matchers.h> +#include <gtest/gtest.h> +#include "gtest-qt-printing.h" + +using ClangBackEnd::Cursor; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::UnsavedFiles; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::TranslationUnits; +using ClangBackEnd::ClangString; +using ClangBackEnd::SourceRange; + +using testing::IsNull; +using testing::NotNull; +using testing::Gt; +using testing::Contains; +using testing::EndsWith; +using testing::AllOf; +using testing::Not; +using testing::IsEmpty; +using testing::StrEq; + +namespace { + +struct Data { + ClangBackEnd::ProjectParts projects; + ClangBackEnd::UnsavedFiles unsavedFiles; + ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles}; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/cursor.cpp"), + ProjectPart(Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++11")}), + {}, + translationUnits}; +}; + +class Cursor : public ::testing::Test +{ +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + +protected: + static Data *d; + const TranslationUnit &translationUnit = d->translationUnit; + + +}; + +TEST_F(Cursor, CreateNullCursor) +{ + ::Cursor cursor; + + ASSERT_TRUE(cursor.isNull()); +} + +TEST_F(Cursor, CompareNullCursors) +{ + ::Cursor cursor; + ::Cursor cursor2; + + ASSERT_THAT(cursor, cursor2); +} + +TEST_F(Cursor, IsNotValid) +{ + ::Cursor cursor; + + ASSERT_FALSE(cursor.isValid()); +} + +TEST_F(Cursor, IsValid) +{ + auto cursor = translationUnit.cursor(); + + ASSERT_TRUE(cursor.isValid()); +} + +TEST_F(Cursor, IsTranslationUnit) +{ + auto cursor = translationUnit.cursor(); + + ASSERT_TRUE(cursor.isTranslationUnit()); +} + +TEST_F(Cursor, NullCursorIsNotTranslationUnit) +{ + ::Cursor cursor; + + ASSERT_FALSE(cursor.isTranslationUnit()); +} + +TEST_F(Cursor, UnifiedSymbolResolution) +{ + ::Cursor cursor; + + ASSERT_TRUE(cursor.unifiedSymbolResolution().isEmpty()); +} + +TEST_F(Cursor, GetCursorAtLocation) +{ + auto cursor = translationUnit.cursorAt(3, 6); + + ASSERT_THAT(cursor.unifiedSymbolResolution(), Utf8StringLiteral("c:@F@function#I#")); +} + +TEST_F(Cursor, GetCursoSourceLocation) +{ + auto cursor = translationUnit.cursorAt(3, 6); + + ASSERT_THAT(cursor.sourceLocation(), translationUnit.sourceLocationAt(3, 6)); +} + +TEST_F(Cursor, GetCursoSourceRange) +{ + auto cursor = translationUnit.cursorAt(3, 6); + + ASSERT_THAT(cursor.sourceRange(), SourceRange(translationUnit.sourceLocationAt(3, 1), + translationUnit.sourceLocationAt(6, 2))); +} + +TEST_F(Cursor, Mangling) +{ + auto cursor = translationUnit.cursorAt(3, 6); + + + ASSERT_THAT(cursor.mangling(), Utf8StringLiteral("_Z8functioni")); +} + +TEST_F(Cursor, Spelling) +{ + auto cursor = translationUnit.cursorAt(3, 6); + + + ASSERT_THAT(cursor.spelling().cString(), StrEq("function")); +} + +TEST_F(Cursor, DisplayName) +{ + auto cursor = translationUnit.cursorAt(3, 6); + + + ASSERT_THAT(cursor.displayName(), Utf8StringLiteral("function(int)")); +} + +TEST_F(Cursor, BriefComment) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + + ASSERT_THAT(cursor.briefComment(), Utf8StringLiteral("A brief comment")); +} + +TEST_F(Cursor, RawComment) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + + ASSERT_THAT(cursor.rawComment(), Utf8StringLiteral("/**\n * A brief comment\n */")); +} + +TEST_F(Cursor, CommentRange) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + + ASSERT_THAT(cursor.commentRange(), + SourceRange(translationUnit.sourceLocationAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 7, 1), + translationUnit.sourceLocationAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 9, 4))); +} + +TEST_F(Cursor, IsDefinition) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + ASSERT_TRUE(cursor.isDefinition()); +} + +TEST_F(Cursor, ForwardDeclarationIsNotDefinition) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 6, 7); + + ASSERT_FALSE(cursor.isDefinition()); +} + +TEST_F(Cursor, GetDefinitionOfFowardDeclaration) +{ + auto forwardDeclarationcursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 6, 7); + auto definitionCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + ASSERT_THAT(forwardDeclarationcursor.definition(), definitionCursor); +} + +TEST_F(Cursor, CallToMethodeIsNotDynamic) +{ + auto cursor = translationUnit.cursorAt(18, 5); + + ASSERT_FALSE(cursor.isDynamicCall()); +} + +TEST_F(Cursor, CallToAbstractVirtualMethodeIsDynamic) +{ + auto cursor = translationUnit.cursorAt(19, 5); + + ASSERT_TRUE(cursor.isDynamicCall()); +} + +TEST_F(Cursor, CanonicalCursor) +{ + auto forwardDeclarationcursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 6, 7); + auto definitionCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + ASSERT_THAT(definitionCursor.canonical(), forwardDeclarationcursor); +} + +TEST_F(Cursor, ReferencedCursor) +{ + auto functionCallCursor = translationUnit.cursorAt(18, 5); + auto functionCursor = translationUnit.cursorAt(16, 17); + + ASSERT_THAT(functionCallCursor.referenced(), functionCursor); +} + +TEST_F(Cursor, IsVirtual) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 15, 17); + + ASSERT_TRUE(cursor.isVirtualMethod()); +} + +TEST_F(Cursor, IsNotPureVirtualOnlyVirtual) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 15, 17); + + ASSERT_FALSE(cursor.isPureVirtualMethod()); +} + +TEST_F(Cursor, IsPureVirtual) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 16, 17); + + ASSERT_TRUE(cursor.isPureVirtualMethod()); +} + +TEST_F(Cursor, ConstantMethod) +{ + auto cursor = translationUnit.cursorAt(31, 18); + + ASSERT_TRUE(cursor.isConstantMethod()); +} + +TEST_F(Cursor, IsStaticMethod) +{ + auto cursor = translationUnit.cursorAt(36, 18); + + ASSERT_TRUE(cursor.isStaticMethod()); +} + +TEST_F(Cursor, TypeSpelling) +{ + auto cursor = translationUnit.cursorAt(43, 5); + + ASSERT_THAT(cursor.type().utf8Spelling(), Utf8StringLiteral("lint")); +} + +TEST_F(Cursor, CanonicalTypeSpelling) +{ + auto cursor = translationUnit.cursorAt(43, 5); + + ASSERT_THAT(cursor.type().canonical().utf8Spelling(), Utf8StringLiteral("long long")); +} + +TEST_F(Cursor, CanonicalTypeCStringSpelling) +{ + auto cursor = translationUnit.cursorAt(43, 5); + + auto spelling = cursor.type().canonical().spelling(); + + ASSERT_THAT(spelling.cString(), StrEq("long long")); +} + +TEST_F(Cursor, CanonicalTypeIsNotType) +{ + auto cursor = translationUnit.cursorAt(43, 5); + + ASSERT_THAT(cursor.type().canonical(), Not(cursor.type())); +} + +TEST_F(Cursor, TypeDeclartionIsAlias) +{ + auto declarationCursor = translationUnit.cursorAt(41, 5); + auto lintCursor = translationUnit.cursorAt(39, 11); + + ASSERT_THAT(declarationCursor.type().declaration().type(), lintCursor.type()); +} + +TEST_F(Cursor, TypeIsConstantWithoutAliasLookup) +{ + auto cursor = translationUnit.cursorAt(45, 16); + + ASSERT_TRUE(cursor.type().isConstant()); +} + +TEST_F(Cursor, ClassIsCompoundType) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7); + + ASSERT_TRUE(cursor.isCompoundType()); +} + +TEST_F(Cursor, StructIsCompoundType) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8); + + ASSERT_TRUE(cursor.isCompoundType()); +} + +TEST_F(Cursor, UnionIsCompoundType) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 33, 7); + + ASSERT_TRUE(cursor.isCompoundType()); +} + +TEST_F(Cursor, IsDeclaration) +{ + auto cursor = translationUnit.cursorAt(41, 10); + + ASSERT_TRUE(cursor.isDeclaration()); +} + +TEST_F(Cursor, SemanticParent) +{ + auto cursor = translationUnit.cursorAt(43, 6); + auto expectedSemanticParent = translationUnit.cursorAt(36, 18); + + auto semanticParent = cursor.semanticParent(); + + ASSERT_THAT(semanticParent, expectedSemanticParent); +} + +TEST_F(Cursor, IsLocalVariableInMethod) +{ + auto cursor = translationUnit.cursorAt(20, 9); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, IsLocalVariableInStaticFunction) +{ + auto cursor = translationUnit.cursorAt(43, 5); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, IsLocalVariableInTemplateFunction) +{ + auto cursor = translationUnit.cursorAt(52, 7); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, IsLocalVariableInConversionOperator) +{ + auto cursor = translationUnit.cursorAt(57, 9); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, IsLocalVariableInOperator) +{ + auto cursor = translationUnit.cursorAt(62, 9); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, IsLocalVariableInConstructor) +{ + auto cursor = translationUnit.cursorAt(13, 9); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, IsLocalVariableInDestructor) +{ + auto cursor = translationUnit.cursorAt(69, 9); + + ASSERT_TRUE(cursor.isLocalVariable()); +} + +TEST_F(Cursor, FindFunctionCaller) +{ + auto functionCursor = translationUnit.cursorAt(92, 24); + auto structCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8); + + ASSERT_THAT(functionCursor.functionBaseDeclaration(), structCursor); +} + +TEST_F(Cursor, FindFunctionCallerPointer) +{ + auto functionCursor = translationUnit.cursorAt(79, 25); + auto structCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8); + + ASSERT_THAT(functionCursor.functionBaseDeclaration(), structCursor); +} + +TEST_F(Cursor, FindFunctionCallerThis) +{ + auto functionCursor = translationUnit.cursorAt(106, 5); + auto structCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 38, 8); + + ASSERT_THAT(functionCursor.functionBaseDeclaration(), structCursor); +} + +TEST_F(Cursor, NonPointerTypeForValue) +{ + auto variableCursor = translationUnit.cursorAt(101, 10); + auto variablePointerCursor = translationUnit.cursorAt(100, 11); + + ASSERT_THAT(variableCursor.nonPointerTupe(), variablePointerCursor.nonPointerTupe()); +} + +TEST_F(Cursor, HasFinalAttributeInFunction) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 30, 18); + + ASSERT_TRUE(cursor.hasFinalFunctionAttribute()); +} + +TEST_F(Cursor, HasNotFinalAttributeInFunction) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 15, 17); + + ASSERT_FALSE(cursor.hasFinalFunctionAttribute()); +} + +TEST_F(Cursor, HasFinalAttributeInClass) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8); + + ASSERT_TRUE(cursor.hasFinalClassAttribute()); +} + +TEST_F(Cursor, HasNotFinaAttributeInClass) +{ + auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 38, 8); + + ASSERT_FALSE(cursor.hasFinalClassAttribute()); +} + +TEST_F(Cursor, HasOutputValues) +{ + auto callExpressionCursor = translationUnit.cursorAt(117, 19); + auto outputArgumentExpectedCursor = translationUnit.cursorAt(117, 20); + + auto outputArguments = callExpressionCursor.outputArguments(); + + ASSERT_THAT(outputArguments.size(), 1); + ASSERT_THAT(outputArguments[0], outputArgumentExpectedCursor); +} + +TEST_F(Cursor, HasOnlyInputValues) +{ + auto callExpressionCursor = translationUnit.cursorAt(118, 18); + + auto outputArguments = callExpressionCursor.outputArguments(); + + ASSERT_THAT(outputArguments, IsEmpty()); +} + +TEST_F(Cursor, ArgumentCountIsZero) +{ + auto cursor = translationUnit.cursorAt(121, 23); + + auto count = cursor.type().argumentCount(); + + ASSERT_THAT(count, 0); +} + +TEST_F(Cursor, ArgumentCountIsTwo) +{ + auto cursor = translationUnit.cursorAt(122, 22); + + auto count = cursor.type().argumentCount(); + + ASSERT_THAT(count, 2); +} + +TEST_F(Cursor, ArgumentOneIsValue) +{ + auto callExpressionCursor = translationUnit.cursorAt(122, 22); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isConstant()); + ASSERT_THAT(argument.kind(), CXType_Int); +} + +TEST_F(Cursor, ArgumentTwoIsLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(122, 22); + + auto argument = callExpressionCursor.type().argument(1); + + ASSERT_THAT(argument.kind(), CXType_LValueReference); +} + +TEST_F(Cursor, ArgumentTwoIsConstantReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(122, 22); + + auto argumentPointee = callExpressionCursor.type().argument(1); + + ASSERT_TRUE(argumentPointee.isConstantReference()); +} + +TEST_F(Cursor, CursorArgumentCount) +{ + auto cursor = translationUnit.cursorAt(117, 19); + + ASSERT_THAT(cursor.kind(), CXCursor_CallExpr); + ASSERT_THAT(cursor.argumentCount(), 4); +} + +TEST_F(Cursor, CursorArgumentInputValue) +{ + auto callExpressionCursor = translationUnit.cursorAt(117, 19); + auto declarationReferenceExpressionCursor = translationUnit.cursorAt(117, 20); + + ASSERT_THAT(callExpressionCursor.argument(0), declarationReferenceExpressionCursor); +} + +TEST_F(Cursor, IsConstantLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(125, 26); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isConstantReference()); +} + +TEST_F(Cursor, LValueReferenceIsNotConstantLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(124, 21); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isConstantReference()); +} + +TEST_F(Cursor, ValueIsNotConstantLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(123, 18); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isConstantReference()); +} + +TEST_F(Cursor, PointerToConstantNotConstantLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(126, 20); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isConstantReference()); +} + +TEST_F(Cursor, IsLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(124, 21); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isLValueReference()); +} + +TEST_F(Cursor, ConstantLValueReferenceIsLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(125, 26); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isLValueReference()); +} + +TEST_F(Cursor, ValueIsNotLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(123, 18); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isLValueReference()); +} + +TEST_F(Cursor, PointerIsNotLValueReference) +{ + auto callExpressionCursor = translationUnit.cursorAt(126, 20); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isLValueReference()); +} + +TEST_F(Cursor, PointerToConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(126, 20); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isPointerToConstant()); +} + +TEST_F(Cursor, ValueIsNotPointerToConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(123, 18); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isPointerToConstant()); +} + +TEST_F(Cursor, PointerNotPointerToConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(127, 13); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isPointerToConstant()); +} + +TEST_F(Cursor, ConstantLValueReferenceIsNotPointerToConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(125, 26); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isPointerToConstant()); +} + +TEST_F(Cursor, IsConstantPointer) +{ + auto callExpressionCursor = translationUnit.cursorAt(128, 21); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isConstantPointer()); +} + +TEST_F(Cursor, PointerToConstantIsNotConstantPointer) +{ + auto callExpressionCursor = translationUnit.cursorAt(126, 20); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isConstantPointer()); +} + +TEST_F(Cursor, ConstValueIsNotConstantPointer) +{ + auto callExpressionCursor = translationUnit.cursorAt(129, 23); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isConstantPointer()); +} + +TEST_F(Cursor, PointerToConstantIsReferencingConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(126, 20); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isReferencingConstant()); +} + +TEST_F(Cursor, ConstantReferenceIsReferencingConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(125, 26); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isReferencingConstant()); +} + +TEST_F(Cursor, LValueReferenceIsNotReferencingConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(124, 21); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isReferencingConstant()); +} + +TEST_F(Cursor, ValueIsNotReferencingConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(123, 18); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isReferencingConstant()); +} + +TEST_F(Cursor, PointerIsNotRefencingConstant) +{ + auto callExpressionCursor = translationUnit.cursorAt(127, 13); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isReferencingConstant()); +} + +TEST_F(Cursor, PointerIsOutputParameter) +{ + auto callExpressionCursor = translationUnit.cursorAt(127, 13); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isOutputParameter()); +} + +TEST_F(Cursor, ConstantReferenceIsNotOutputParameter) +{ + auto callExpressionCursor = translationUnit.cursorAt(125, 26); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isOutputParameter()); +} + +TEST_F(Cursor, PointerToConstantIsNotOutputParameter) +{ + auto callExpressionCursor = translationUnit.cursorAt(126, 20); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isOutputParameter()) << argument.isConstant() << argument.pointeeType().isConstant(); +} + +TEST_F(Cursor, ConstantPointerIsNotOutputParameter) +{ + auto callExpressionCursor = translationUnit.cursorAt(128, 21); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isOutputParameter()); +} + +TEST_F(Cursor, ReferenceIsOutputParameter) +{ + auto callExpressionCursor = translationUnit.cursorAt(124, 21); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_TRUE(argument.isOutputParameter()); +} + +TEST_F(Cursor, ConstReferenceIsNotOutputParameter) +{ + auto callExpressionCursor = translationUnit.cursorAt(125, 26); + + auto argument = callExpressionCursor.type().argument(0); + + ASSERT_FALSE(argument.isOutputParameter()); +} + +Data *Cursor::d; + +void Cursor::SetUpTestCase() +{ + d = new Data; +} + +void Cursor::TearDownTestCase() +{ + delete d; + d = nullptr; +} + +} diff --git a/tests/unit/unittest/data/cursor.cpp b/tests/unit/unittest/data/cursor.cpp new file mode 100644 index 0000000000..a492867dd6 --- /dev/null +++ b/tests/unit/unittest/data/cursor.cpp @@ -0,0 +1,129 @@ +#include "cursor.h" + +void function(int x) +{ + +} + +namespace Namespace +{ +SuperClass::SuperClass(int x) noexcept + : y(x) +{ + int LocalVariable; +} + +int SuperClass::Method() +{ + Method(); + AbstractVirtualMethod(y); + int LocalVariable; + return y; +} + +int SuperClass::VirtualMethod(int z) +{ + AbstractVirtualMethod(z); + + return y; +} + +bool SuperClass::ConstMethod() const +{ + return y; +} + +void SuperClass::StaticMethod() +{ + using longint = long long int; + using lint = longint; + + lint foo; + + foo = 30; + + const lint bar = 20; +} +} + +template <class T> +void TemplateFunction(T LocalVariableParameter) +{ + T LocalVariable; +} + +Namespace::SuperClass::operator int() const +{ + int LocalVariable; +} + +int Namespace::SuperClass::operator ++() const +{ + int LocalVariable; + + return LocalVariable; +} + +Namespace::SuperClass::~SuperClass() +{ + int LocalVariable; +} + +void Struct::FinalVirtualMethod() +{ + +} + +void f1(Struct *FindFunctionCaller) +{ + FindFunctionCaller->FinalVirtualMethod(); +} + +void f2(){ + Struct *s = new Struct; + + f1(s); +} + +void f3() +{ + auto FindFunctionCaller = Struct(); + + FindFunctionCaller.FinalVirtualMethod(); +} + + +void f4() +{ + Struct s; + + auto *sPointer = &s; + auto sValue = s; +} + +void NonFinalStruct::function() +{ + FinalVirtualMethod(); +} + +void OutputFunction(int &out, int in = 1, const int &in2=2, int *out2=nullptr); +void InputFunction(const int &value); + +void f5() +{ + int OutputValue; + int InputValue = 20; + + OutputFunction(OutputValue); + InputFunction(InputValue); +} + +void ArgumentCountZero(); +void ArgumentCountTwo(int one, const int &two); +void IntegerValue(int); +void LValueReference(int &); +void ConstLValueReference(const int &); +void PointerToConst(const int *); +void Pointer(int *); +void ConstantPointer(int *const); +void ConstIntegerValue(const int); diff --git a/tests/unit/unittest/data/cursor.h b/tests/unit/unittest/data/cursor.h new file mode 100644 index 0000000000..3e9e9a2bfb --- /dev/null +++ b/tests/unit/unittest/data/cursor.h @@ -0,0 +1,42 @@ + + + +namespace Namespace +{ +class SuperClass; +/** + * A brief comment + */ +class SuperClass +{ + SuperClass() = default; + SuperClass(int x) noexcept; + int Method(); + virtual int VirtualMethod(int z); + virtual int AbstractVirtualMethod(int z) = 0; + bool ConstMethod() const; + static void StaticMethod(); + operator int() const; + int operator ++() const; + ~SuperClass(); + +private: + int y; +}; +} + +struct Struct final +{ + virtual void FinalVirtualMethod() final; +}; + +union Union +{ + +}; + +struct NonFinalStruct +{ + virtual void FinalVirtualMethod() final; + void function(); +}; diff --git a/tests/unit/unittest/data/highlightinginformations.cpp b/tests/unit/unittest/data/highlightinginformations.cpp new file mode 100644 index 0000000000..d651fd65e1 --- /dev/null +++ b/tests/unit/unittest/data/highlightinginformations.cpp @@ -0,0 +1,385 @@ +auto *Variable = "Variable"; +auto *u8Variable = u8"Variable"; +auto *rawVariable = R"(Variable)"; +auto Character = 'c'; + + + + + + + + + + + + + + + + + + +auto integer = 1; +auto numFloat = 1.2f; + + + + + + + + + + + + + + + + + + + + +int function(int x) +{ + return x; +} + +struct Foo +{ + void memberFunction() {} +}; + +int functionDeclaration(int x); + +struct Foo2 +{ + void memberFunction(); +}; + +void f() +{ + function(1); +} + +struct ConversionFunction { + operator Foo(); + operator int(); +}; + +void TypeReference() +{ + Foo foo; +} + +void LocalVariableDeclaration() +{ + Foo foo; + + foo.memberFunction(); +} + +void LocalVariableFunctionArgument(Foo &foo) +{ + foo.memberFunction(); +} + +struct Foo3 { + int ClassMember; + + void ClassMemberReference() + { + ClassMember++; + } +}; + +struct Foo4 +{ + void MemberFunctionReference(); + + void function() + { + MemberFunctionReference(); + } +}; + +struct Foo5 +{ + void StaticMethod(); + + void function() + { + Foo5::StaticMethod(); + } +}; + +enum Enumeration +{ + Enumerator +}; + +void f2() +{ + Enumeration enumeration; + + enumeration = Enumerator; +} + +class ForwardReference; + +class Class +{ public: + Class(); + ~Class(); +}; + +ForwardReference *f3() +{ + Class ConstructorReference; + + return 0; +} + +union Union +{ + +}; + +Union UnionDeclarationReference; + + + + + + + + + +namespace NameSpace { +struct StructInNameSpace {}; +} + +namespace NameSpaceAlias = NameSpace; + +NameSpace::StructInNameSpace foo6; + +class BaseClass { +public: + virtual void VirtualFunction(); + virtual void FinalVirtualFunction(); +}; + + +void f8() +{ + BaseClass NonVirtualFunctionCall; + NonVirtualFunctionCall.VirtualFunction(); + + BaseClass *NonVirtualFunctionCallPointer = new BaseClass(); + NonVirtualFunctionCallPointer->VirtualFunction(); +} + +class DerivedClass : public BaseClass +{public: + void VirtualFunction() override; + void FinalVirtualFunction() final; +}; + +void f8(BaseClass *VirtualFunctionCallPointer) +{ + VirtualFunctionCallPointer->VirtualFunction(); +} + +class FinalClass final : public DerivedClass +{ + void FinalClassThisCall(); +}; + +void f8(DerivedClass *FinalVirtualFunctionCallPointer) +{ + FinalVirtualFunctionCallPointer->FinalVirtualFunction(); +} + +void f9(BaseClass *NonFinalVirtualFunctionCallPointer) +{ + NonFinalVirtualFunctionCallPointer->FinalVirtualFunction(); +} + +void f10(FinalClass *ClassFinalVirtualFunctionCallPointer) +{ + ClassFinalVirtualFunctionCallPointer->VirtualFunction(); +} + +class Operator { +public: + Operator operator+=(const Operator &first); +}; + +Operator operator+(const Operator &first, const Operator &second); + +void f10() +{ + auto PlusOperator = Operator() + Operator(); + Operator PlusAssignOperator; + PlusAssignOperator += Operator(); +} + +/* Comment */ + +#define PreprocessorDefinition Class +#define MacroDefinition(a,b) ((a)>(b)?(a):(b)) + +void f11() +{ + MacroDefinition(2, 4); +} + +#include "highlightinginformations.h" + +void f12() { +GOTO_LABEL: + + goto GOTO_LABEL; +} + +template <class T> +void TemplateFunction(T v) +{ + T XXXXX = v; +} +void TemplateReference() +{ + TemplateFunction(1); +// std::vector<int> TemplateIntance; +} + + + + +template <class T> +class TemplateFoo {}; + + +template <class TemplateTypeParameter = Foo, int NonTypeTemplateParameter = 1, template <class> class TemplateTemplateParameter = TemplateFoo> +void TemplateFunction(TemplateTypeParameter TemplateParameter) +{ + TemplateTypeParameter TemplateTypeParameterReference; + auto NonTypeTemplateParameterReference = NonTypeTemplateParameter; + TemplateTemplateParameter<TemplateTypeParameter> TemplateTemplateParameterReference; +} + + + +void FinalClass::FinalClassThisCall() +{ + VirtualFunction(); +} + + +void OutputParameter(int &one, const int &two, int *three=0); + +void f12() +{ + int One; + OutputParameter(One, 2); +} + +#include <highlightinginformations.h> + +#define FOREACH(variable, container) \ + variable; \ + auto x = container; + +#define foreach2 FOREACH + +#include <initializer_list> + +void f13() +{ + auto container = 1; + foreach2(int index, container); +} + +class SecondArgumentInMacroExpansionIsField { + int container = 1; + + void f() + { + foreach2(int index, container); + } +}; + +typedef unsigned uint32; + +enum EnumerationType : uint32 +{ + Other = 0, +}; + + +struct TypeInCast { + void function(); +}; + +void f14() +{ + static_cast<void (TypeInCast::*)()>(&TypeInCast::function); + reinterpret_cast<void (TypeInCast::*)()>(&TypeInCast::function); +} + +using IntegerAlias = int; +using SecondIntegerAlias = IntegerAlias; +using IntegerTypedef = int; +using Function = void (*)(); + + + +void f15() +{ + IntegerAlias integerAlias; + SecondIntegerAlias secondIntegerAlias; + IntegerTypedef integerTypedef; + Function(); +} + +class FriendFoo +{ +public: + friend class FooFriend; + friend bool operator==(const FriendFoo &first, const FriendFoo &second); +}; + +class FieldInitialization +{ +public: + FieldInitialization() : + member(0) + {} + + int member; +}; + +template<class Type> +void TemplateFunctionCall(Type type) +{ + type + type; +} + +void f16() +{ + TemplateFunctionCall(1); +} + + +template <typename T> +class TemplatedType +{ + T value = T(); +}; + +void f17() +{ + TemplatedType<int> TemplatedTypeDeclaration; +} diff --git a/tests/unit/unittest/data/highlightinginformations.h b/tests/unit/unittest/data/highlightinginformations.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/unit/unittest/data/highlightinginformations.h diff --git a/tests/unit/unittest/data/skippedsourceranges.cpp b/tests/unit/unittest/data/skippedsourceranges.cpp new file mode 100644 index 0000000000..775393fced --- /dev/null +++ b/tests/unit/unittest/data/skippedsourceranges.cpp @@ -0,0 +1,19 @@ +#if 0 + +void f(); + +#endif + +#ifndef BLAH +class Class +{ + +}; +#endif + +#ifdef BLAH +class Class +{ + +}; +#endif diff --git a/tests/unit/unittest/highlightinginformationstest.cpp b/tests/unit/unittest/highlightinginformationstest.cpp new file mode 100644 index 0000000000..c09f12cc17 --- /dev/null +++ b/tests/unit/unittest/highlightinginformationstest.cpp @@ -0,0 +1,902 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include <cursor.h> +#include <clangbackendipc_global.h> +#include <clangstring.h> +#include <projectpart.h> +#include <projects.h> +#include <sourcelocation.h> +#include <sourcerange.h> +#include <highlightinginformation.h> +#include <highlightinginformations.h> +#include <translationunit.h> +#include <translationunits.h> +#include <unsavedfiles.h> + +#include <gmock/gmock.h> +#include <gmock/gmock-matchers.h> +#include <gtest/gtest.h> +#include "gtest-qt-printing.h" + +using ClangBackEnd::Cursor; +using ClangBackEnd::HighlightingInformation; +using ClangBackEnd::HighlightingInformations; +using ClangBackEnd::HighlightingType; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::UnsavedFiles; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::TranslationUnits; +using ClangBackEnd::ClangString; +using ClangBackEnd::SourceRange; + +using testing::PrintToString; +using testing::IsNull; +using testing::NotNull; +using testing::Gt; +using testing::Contains; +using testing::EndsWith; +using testing::AllOf; +using testing::Not; +using testing::IsEmpty; +using testing::SizeIs; + +namespace { + +MATCHER_P4(IsHighlightingInformation, line, column, length, type, + std::string(negation ? "isn't " : "is ") + + PrintToString(HighlightingInformation(line, column, length, type)) + ) +{ + const HighlightingInformation expected(line, column, length, type); + + return arg == expected; +} + +MATCHER_P(HasType, type, + std::string(negation ? "isn't " : "is ") + + PrintToString(type) + ) +{ + return arg.hasType(type); +} + +struct Data { + ClangBackEnd::ProjectParts projects; + ClangBackEnd::UnsavedFiles unsavedFiles; + ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles}; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/highlightinginformations.cpp"), + ProjectPart(Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}), + {}, + translationUnits}; +}; + +class HighlightingInformations : public ::testing::Test +{ +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + SourceRange sourceRange(uint line, uint columnEnd) const; + +protected: + static Data *d; + const TranslationUnit &translationUnit = d->translationUnit; +}; + +TEST_F(HighlightingInformations, CreateNullInformations) +{ + ::HighlightingInformations infos; + + ASSERT_TRUE(infos.isNull()); +} + +TEST_F(HighlightingInformations, NullInformationsAreEmpty) +{ + ::HighlightingInformations infos; + + ASSERT_TRUE(infos.isEmpty()); +} + +TEST_F(HighlightingInformations, IsNotNull) +{ + const auto aRange = translationUnit.sourceRange(3, 1, 5, 1); + + const auto infos = translationUnit.highlightingInformationsInRange(aRange); + + ASSERT_FALSE(infos.isNull()); +} + +TEST_F(HighlightingInformations, IteratorBeginEnd) +{ + const auto aRange = translationUnit.sourceRange(3, 1, 5, 1); + const auto infos = translationUnit.highlightingInformationsInRange(aRange); + + const auto endIterator = std::next(infos.begin(), infos.size()); + + ASSERT_THAT(infos.end(), endIterator); +} + +TEST_F(HighlightingInformations, Size) +{ + const auto range = translationUnit.sourceRange(5, 5, 5, 10); + + const auto infos = translationUnit.highlightingInformationsInRange(range); + + ASSERT_THAT(infos.size(), 1); +} + +TEST_F(HighlightingInformations, DISABLED_Keyword) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(5, 12)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(5u, 5u, 6u, HighlightingType::Keyword)); +} + +TEST_F(HighlightingInformations, StringLiteral) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(1, 29)); + + ASSERT_THAT(infos[4], IsHighlightingInformation(1u, 24u, 10u, HighlightingType::StringLiteral)); +} + +TEST_F(HighlightingInformations, Utf8StringLiteral) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(2, 33)); + + ASSERT_THAT(infos[4], IsHighlightingInformation(2u, 24u, 12u, HighlightingType::StringLiteral)); +} + +TEST_F(HighlightingInformations, RawStringLiteral) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(3, 34)); + + ASSERT_THAT(infos[4], IsHighlightingInformation(3u, 24u, 13u, HighlightingType::StringLiteral)); +} + +TEST_F(HighlightingInformations, CharacterLiteral) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(4, 28)); + + ASSERT_THAT(infos[3], IsHighlightingInformation(4u, 24u, 3u, HighlightingType::StringLiteral)); +} + +TEST_F(HighlightingInformations, IntegerLiteral) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(23, 26)); + + ASSERT_THAT(infos[3], IsHighlightingInformation(23u, 24u, 1u, HighlightingType::NumberLiteral)); +} + +TEST_F(HighlightingInformations, FloatLiteral) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(24, 29)); + + ASSERT_THAT(infos[3], IsHighlightingInformation(24u, 24u, 4u, HighlightingType::NumberLiteral)); +} + +TEST_F(HighlightingInformations, FunctionDefinition) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(45, 20)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(45u, 5u, 8u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, MemberFunctionDefinition) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(52, 29)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(52u, 10u, 14u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, FunctionDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(55, 32)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(55u, 5u, 19u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, MemberFunctionDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(59, 27)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(59u, 10u, 14u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, MemberFunctionReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(104, 35)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(104u, 9u, 23u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, FunctionCall) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(64, 16)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(64u, 5u, 8u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, TypeConversionFunction) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(68, 20)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(68u, 14u, 3u, HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, InbuiltTypeConversionFunction) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(69, 20)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(69u, 14u, 3u, HighlightingType::Keyword)); +} + +TEST_F(HighlightingInformations, TypeReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(74, 13)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(74u, 5u, 3u, HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, LocalVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(79, 13)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(79u, 9u, 3u, HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, LocalVariableDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(79, 13)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(79u, 9u, 3u, HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, LocalVariableReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(81, 26)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(81u, 5u, 3u, HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, LocalVariableFunctionArgumentDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(84, 45)); + + ASSERT_THAT(infos[5], IsHighlightingInformation(84u, 41u, 3u, HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, LocalVariableFunctionArgumentReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(86, 26)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(86u, 5u, 3u, HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, ClassVariableDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(90, 21)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(90u, 9u, 11u, HighlightingType::Field)); +} + +TEST_F(HighlightingInformations, ClassVariableReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(94, 23)); + + ASSERT_THAT(infos[0], IsHighlightingInformation(94u, 9u, 11u, HighlightingType::Field)); +} + +TEST_F(HighlightingInformations, StaticMethodDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(110, 25)); + + ASSERT_THAT(infos[1], IsHighlightingInformation(110u, 10u, 12u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, StaticMethodReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(114, 30)); + + ASSERT_THAT(infos[2], IsHighlightingInformation(114u, 15u, 12u, HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, Enumeration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(118, 17)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Enumeration)); +} + +TEST_F(HighlightingInformations, Enumerator) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(120, 15)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Enumeration)); +} + +TEST_F(HighlightingInformations, EnumerationReferenceDeclarationType) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(125, 28)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Enumeration)); +} + +TEST_F(HighlightingInformations, EnumerationReferenceDeclarationVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(125, 28)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, EnumerationReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(127, 30)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, EnumeratorReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(127, 30)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Enumeration)); +} + +TEST_F(HighlightingInformations, ClassForwardDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(130, 12)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, ConstructorDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(134, 13)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, DestructorDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(135, 15)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, ClassForwardDeclarationReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(138, 23)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, ClassTypeReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(140, 32)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, ConstructorReferenceVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(140, 32)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, UnionDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(145, 12)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, UnionDeclarationReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(150, 33)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, GlobalVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(150, 33)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::GlobalVariable)); +} + +TEST_F(HighlightingInformations, StructDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(50, 11)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, NameSpace) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(160, 22)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, NameSpaceAlias) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(164, 38)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, NameSpaceReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(166, 35)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, VirtualFunction) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(170, 35)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::VirtualFunction)); +} + +TEST_F(HighlightingInformations, DISABLED_NonVirtualFunctionCall) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(177, 46)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, DISABLED_NonVirtualFunctionCallPointer) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(180, 54)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, VirtualFunctionCallPointer) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(192, 51)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::VirtualFunction)); +} + +TEST_F(HighlightingInformations, FinalVirtualFunctionCallPointer) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(202, 61)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, NonFinalVirtualFunctionCallPointer) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(207, 61)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::VirtualFunction)); +} + +TEST_F(HighlightingInformations, PlusOperator) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(224, 49)); + + ASSERT_THAT(infos[6], HasType(HighlightingType::Operator)); +} + +TEST_F(HighlightingInformations, PlusAssignOperator) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(226, 24)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Operator)); +} + +TEST_F(HighlightingInformations, Comment) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(229, 14)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Comment)); +} + +TEST_F(HighlightingInformations, PreprocessingDirective) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(231, 37)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Preprocessor)); +} + +TEST_F(HighlightingInformations, PreprocessorMacroDefinition) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(231, 37)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::PreprocessorDefinition)); +} + +TEST_F(HighlightingInformations, PreprocessorFunctionMacroDefinition) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(232, 47)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::PreprocessorDefinition)); +} + +TEST_F(HighlightingInformations, PreprocessorMacroExpansion) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(236, 27)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::PreprocessorExpansion)); +} + +TEST_F(HighlightingInformations, PreprocessorMacroExpansionArgument) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(236, 27)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::NumberLiteral)); +} + +TEST_F(HighlightingInformations, PreprocessorInclusionDirective) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(239, 18)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::StringLiteral)); +} + +TEST_F(HighlightingInformations, GotoLabelStatement) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(242, 12)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Label)); +} + +TEST_F(HighlightingInformations, GotoLabelStatementReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(244, 21)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Label)); +} + +TEST_F(HighlightingInformations, TemplateReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(254, 25)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, TemplateTypeParameter) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135)); + + ASSERT_THAT(infos[3], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplateDefaultParameter) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135)); + + ASSERT_THAT(infos[5], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, NonTypeTemplateParameter) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135)); + + ASSERT_THAT(infos[8], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, NonTypeTemplateParameterDefaultArgument) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135)); + + ASSERT_THAT(infos[10], HasType(HighlightingType::NumberLiteral)); +} + +TEST_F(HighlightingInformations, TemplateTemplateParameter) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135)); + + ASSERT_THAT(infos[17], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplateTemplateParameterDefaultArgument) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135)); + + ASSERT_THAT(infos[19], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplateFunctionDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(266, 63)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, TemplateTypeParameterReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(268, 58)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplateTypeParameterDeclarationReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(268, 58)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, NonTypeTemplateParameterReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(269, 71)); + + ASSERT_THAT(infos[3], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, NonTypeTemplateParameterReferenceReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(269, 71)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, TemplateTemplateParameterReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(270, 89)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplateTemplateContainerParameterReference) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(270, 89)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplateTemplateParameterReferenceVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(270, 89)); + + ASSERT_THAT(infos[4], HasType(HighlightingType::LocalVariable)); +} + +TEST_F(HighlightingInformations, ClassFinalVirtualFunctionCallPointer) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(212, 61)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, ClassFinalVirtualFunctionCall) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(277, 23)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, HasFunctionArguments) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(286, 29)); + + ASSERT_TRUE(infos[1].hasFunctionArguments()); +} + +TEST_F(HighlightingInformations, NoOutputFunctionArguments) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(285, 13)); + + auto outputFunctionArguments = infos[1].outputFunctionArguments(); + + ASSERT_THAT(outputFunctionArguments, IsEmpty()); +} + +TEST_F(HighlightingInformations, DISABLED_OneOutputFunctionArguments) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(285, 13)); + + auto outputFunctionArguments = infos[1].outputFunctionArguments(); + + ASSERT_THAT(outputFunctionArguments, SizeIs(1)); +} + +TEST_F(HighlightingInformations, PreprocessorInclusionDirectiveWithAngleBrackets ) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(289, 38)); + + ASSERT_THAT(infos[3], HasType(HighlightingType::StringLiteral)); +} + +TEST_F(HighlightingInformations, ArgumentInMacroExpansionIsKeyword) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(302, 36)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Keyword)); +} + +TEST_F(HighlightingInformations, DISABLED_FirstArgumentInMacroExpansionIsLocalVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(302, 36)); + + ASSERT_THAT(infos[3], HasType(HighlightingType::Invalid)); +} + +TEST_F(HighlightingInformations, DISABLED_SecondArgumentInMacroExpansionIsLocalVariable) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(302, 36)); + + ASSERT_THAT(infos[5], HasType(HighlightingType::Invalid)); +} + +TEST_F(HighlightingInformations, DISABLED_SecondArgumentInMacroExpansionIsField) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(310, 40)); + + ASSERT_THAT(infos[5], HasType(HighlightingType::Invalid)); +} + + +TEST_F(HighlightingInformations, DISABLED_EnumerationType) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(316, 30)); + + ASSERT_THAT(infos[3], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TypeInStaticCast) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(328, 64)); + + ASSERT_THAT(infos[4], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, StaticCastIsKeyword) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(328, 64)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Keyword)); +} + +TEST_F(HighlightingInformations, StaticCastPunctationIsInvalid) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(328, 64)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Invalid)); + ASSERT_THAT(infos[3], HasType(HighlightingType::Invalid)); + ASSERT_THAT(infos[5], HasType(HighlightingType::Invalid)); +} + +TEST_F(HighlightingInformations, TypeInReinterpretCast) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(329, 69)); + + ASSERT_THAT(infos[4], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, IntegerAliasDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(333, 41)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, IntegerAlias) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(341, 31)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, SecondIntegerAlias) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(342, 43)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, IntegerTypedef) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(343, 35)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, FunctionAlias) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(344, 16)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, FriendTypeDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(350, 28)); + + ASSERT_THAT(infos[2], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, FriendArgumentTypeDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(351, 65)); + + ASSERT_THAT(infos[6], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, DISABLED_FriendArgumentDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(351, 65)); + + ASSERT_THAT(infos[8], HasType(HighlightingType::Invalid)); +} + +TEST_F(HighlightingInformations, FieldInitialization) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(358, 18)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Field)); +} + +TEST_F(HighlightingInformations, TemplateFunctionCall) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(372, 29)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Function)); +} + +TEST_F(HighlightingInformations, TemplatedType) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(377, 21)); + + ASSERT_THAT(infos[1], HasType(HighlightingType::Type)); +} + +TEST_F(HighlightingInformations, TemplatedTypeDeclaration) +{ + const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(384, 49)); + + ASSERT_THAT(infos[0], HasType(HighlightingType::Type)); +} + +Data *HighlightingInformations::d; + +void HighlightingInformations::SetUpTestCase() +{ + d = new Data; +} + +void HighlightingInformations::TearDownTestCase() +{ + delete d; + d = nullptr; +} + +ClangBackEnd::SourceRange HighlightingInformations::sourceRange(uint line, uint columnEnd) const +{ + return translationUnit.sourceRange(line, 1, line, columnEnd); +} + +} diff --git a/tests/unit/unittest/skippedsourcerangestest.cpp b/tests/unit/unittest/skippedsourcerangestest.cpp new file mode 100644 index 0000000000..b37b872690 --- /dev/null +++ b/tests/unit/unittest/skippedsourcerangestest.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include <cursor.h> +#include <clangstring.h> +#include <projectpart.h> +#include <projects.h> +#include <skippedsourceranges.h> +#include <sourcelocation.h> +#include <sourcerange.h> +#include <translationunit.h> +#include <translationunits.h> +#include <unsavedfiles.h> + +#include <sourcerangecontainer.h> + +#include <QVector> + +#include <gmock/gmock.h> +#include <gmock/gmock-matchers.h> +#include <gtest/gtest.h> +#include "gtest-qt-printing.h" + +using ClangBackEnd::Cursor; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::UnsavedFiles; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::TranslationUnits; +using ClangBackEnd::ClangString; +using ClangBackEnd::SourceRange; +using ClangBackEnd::SkippedSourceRanges; + +using testing::IsNull; +using testing::NotNull; +using testing::Gt; +using testing::Contains; +using testing::EndsWith; +using testing::AllOf; +using testing::Not; +using testing::IsEmpty; +using testing::SizeIs; +using testing::PrintToString; + +namespace { + +MATCHER_P4(IsSourceLocation, filePath, line, column, offset, + std::string(negation ? "isn't" : "is") + + " source location with file path "+ PrintToString(filePath) + + ", line " + PrintToString(line) + + ", column " + PrintToString(column) + + " and offset " + PrintToString(offset) + ) +{ + if (!arg.filePath().endsWith(filePath) + || arg.line() != line + || arg.column() != column + || arg.offset() != offset) { + return false; + } + + return true; +} + +struct Data { + ClangBackEnd::ProjectParts projects; + ClangBackEnd::UnsavedFiles unsavedFiles; + ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles}; + Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/skippedsourceranges.cpp"); + TranslationUnit translationUnit{filePath, + ProjectPart(Utf8StringLiteral("projectPartId"), + {Utf8StringLiteral("-std=c++11"),Utf8StringLiteral("-DBLAH")}), + {}, + translationUnits}; +}; + +class SkippedSourceRanges : public ::testing::Test +{ +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + +protected: + static Data *d; + const TranslationUnit &translationUnit = d->translationUnit; + const Utf8String &filePath = d->filePath; + const ::SkippedSourceRanges skippedSourceRanges{d->translationUnit.skippedSourceRanges()}; +}; + +Data *SkippedSourceRanges::d; + +TEST_F(SkippedSourceRanges, RangeWithZero) +{ + auto ranges = skippedSourceRanges.sourceRanges(); + + ASSERT_THAT(ranges, SizeIs(2)); +} + +TEST_F(SkippedSourceRanges, RangeOne) +{ + auto ranges = skippedSourceRanges.sourceRanges(); + + ASSERT_THAT(ranges[0].start(), IsSourceLocation(filePath, 1, 2, 1)); + ASSERT_THAT(ranges[0].end(), IsSourceLocation(filePath, 5, 7, 24)); +} + +TEST_F(SkippedSourceRanges, RangeTwo) +{ + auto ranges = skippedSourceRanges.sourceRanges(); + + ASSERT_THAT(ranges[1].start(), IsSourceLocation(filePath, 7, 2, 27)); + ASSERT_THAT(ranges[1].end(), IsSourceLocation(filePath, 12, 7, 63)); +} + +TEST_F(SkippedSourceRanges, RangeContainerSize) +{ + auto ranges = skippedSourceRanges.toSourceRangeContainers(); + + ASSERT_THAT(ranges, SizeIs(2)); +} + +void SkippedSourceRanges::SetUpTestCase() +{ + d = new Data; +} + +void SkippedSourceRanges::TearDownTestCase() +{ + delete d; + d = nullptr; +} + +} diff --git a/tests/unit/unittest/sourcelocationtest.cpp b/tests/unit/unittest/sourcelocationtest.cpp index 9db922c282..9213d9359c 100644 --- a/tests/unit/unittest/sourcelocationtest.cpp +++ b/tests/unit/unittest/sourcelocationtest.cpp @@ -50,13 +50,13 @@ using ClangBackEnd::ProjectPart; using ClangBackEnd::SourceLocation; using ClangBackEnd::TranslationUnit; using ClangBackEnd::UnsavedFiles; + using testing::EndsWith; +using testing::Not; namespace { -class SourceLocation : public ::testing::Test -{ -protected: +struct Data { ProjectPart projectPart{Utf8StringLiteral("projectPartId")}; ClangBackEnd::ProjectParts projects; ClangBackEnd::UnsavedFiles unsavedFiles; @@ -68,7 +68,18 @@ protected: DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; Diagnostic diagnostic{diagnosticSet.front()}; ::SourceLocation sourceLocation{diagnostic.location()}; +}; +class SourceLocation : public ::testing::Test +{ +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + +protected: + static Data *d; + const ::SourceLocation &sourceLocation = d->sourceLocation; + const TranslationUnit &translationUnit = d->translationUnit; }; TEST_F(SourceLocation, FilePath) @@ -91,4 +102,27 @@ TEST_F(SourceLocation, Offset) ASSERT_THAT(sourceLocation.offset(), 18); } +TEST_F(SourceLocation, Create) +{ + ASSERT_THAT(translationUnit.sourceLocationAt(4, 1), sourceLocation); +} + +TEST_F(SourceLocation, NotEqual) +{ + ASSERT_THAT(translationUnit.sourceLocationAt(3, 1), Not(sourceLocation)); +} + +Data *SourceLocation::d; + +void SourceLocation::SetUpTestCase() +{ + d = new Data; +} + +void SourceLocation::TearDownTestCase() +{ + delete d; + d = nullptr; +} + } diff --git a/tests/unit/unittest/sourcerangetest.cpp b/tests/unit/unittest/sourcerangetest.cpp index 771bd49ccf..b517c42380 100644 --- a/tests/unit/unittest/sourcerangetest.cpp +++ b/tests/unit/unittest/sourcerangetest.cpp @@ -51,7 +51,9 @@ using ClangBackEnd::UnsavedFiles; using ClangBackEnd::Diagnostic; using ClangBackEnd::SourceRange; using ClangBackEnd::TranslationUnits; + using testing::PrintToString; +using testing::IsEmpty; namespace { @@ -73,9 +75,7 @@ MATCHER_P4(IsSourceLocation, filePath, line, column, offset, return true; } -class SourceRange : public ::testing::Test -{ -protected: +struct Data { ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}}; ClangBackEnd::ProjectParts projects; ClangBackEnd::UnsavedFiles unsavedFiles; @@ -90,6 +90,20 @@ protected: ::SourceRange sourceRange{diagnostic.ranges().front()}; }; +class SourceRange : public ::testing::Test +{ +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + +protected: + static Data *d; + const ::SourceRange &sourceRange = d->sourceRange; + const Diagnostic &diagnostic = d->diagnostic; + const Diagnostic &diagnosticWithFilteredOutInvalidRange = d->diagnosticWithFilteredOutInvalidRange; + const TranslationUnit &translationUnit = d->translationUnit; +}; + TEST_F(SourceRange, IsNull) { ::SourceRange sourceRange; @@ -125,9 +139,34 @@ TEST_F(SourceRange, End) 44u)); } +TEST_F(SourceRange, Create) +{ + ASSERT_THAT(sourceRange, ::SourceRange(sourceRange.start(), sourceRange.end())); +} + +TEST_F(SourceRange, SourceRangeFromTranslationUnit) +{ + auto sourceRangeFromTranslationUnit = translationUnit.sourceRange(8u, 5u, 8u, 6u); + + ASSERT_THAT(sourceRangeFromTranslationUnit, sourceRange); +} + TEST_F(SourceRange, InvalidRangeIsFilteredOut) { - ASSERT_TRUE(diagnosticWithFilteredOutInvalidRange.ranges().empty()); + ASSERT_THAT(diagnosticWithFilteredOutInvalidRange.ranges(), IsEmpty()); +} + +Data *SourceRange::d; + +void SourceRange::SetUpTestCase() +{ + d = new Data; +} + +void SourceRange::TearDownTestCase() +{ + delete d; + d = nullptr; } } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 193f1caa68..6fe2d25f2e 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -53,7 +53,10 @@ SOURCES += \ translationunittest.cpp \ unsavedfilestest.cpp \ utf8test.cpp \ - senddocumenttrackertest.cpp + senddocumenttrackertest.cpp \ + cursortest.cpp \ + highlightinginformationstest.cpp \ + skippedsourcerangestest.cpp HEADERS += \ gtest-qt-printing.h \ |